7ddac7b3d3a4c80bb670c54b88d3f6cc5b31f07d
[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 constInt8(int8_t value) { return constInt(int8, value, SignExtend); }
109     LValue constInt32(int32_t value) { return constInt(int32, value, SignExtend); }
110     template<typename T>
111     LValue constIntPtr(T value) { return constInt(intPtr, bitwise_cast<intptr_t>(value), SignExtend); }
112     LValue constInt64(int64_t value) { return constInt(int64, value, SignExtend); }
113     LValue constDouble(double value) { return constReal(doubleType, value); }
114     
115     LValue phi(LType type) { return buildPhi(m_builder, type); }
116     LValue phi(LType type, ValueFromBlock value1)
117     {
118         return buildPhi(m_builder, type, value1);
119     }
120     LValue phi(LType type, ValueFromBlock value1, ValueFromBlock value2)
121     {
122         return buildPhi(m_builder, type, value1, value2);
123     }
124     template<typename VectorType>
125     LValue phi(LType type, const VectorType& vector)
126     {
127         LValue result = phi(type);
128         for (unsigned i = 0; i < vector.size(); ++i)
129             addIncoming(result, vector[i]);
130         return result;
131     }
132     
133     LValue add(LValue left, LValue right) { return buildAdd(m_builder, left, right); }
134     LValue sub(LValue left, LValue right) { return buildSub(m_builder, left, right); }
135     LValue mul(LValue left, LValue right) { return buildMul(m_builder, left, right); }
136     LValue neg(LValue value) { return buildNeg(m_builder, value); }
137
138     LValue doubleAdd(LValue left, LValue right) { return buildFAdd(m_builder, left, right); }
139     LValue doubleSub(LValue left, LValue right) { return buildFSub(m_builder, left, right); }
140     LValue doubleMul(LValue left, LValue right) { return buildFMul(m_builder, left, right); }
141     LValue doubleNeg(LValue value) { return buildFNeg(m_builder, value); }
142
143     LValue bitAnd(LValue left, LValue right) { return buildAnd(m_builder, left, right); }
144     LValue bitOr(LValue left, LValue right) { return buildOr(m_builder, left, right); }
145     LValue bitXor(LValue left, LValue right) { return buildXor(m_builder, left, right); }
146     LValue shl(LValue left, LValue right) { return buildShl(m_builder, left, right); }
147     LValue aShr(LValue left, LValue right) { return buildAShr(m_builder, left, right); }
148     LValue lShr(LValue left, LValue right) { return buildLShr(m_builder, left, right); }
149     LValue bitNot(LValue value) { return buildNot(m_builder, value); }
150     
151     LValue addWithOverflow32(LValue left, LValue right)
152     {
153         return call(addWithOverflow32Intrinsic(), left, right);
154     }
155     LValue subWithOverflow32(LValue left, LValue right)
156     {
157         return call(subWithOverflow32Intrinsic(), left, right);
158     }
159     LValue mulWithOverflow32(LValue left, LValue right)
160     {
161         return call(mulWithOverflow32Intrinsic(), left, right);
162     }
163     
164     LValue zeroExt(LValue value, LType type) { return buildZExt(m_builder, value, type); }
165     LValue intToFP(LValue value, LType type) { return buildSIToFP(m_builder, value, type); }
166     LValue intToDouble(LValue value) { return intToFP(value, doubleType); }
167     LValue unsignedToFP(LValue value, LType type) { return buildUIToFP(m_builder, value, type); }
168     LValue unsignedToDouble(LValue value) { return unsignedToFP(value, doubleType); }
169     LValue intCast(LValue value, LType type) { return buildIntCast(m_builder, value, type); }
170     LValue castToInt32(LValue value) { return intCast(value, int32); }
171     LValue intToPtr(LValue value, LType type) { return buildIntToPtr(m_builder, value, type); }
172     LValue bitCast(LValue value, LType type) { return buildBitCast(m_builder, value, type); }
173     
174     LValue get(LValue reference) { return buildLoad(m_builder, reference); }
175     LValue set(LValue value, LValue reference) { return buildStore(m_builder, value, reference); }
176     
177     LValue load(TypedPointer pointer, LType refType)
178     {
179         LValue result = get(intToPtr(pointer.value(), refType));
180         pointer.heap().decorateInstruction(result, *m_heaps);
181         return result;
182     }
183     void store(LValue value, TypedPointer pointer, LType refType)
184     {
185         LValue result = set(value, intToPtr(pointer.value(), refType));
186         pointer.heap().decorateInstruction(result, *m_heaps);
187     }
188     
189     LValue load8(TypedPointer pointer) { return load(pointer, ref8); }
190     LValue load32(TypedPointer pointer) { return load(pointer, ref32); }
191     LValue load64(TypedPointer pointer) { return load(pointer, ref64); }
192     LValue loadPtr(TypedPointer pointer) { return load(pointer, refPtr); }
193     LValue loadDouble(TypedPointer pointer) { return load(pointer, refDouble); }
194     void store32(LValue value, TypedPointer pointer) { store(value, pointer, ref32); }
195     void store64(LValue value, TypedPointer pointer) { store(value, pointer, ref64); }
196     void storePtr(LValue value, TypedPointer pointer) { store(value, pointer, refPtr); }
197     void storeDouble(LValue value, TypedPointer pointer) { store(value, pointer, refDouble); }
198
199     LValue addPtr(LValue value, ptrdiff_t immediate = 0)
200     {
201         if (!immediate)
202             return value;
203         return add(value, constIntPtr(immediate));
204     }
205     
206     // Construct an address by offsetting base by the requested amount and ascribing
207     // the requested abstract heap to it.
208     TypedPointer address(const AbstractHeap& heap, LValue base, ptrdiff_t offset = 0)
209     {
210         return TypedPointer(heap, addPtr(base, offset));
211     }
212     // Construct an address by offsetting base by the amount specified by the field,
213     // and optionally an additional amount (use this with care), and then creating
214     // a TypedPointer with the given field as the heap.
215     TypedPointer address(LValue base, const AbstractField& field, ptrdiff_t offset = 0)
216     {
217         return address(field, base, offset + field.offset());
218     }
219     
220     LValue baseIndex(LValue base, LValue index, Scale scale, ptrdiff_t offset = 0)
221     {
222         LValue accumulatedOffset;
223         
224         switch (scale) {
225         case ScaleOne:
226             accumulatedOffset = index;
227             break;
228         case ScaleTwo:
229             accumulatedOffset = shl(index, intPtrOne);
230             break;
231         case ScaleFour:
232             accumulatedOffset = shl(index, intPtrTwo);
233             break;
234         case ScaleEight:
235         case ScalePtr:
236             accumulatedOffset = shl(index, intPtrThree);
237             break;
238         }
239         
240         if (offset)
241             accumulatedOffset = add(accumulatedOffset, constIntPtr(offset));
242         
243         return add(base, accumulatedOffset);
244     }
245     TypedPointer baseIndex(const AbstractHeap& heap, LValue base, LValue index, Scale scale, ptrdiff_t offset = 0)
246     {
247         return TypedPointer(heap, baseIndex(base, index, scale, offset));
248     }
249     TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0)
250     {
251         return heap.baseIndex(*this, base, index, indexAsConstant, offset);
252     }
253     
254     TypedPointer absolute(void* address)
255     {
256         return TypedPointer(m_heaps->absolute[address], constIntPtr(address));
257     }
258     
259     LValue load8(LValue base, const AbstractField& field) { return load8(address(base, field)); }
260     LValue load32(LValue base, const AbstractField& field) { return load32(address(base, field)); }
261     LValue load64(LValue base, const AbstractField& field) { return load64(address(base, field)); }
262     LValue loadPtr(LValue base, const AbstractField& field) { return loadPtr(address(base, field)); }
263     void store32(LValue value, LValue base, const AbstractField& field) { store32(value, address(base, field)); }
264     void store64(LValue value, LValue base, const AbstractField& field) { store64(value, address(base, field)); }
265     void storePtr(LValue value, LValue base, const AbstractField& field) { storePtr(value, address(base, field)); }
266     
267     LValue equal(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntEQ, left, right); }
268     LValue notEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntNE, left, right); }
269     LValue above(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntUGT, left, right); }
270     LValue aboveOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntUGE, left, right); }
271     LValue below(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntULT, left, right); }
272     LValue belowOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntULE, left, right); }
273     LValue greaterThan(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSGT, left, right); }
274     LValue greaterThanOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSGE, left, right); }
275     LValue lessThan(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSLT, left, right); }
276     LValue lessThanOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSLE, left, right); }
277     
278     LValue doubleEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOEQ, left, right); }
279     LValue doubleNotEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUNE, left, right); }
280     LValue doubleLessThan(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOLT, left, right); }
281     LValue doubleLessThanOrEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOLE, left, right); }
282     LValue doubleGreaterThan(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOGT, left, right); }
283     LValue doubleGreaterThanOrEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOGE, left, right); }
284     LValue doubleEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUEQ, left, right); }
285     LValue doubleNotEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealONE, left, right); }
286     LValue doubleLessThanOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealULT, left, right); }
287     LValue doubleLessThanOrEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealULE, left, right); }
288     LValue doubleGreaterThanOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUGT, left, right); }
289     LValue doubleGreaterThanOrEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUGE, left, right); }
290     
291     LValue isZero8(LValue value) { return equal(value, int8Zero); }
292     LValue notZero8(LValue value) { return notEqual(value, int8Zero); }
293     LValue isZero64(LValue value) { return equal(value, int64Zero); }
294     LValue notZero64(LValue value) { return notEqual(value, int64Zero); }
295     
296     LValue testIsZero8(LValue value, LValue mask) { return isZero8(bitAnd(value, mask)); }
297     LValue testNonZero8(LValue value, LValue mask) { return notZero8(bitAnd(value, mask)); }
298     LValue testIsZero64(LValue value, LValue mask) { return isZero64(bitAnd(value, mask)); }
299     LValue testNonZero64(LValue value, LValue mask) { return notZero64(bitAnd(value, mask)); }
300     
301     LValue select(LValue value, LValue taken, LValue notTaken) { return buildSelect(m_builder, value, taken, notTaken); }
302     LValue extractValue(LValue aggVal, unsigned index) { return buildExtractValue(m_builder, aggVal, index); }
303     
304     template<typename VectorType>
305     LValue call(LValue function, const VectorType& vector) { return buildCall(m_builder, function, vector); }
306     LValue call(LValue function) { return buildCall(m_builder, function); }
307     LValue call(LValue function, LValue arg1) { return buildCall(m_builder, function, arg1); }
308     LValue call(LValue function, LValue arg1, LValue arg2) { return buildCall(m_builder, function, arg1, arg2); }
309     
310     LValue convertToTailCall(LValue call)
311     {
312         setTailCall(call, IsTailCall);
313         return call;
314     }
315     
316     void jump(LBasicBlock destination) { buildBr(m_builder, destination); }
317     void branch(LValue condition, LBasicBlock taken, LBasicBlock notTaken) { buildCondBr(m_builder, condition, taken, notTaken); }
318     void ret(LValue value) { buildRet(m_builder, value); }
319     
320     void unreachable() { buildUnreachable(m_builder); }
321     
322     ValueFromBlock anchor(LValue value)
323     {
324         return ValueFromBlock(value, m_block);
325     }
326     
327     LValue m_function;
328     AbstractHeapRepository* m_heaps;
329     LBuilder m_builder;
330     LBasicBlock m_block;
331     LBasicBlock m_nextBlock;
332 };
333
334 #define FTL_NEW_BLOCK(output, nameArguments) \
335     (LIKELY(!::JSC::DFG::verboseCompilationEnabled()) \
336     ? (output).newBlock() \
337     : (output).newBlock((toCString nameArguments).data()))
338
339 } } // namespace JSC::FTL
340
341 #endif // ENABLE(FTL_JIT)
342
343 #endif // FTLOutput_h
344