fourthTier: Landing the initial FTL logic in a single commit to avoid spurious
[WebKit-https.git] / Source / JavaScriptCore / ftl / FTLOutput.h
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef FTLOutput_h
27 #define FTLOutput_h
28
29 #include <wtf/Platform.h>
30
31 #if ENABLE(FTL_JIT)
32
33 #include "DFGCommon.h"
34 #include "FTLAbbreviations.h"
35 #include "FTLAbstractHeapRepository.h"
36 #include "FTLCommonValues.h"
37 #include "FTLIntrinsicRepository.h"
38 #include "FTLTypedPointer.h"
39 #include <wtf/StringPrintStream.h>
40
41 namespace JSC { namespace FTL {
42
43 // Idiomatic LLVM IR builder specifically designed for FTL. This uses our own lowering
44 // terminology, and has some of its own notions:
45 //
46 // We say that a "reference" is what LLVM considers to be a "pointer". That is, it has
47 // an element type and can be passed directly to memory access instructions. Note that
48 // broadly speaking the users of FTL::Output should only use references for alloca'd
49 // slots for mutable local variables.
50 //
51 // We say that a "pointer" is what LLVM considers to be a pointer-width integer.
52 //
53 // We say that a "typed pointer" is a pointer that carries TBAA meta-data (i.e. an
54 // AbstractHeap). These should usually not have further computation performed on them
55 // prior to access, though there are exceptions (like offsetting into the payload of
56 // a typed pointer to a JSValue).
57 //
58 // We say that "get" and "set" are what LLVM considers to be "load" and "store". Get
59 // and set take references.
60 //
61 // We say that "load" and "store" are operations that take a typed pointer. These
62 // operations translate the pointer into a reference (or, a pointer in LLVM-speak),
63 // emit get or set on the reference (or, load and store in LLVM-speak), and apply the
64 // TBAA meta-data to the get or set.
65
66 enum Scale { ScaleOne, ScaleTwo, ScaleFour, ScaleEight, ScalePtr };
67
68 class Output : public IntrinsicRepository {
69 public:
70     Output();
71     ~Output();
72     
73     void initialize(LModule module, LValue function, AbstractHeapRepository& heaps)
74     {
75         IntrinsicRepository::initialize(module);
76         m_function = function;
77         m_heaps = &heaps;
78     }
79     
80     LBasicBlock insertNewBlocksBefore(LBasicBlock nextBlock)
81     {
82         LBasicBlock lastNextBlock = m_nextBlock;
83         m_nextBlock = nextBlock;
84         return lastNextBlock;
85     }
86     
87     LBasicBlock appendTo(LBasicBlock block, LBasicBlock nextBlock)
88     {
89         appendTo(block);
90         return insertNewBlocksBefore(nextBlock);
91     }
92     
93     void appendTo(LBasicBlock block)
94     {
95         m_block = block;
96         
97         LLVMPositionBuilderAtEnd(m_builder, block);
98     }
99     LBasicBlock newBlock(const char* name = "")
100     {
101         if (!m_nextBlock)
102             return appendBasicBlock(m_function, name);
103         return insertBasicBlock(m_nextBlock, name);
104     }
105     
106     LValue param(unsigned index) { return getParam(m_function, index); }
107     LValue constBool(bool value) { return constInt(boolean, value, ZeroExtend); }
108     LValue constInt32(int32_t value) { return constInt(int32, value, SignExtend); }
109     template<typename T>
110     LValue constIntPtr(T value) { return constInt(intPtr, bitwise_cast<intptr_t>(value), SignExtend); }
111     LValue constInt64(int64_t value) { return constInt(int64, value, SignExtend); }
112     
113     LValue add(LValue left, LValue right) { return buildAdd(m_builder, left, right); }
114     LValue sub(LValue left, LValue right) { return buildSub(m_builder, left, right); }
115     LValue mul(LValue left, LValue right) { return buildMul(m_builder, left, right); }
116     LValue neg(LValue value) { return buildNeg(m_builder, value); }
117     LValue bitAnd(LValue left, LValue right) { return buildAnd(m_builder, left, right); }
118     LValue bitOr(LValue left, LValue right) { return buildOr(m_builder, left, right); }
119     LValue bitXor(LValue left, LValue right) { return buildXor(m_builder, left, right); }
120     LValue shl(LValue left, LValue right) { return buildShl(m_builder, left, right); }
121     LValue aShr(LValue left, LValue right) { return buildAShr(m_builder, left, right); }
122     LValue lShr(LValue left, LValue right) { return buildLShr(m_builder, left, right); }
123     
124     LValue addWithOverflow32(LValue left, LValue right)
125     {
126         return call(addWithOverflow32Intrinsic(), left, right);
127     }
128     LValue subWithOverflow32(LValue left, LValue right)
129     {
130         return call(subWithOverflow32Intrinsic(), left, right);
131     }
132     LValue mulWithOverflow32(LValue left, LValue right)
133     {
134         return call(mulWithOverflow32Intrinsic(), left, right);
135     }
136     
137     LValue zeroExt(LValue value, LType type) { return buildZExt(m_builder, value, type); }
138     LValue intCast(LValue value, LType type) { return buildIntCast(m_builder, value, type); }
139     LValue castToInt32(LValue value) { return intCast(value, int32); }
140     LValue intToPtr(LValue value, LType type) { return buildIntToPtr(m_builder, value, type); }
141     
142     LValue get(LValue reference) { return buildLoad(m_builder, reference); }
143     LValue set(LValue value, LValue reference) { return buildStore(m_builder, value, reference); }
144     
145     LValue load(TypedPointer pointer, LType refType)
146     {
147         LValue result = get(intToPtr(pointer.value(), refType));
148         pointer.heap().decorateInstruction(result, *m_heaps);
149         return result;
150     }
151     void store(LValue value, TypedPointer pointer, LType refType)
152     {
153         LValue result = set(value, intToPtr(pointer.value(), refType));
154         pointer.heap().decorateInstruction(result, *m_heaps);
155     }
156     
157     LValue load32(TypedPointer pointer) { return load(pointer, ref32); }
158     LValue load64(TypedPointer pointer) { return load(pointer, ref64); }
159     LValue loadPtr(TypedPointer pointer) { return load(pointer, refPtr); }
160     void store32(LValue value, TypedPointer pointer) { store(value, pointer, ref32); }
161     void store64(LValue value, TypedPointer pointer) { store(value, pointer, ref64); }
162     void storePtr(LValue value, TypedPointer pointer) { store(value, pointer, refPtr); }
163
164     LValue addPtr(LValue value, ptrdiff_t immediate = 0)
165     {
166         if (!immediate)
167             return value;
168         return add(value, constIntPtr(immediate));
169     }
170     
171     // Construct an address by offsetting base by the requested amount and ascribing
172     // the requested abstract heap to it.
173     TypedPointer address(const AbstractHeap& heap, LValue base, ptrdiff_t offset = 0)
174     {
175         return TypedPointer(heap, addPtr(base, offset));
176     }
177     // Construct an address by offsetting base by the amount specified by the field,
178     // and optionally an additional amount (use this with care), and then creating
179     // a TypedPointer with the given field as the heap.
180     TypedPointer address(LValue base, const AbstractField& field, ptrdiff_t offset = 0)
181     {
182         return address(field, base, offset + field.offset());
183     }
184     
185     LValue baseIndex(LValue base, LValue index, Scale scale, ptrdiff_t offset = 0)
186     {
187         LValue accumulatedOffset;
188         
189         switch (scale) {
190         case ScaleOne:
191             accumulatedOffset = index;
192             break;
193         case ScaleTwo:
194             accumulatedOffset = shl(index, intPtrOne);
195             break;
196         case ScaleFour:
197             accumulatedOffset = shl(index, intPtrTwo);
198             break;
199         case ScaleEight:
200         case ScalePtr:
201             accumulatedOffset = shl(index, intPtrThree);
202             break;
203         }
204         
205         if (offset)
206             accumulatedOffset = add(accumulatedOffset, constIntPtr(offset));
207         
208         return add(base, accumulatedOffset);
209     }
210     TypedPointer baseIndex(const AbstractHeap& heap, LValue base, LValue index, Scale scale, ptrdiff_t offset = 0)
211     {
212         return TypedPointer(heap, baseIndex(base, index, scale, offset));
213     }
214     TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0)
215     {
216         return heap.baseIndex(*this, base, index, indexAsConstant, offset);
217     }
218     
219     TypedPointer absolute(void* address)
220     {
221         return TypedPointer(m_heaps->absolute[address], constIntPtr(address));
222     }
223     
224     LValue load32(LValue base, const AbstractField& field) { return load32(address(base, field)); }
225     LValue load64(LValue base, const AbstractField& field) { return load64(address(base, field)); }
226     LValue loadPtr(LValue base, const AbstractField& field) { return loadPtr(address(base, field)); }
227     void store32(LValue value, LValue base, const AbstractField& field) { store32(value, address(base, field)); }
228     void store64(LValue value, LValue base, const AbstractField& field) { store64(value, address(base, field)); }
229     void storePtr(LValue value, LValue base, const AbstractField& field) { storePtr(value, address(base, field)); }
230     
231     LValue equal(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntEQ, left, right); }
232     LValue notEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntNE, left, right); }
233     LValue above(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntUGT, left, right); }
234     LValue aboveOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntUGE, left, right); }
235     LValue below(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntULT, left, right); }
236     LValue belowOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntULE, left, right); }
237     LValue greaterThan(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSGT, left, right); }
238     LValue greaterThanOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSGE, left, right); }
239     LValue lessThan(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSLT, left, right); }
240     LValue lessThanOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSLE, left, right); }
241     
242     LValue isZero64(LValue value) { return equal(value, int64Zero); }
243     LValue notZero64(LValue value) { return notEqual(value, int64Zero); }
244     
245     LValue testNonZero64(LValue value, LValue mask) { return notZero64(bitAnd(value, mask)); }
246     
247     LValue select(LValue value, LValue taken, LValue notTaken) { return buildSelect(m_builder, value, taken, notTaken); }
248     LValue extractValue(LValue aggVal, unsigned index) { return buildExtractValue(m_builder, aggVal, index); }
249     
250     template<typename VectorType>
251     LValue call(LValue function, const VectorType& vector) { return buildCall(m_builder, function, vector); }
252     LValue call(LValue function) { return buildCall(m_builder, function); }
253     LValue call(LValue function, LValue arg1) { return buildCall(m_builder, function, arg1); }
254     LValue call(LValue function, LValue arg1, LValue arg2) { return buildCall(m_builder, function, arg1, arg2); }
255     
256     LValue convertToTailCall(LValue call)
257     {
258         setTailCall(call, IsTailCall);
259         return call;
260     }
261     
262     void jump(LBasicBlock destination) { buildBr(m_builder, destination); }
263     void branch(LValue condition, LBasicBlock taken, LBasicBlock notTaken) { buildCondBr(m_builder, condition, taken, notTaken); }
264     void ret(LValue value) { buildRet(m_builder, value); }
265     
266     void unreachable() { buildUnreachable(m_builder); }
267     
268     LValue m_function;
269     AbstractHeapRepository* m_heaps;
270     LBuilder m_builder;
271     LBasicBlock m_block;
272     LBasicBlock m_nextBlock;
273 };
274
275 #define FTL_NEW_BLOCK(output, nameArguments) \
276     (LIKELY(!::JSC::DFG::verboseCompilationEnabled()) \
277     ? (output).newBlock() \
278     : (output).newBlock((toCString nameArguments).data()))
279
280 } } // namespace JSC::FTL
281
282 #endif // ENABLE(FTL_JIT)
283
284 #endif // FTLOutput_h
285