]> git.saurik.com Git - apple/javascriptcore.git/blob - ftl/FTLOutput.h
JavaScriptCore-7600.1.4.15.12.tar.gz
[apple/javascriptcore.git] / ftl / FTLOutput.h
1 /*
2 * Copyright (C) 2013, 2014 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 #if ENABLE(FTL_JIT)
30
31 #include "DFGCommon.h"
32 #include "FTLAbbreviations.h"
33 #include "FTLAbstractHeapRepository.h"
34 #include "FTLCommonValues.h"
35 #include "FTLIntrinsicRepository.h"
36 #include "FTLState.h"
37 #include "FTLSwitchCase.h"
38 #include "FTLTypedPointer.h"
39 #include "FTLWeight.h"
40 #include "FTLWeightedTarget.h"
41 #include <wtf/StringPrintStream.h>
42
43 namespace JSC { namespace FTL {
44
45 // Idiomatic LLVM IR builder specifically designed for FTL. This uses our own lowering
46 // terminology, and has some of its own notions:
47 //
48 // We say that a "reference" is what LLVM considers to be a "pointer". That is, it has
49 // an element type and can be passed directly to memory access instructions. Note that
50 // broadly speaking the users of FTL::Output should only use references for alloca'd
51 // slots for mutable local variables.
52 //
53 // We say that a "pointer" is what LLVM considers to be a pointer-width integer.
54 //
55 // We say that a "typed pointer" is a pointer that carries TBAA meta-data (i.e. an
56 // AbstractHeap). These should usually not have further computation performed on them
57 // prior to access, though there are exceptions (like offsetting into the payload of
58 // a typed pointer to a JSValue).
59 //
60 // We say that "get" and "set" are what LLVM considers to be "load" and "store". Get
61 // and set take references.
62 //
63 // We say that "load" and "store" are operations that take a typed pointer. These
64 // operations translate the pointer into a reference (or, a pointer in LLVM-speak),
65 // emit get or set on the reference (or, load and store in LLVM-speak), and apply the
66 // TBAA meta-data to the get or set.
67
68 enum Scale { ScaleOne, ScaleTwo, ScaleFour, ScaleEight, ScalePtr };
69
70 class Output : public IntrinsicRepository {
71 public:
72 Output(LContext);
73 ~Output();
74
75 void initialize(LModule, LValue, AbstractHeapRepository&);
76
77 LBasicBlock insertNewBlocksBefore(LBasicBlock nextBlock)
78 {
79 LBasicBlock lastNextBlock = m_nextBlock;
80 m_nextBlock = nextBlock;
81 return lastNextBlock;
82 }
83
84 LBasicBlock appendTo(LBasicBlock, LBasicBlock nextBlock);
85
86 void appendTo(LBasicBlock);
87
88 LBasicBlock newBlock(const char* name = "");
89
90 LValue param(unsigned index) { return getParam(m_function, index); }
91 LValue constBool(bool value) { return constInt(boolean, value); }
92 LValue constInt8(int8_t value) { return constInt(int8, value); }
93 LValue constInt32(int32_t value) { return constInt(int32, value); }
94 template<typename T>
95 LValue constIntPtr(T* value) { return constInt(intPtr, bitwise_cast<intptr_t>(value)); }
96 template<typename T>
97 LValue constIntPtr(T value) { return constInt(intPtr, static_cast<intptr_t>(value)); }
98 LValue constInt64(int64_t value) { return constInt(int64, value); }
99 LValue constDouble(double value) { return constReal(doubleType, value); }
100
101 LValue phi(LType type) { return buildPhi(m_builder, type); }
102 template<typename... Params>
103 LValue phi(LType type, ValueFromBlock value, Params... theRest)
104 {
105 LValue result = phi(type, theRest...);
106 addIncoming(result, value);
107 return result;
108 }
109 template<typename VectorType>
110 LValue phi(LType type, const VectorType& vector)
111 {
112 LValue result = phi(type);
113 for (unsigned i = 0; i < vector.size(); ++i)
114 addIncoming(result, vector[i]);
115 return result;
116 }
117
118 LValue add(LValue left, LValue right) { return buildAdd(m_builder, left, right); }
119 LValue sub(LValue left, LValue right) { return buildSub(m_builder, left, right); }
120 LValue mul(LValue left, LValue right) { return buildMul(m_builder, left, right); }
121 LValue div(LValue left, LValue right) { return buildDiv(m_builder, left, right); }
122 LValue rem(LValue left, LValue right) { return buildRem(m_builder, left, right); }
123 LValue neg(LValue value) { return buildNeg(m_builder, value); }
124
125 LValue doubleAdd(LValue left, LValue right) { return buildFAdd(m_builder, left, right); }
126 LValue doubleSub(LValue left, LValue right) { return buildFSub(m_builder, left, right); }
127 LValue doubleMul(LValue left, LValue right) { return buildFMul(m_builder, left, right); }
128 LValue doubleDiv(LValue left, LValue right) { return buildFDiv(m_builder, left, right); }
129 LValue doubleRem(LValue left, LValue right) { return buildFRem(m_builder, left, right); }
130 LValue doubleNeg(LValue value) { return buildFNeg(m_builder, value); }
131
132 LValue bitAnd(LValue left, LValue right) { return buildAnd(m_builder, left, right); }
133 LValue bitOr(LValue left, LValue right) { return buildOr(m_builder, left, right); }
134 LValue bitXor(LValue left, LValue right) { return buildXor(m_builder, left, right); }
135 LValue shl(LValue left, LValue right) { return buildShl(m_builder, left, right); }
136 LValue aShr(LValue left, LValue right) { return buildAShr(m_builder, left, right); }
137 LValue lShr(LValue left, LValue right) { return buildLShr(m_builder, left, right); }
138 LValue bitNot(LValue value) { return buildNot(m_builder, value); }
139
140 LValue insertElement(LValue vector, LValue element, LValue index) { return buildInsertElement(m_builder, vector, element, index); }
141
142 LValue addWithOverflow32(LValue left, LValue right)
143 {
144 return call(addWithOverflow32Intrinsic(), left, right);
145 }
146 LValue subWithOverflow32(LValue left, LValue right)
147 {
148 return call(subWithOverflow32Intrinsic(), left, right);
149 }
150 LValue mulWithOverflow32(LValue left, LValue right)
151 {
152 return call(mulWithOverflow32Intrinsic(), left, right);
153 }
154 LValue addWithOverflow64(LValue left, LValue right)
155 {
156 return call(addWithOverflow64Intrinsic(), left, right);
157 }
158 LValue subWithOverflow64(LValue left, LValue right)
159 {
160 return call(subWithOverflow64Intrinsic(), left, right);
161 }
162 LValue mulWithOverflow64(LValue left, LValue right)
163 {
164 return call(mulWithOverflow64Intrinsic(), left, right);
165 }
166 LValue doubleAbs(LValue value)
167 {
168 return call(doubleAbsIntrinsic(), value);
169 }
170
171 LValue doubleSin(LValue value)
172 {
173 return call(doubleSinIntrinsic(), value);
174 }
175 LValue doubleCos(LValue value)
176 {
177 return call(doubleCosIntrinsic(), value);
178 }
179
180 LValue doubleSqrt(LValue value)
181 {
182 return call(doubleSqrtIntrinsic(), value);
183 }
184
185 static bool hasSensibleDoubleToInt() { return isX86(); }
186 LValue sensibleDoubleToInt(LValue);
187
188 LValue signExt(LValue value, LType type) { return buildSExt(m_builder, value, type); }
189 LValue zeroExt(LValue value, LType type) { return buildZExt(m_builder, value, type); }
190 LValue fpToInt(LValue value, LType type) { return buildFPToSI(m_builder, value, type); }
191 LValue fpToUInt(LValue value, LType type) { return buildFPToUI(m_builder, value, type); }
192 LValue fpToInt32(LValue value) { return fpToInt(value, int32); }
193 LValue fpToUInt32(LValue value) { return fpToUInt(value, int32); }
194 LValue intToFP(LValue value, LType type) { return buildSIToFP(m_builder, value, type); }
195 LValue intToDouble(LValue value) { return intToFP(value, doubleType); }
196 LValue unsignedToFP(LValue value, LType type) { return buildUIToFP(m_builder, value, type); }
197 LValue unsignedToDouble(LValue value) { return unsignedToFP(value, doubleType); }
198 LValue intCast(LValue value, LType type) { return buildIntCast(m_builder, value, type); }
199 LValue castToInt32(LValue value) { return intCast(value, int32); }
200 LValue fpCast(LValue value, LType type) { return buildFPCast(m_builder, value, type); }
201 LValue intToPtr(LValue value, LType type) { return buildIntToPtr(m_builder, value, type); }
202 LValue ptrToInt(LValue value, LType type) { return buildPtrToInt(m_builder, value, type); }
203 LValue bitCast(LValue value, LType type) { return buildBitCast(m_builder, value, type); }
204
205 LValue alloca(LType type) { return buildAlloca(m_builder, type); }
206
207 // Access the value of an alloca. Also used as a low-level implementation primitive for
208 // load(). Never use this to load from "pointers" in the FTL sense, since FTL pointers
209 // are actually integers. This requires an LLVM pointer. Broadly speaking, you don't
210 // have any LLVM pointers even if you really think you do. A TypedPointer is not an
211 // LLVM pointer. See comment block at top of this file to understand the distinction
212 // between LLVM pointers, FTL pointers, and FTL references.
213 LValue get(LValue reference) { return buildLoad(m_builder, reference); }
214 // Similar to get() but for storing to the value in an alloca.
215 LValue set(LValue value, LValue reference) { return buildStore(m_builder, value, reference); }
216
217 LValue load(TypedPointer, LType refType);
218 void store(LValue, TypedPointer, LType refType);
219
220 LValue load8(TypedPointer pointer) { return load(pointer, ref8); }
221 LValue load16(TypedPointer pointer) { return load(pointer, ref16); }
222 LValue load32(TypedPointer pointer) { return load(pointer, ref32); }
223 LValue load64(TypedPointer pointer) { return load(pointer, ref64); }
224 LValue loadPtr(TypedPointer pointer) { return load(pointer, refPtr); }
225 LValue loadFloat(TypedPointer pointer) { return load(pointer, refFloat); }
226 LValue loadDouble(TypedPointer pointer) { return load(pointer, refDouble); }
227 void store8(LValue value, TypedPointer pointer) { store(value, pointer, ref8); }
228 void store16(LValue value, TypedPointer pointer) { store(value, pointer, ref16); }
229 void store32(LValue value, TypedPointer pointer) { store(value, pointer, ref32); }
230 void store64(LValue value, TypedPointer pointer) { store(value, pointer, ref64); }
231 void storePtr(LValue value, TypedPointer pointer) { store(value, pointer, refPtr); }
232 void storeFloat(LValue value, TypedPointer pointer) { store(value, pointer, refFloat); }
233 void storeDouble(LValue value, TypedPointer pointer) { store(value, pointer, refDouble); }
234
235 LValue addPtr(LValue value, ptrdiff_t immediate = 0)
236 {
237 if (!immediate)
238 return value;
239 return add(value, constIntPtr(immediate));
240 }
241
242 // Construct an address by offsetting base by the requested amount and ascribing
243 // the requested abstract heap to it.
244 TypedPointer address(const AbstractHeap& heap, LValue base, ptrdiff_t offset = 0)
245 {
246 return TypedPointer(heap, addPtr(base, offset));
247 }
248 // Construct an address by offsetting base by the amount specified by the field,
249 // and optionally an additional amount (use this with care), and then creating
250 // a TypedPointer with the given field as the heap.
251 TypedPointer address(LValue base, const AbstractField& field, ptrdiff_t offset = 0)
252 {
253 return address(field, base, offset + field.offset());
254 }
255
256 LValue baseIndex(LValue base, LValue index, Scale, ptrdiff_t offset = 0);
257
258 TypedPointer baseIndex(const AbstractHeap& heap, LValue base, LValue index, Scale scale, ptrdiff_t offset = 0)
259 {
260 return TypedPointer(heap, baseIndex(base, index, scale, offset));
261 }
262 TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0)
263 {
264 return heap.baseIndex(*this, base, index, indexAsConstant, offset);
265 }
266
267 TypedPointer absolute(void* address)
268 {
269 return TypedPointer(m_heaps->absolute[address], constIntPtr(address));
270 }
271
272 LValue load8(LValue base, const AbstractField& field) { return load8(address(base, field)); }
273 LValue load16(LValue base, const AbstractField& field) { return load16(address(base, field)); }
274 LValue load32(LValue base, const AbstractField& field) { return load32(address(base, field)); }
275 LValue load64(LValue base, const AbstractField& field) { return load64(address(base, field)); }
276 LValue loadPtr(LValue base, const AbstractField& field) { return loadPtr(address(base, field)); }
277 LValue loadDouble(LValue base, const AbstractField& field) { return loadDouble(address(base, field)); }
278 void store8(LValue value, LValue base, const AbstractField& field) { store8(value, address(base, field)); }
279 void store32(LValue value, LValue base, const AbstractField& field) { store32(value, address(base, field)); }
280 void store64(LValue value, LValue base, const AbstractField& field) { store64(value, address(base, field)); }
281 void storePtr(LValue value, LValue base, const AbstractField& field) { storePtr(value, address(base, field)); }
282 void storeDouble(LValue value, LValue base, const AbstractField& field) { storeDouble(value, address(base, field)); }
283
284 void ascribeRange(LValue loadInstruction, const ValueRange& range)
285 {
286 range.decorateInstruction(m_context, loadInstruction, rangeKind);
287 }
288
289 LValue nonNegative32(LValue loadInstruction)
290 {
291 ascribeRange(loadInstruction, nonNegativeInt32);
292 return loadInstruction;
293 }
294
295 LValue load32NonNegative(TypedPointer pointer) { return nonNegative32(load32(pointer)); }
296 LValue load32NonNegative(LValue base, const AbstractField& field) { return nonNegative32(load32(base, field)); }
297
298 LValue icmp(LIntPredicate cond, LValue left, LValue right) { return buildICmp(m_builder, cond, left, right); }
299 LValue equal(LValue left, LValue right) { return icmp(LLVMIntEQ, left, right); }
300 LValue notEqual(LValue left, LValue right) { return icmp(LLVMIntNE, left, right); }
301 LValue above(LValue left, LValue right) { return icmp(LLVMIntUGT, left, right); }
302 LValue aboveOrEqual(LValue left, LValue right) { return icmp(LLVMIntUGE, left, right); }
303 LValue below(LValue left, LValue right) { return icmp(LLVMIntULT, left, right); }
304 LValue belowOrEqual(LValue left, LValue right) { return icmp(LLVMIntULE, left, right); }
305 LValue greaterThan(LValue left, LValue right) { return icmp(LLVMIntSGT, left, right); }
306 LValue greaterThanOrEqual(LValue left, LValue right) { return icmp(LLVMIntSGE, left, right); }
307 LValue lessThan(LValue left, LValue right) { return icmp(LLVMIntSLT, left, right); }
308 LValue lessThanOrEqual(LValue left, LValue right) { return icmp(LLVMIntSLE, left, right); }
309
310 LValue fcmp(LRealPredicate cond, LValue left, LValue right) { return buildFCmp(m_builder, cond, left, right); }
311 LValue doubleEqual(LValue left, LValue right) { return fcmp(LLVMRealOEQ, left, right); }
312 LValue doubleNotEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUNE, left, right); }
313 LValue doubleLessThan(LValue left, LValue right) { return fcmp(LLVMRealOLT, left, right); }
314 LValue doubleLessThanOrEqual(LValue left, LValue right) { return fcmp(LLVMRealOLE, left, right); }
315 LValue doubleGreaterThan(LValue left, LValue right) { return fcmp(LLVMRealOGT, left, right); }
316 LValue doubleGreaterThanOrEqual(LValue left, LValue right) { return fcmp(LLVMRealOGE, left, right); }
317 LValue doubleEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUEQ, left, right); }
318 LValue doubleNotEqual(LValue left, LValue right) { return fcmp(LLVMRealONE, left, right); }
319 LValue doubleLessThanOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealULT, left, right); }
320 LValue doubleLessThanOrEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealULE, left, right); }
321 LValue doubleGreaterThanOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUGT, left, right); }
322 LValue doubleGreaterThanOrEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUGE, left, right); }
323
324 LValue isZero8(LValue value) { return equal(value, int8Zero); }
325 LValue notZero8(LValue value) { return notEqual(value, int8Zero); }
326 LValue isZero32(LValue value) { return equal(value, int32Zero); }
327 LValue notZero32(LValue value) { return notEqual(value, int32Zero); }
328 LValue isZero64(LValue value) { return equal(value, int64Zero); }
329 LValue notZero64(LValue value) { return notEqual(value, int64Zero); }
330 LValue isNull(LValue value) { return equal(value, intPtrZero); }
331 LValue notNull(LValue value) { return notEqual(value, intPtrZero); }
332
333 LValue testIsZero8(LValue value, LValue mask) { return isZero8(bitAnd(value, mask)); }
334 LValue testNonZero8(LValue value, LValue mask) { return notZero8(bitAnd(value, mask)); }
335 LValue testIsZero32(LValue value, LValue mask) { return isZero32(bitAnd(value, mask)); }
336 LValue testNonZero32(LValue value, LValue mask) { return notZero32(bitAnd(value, mask)); }
337 LValue testIsZero64(LValue value, LValue mask) { return isZero64(bitAnd(value, mask)); }
338 LValue testNonZero64(LValue value, LValue mask) { return notZero64(bitAnd(value, mask)); }
339
340 LValue select(LValue value, LValue taken, LValue notTaken) { return buildSelect(m_builder, value, taken, notTaken); }
341 LValue extractValue(LValue aggVal, unsigned index) { return buildExtractValue(m_builder, aggVal, index); }
342
343 LValue fence(LAtomicOrdering ordering = LLVMAtomicOrderingSequentiallyConsistent, SynchronizationScope scope = CrossThread) { return buildFence(m_builder, ordering, scope); }
344 LValue fenceAcqRel() { return fence(LLVMAtomicOrderingAcquireRelease); }
345
346 template<typename VectorType>
347 LValue call(LValue function, const VectorType& vector) { return buildCall(m_builder, function, vector); }
348 LValue call(LValue function) { return buildCall(m_builder, function); }
349 LValue call(LValue function, LValue arg1) { return buildCall(m_builder, function, arg1); }
350 LValue call(LValue function, LValue arg1, LValue arg2) { return buildCall(m_builder, function, arg1, arg2); }
351 LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3) { return buildCall(m_builder, function, arg1, arg2, arg3); }
352 LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4); }
353 LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4, arg5); }
354 LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5, LValue arg6) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4, arg5, arg6); }
355 LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5, LValue arg6, LValue arg7) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4, arg5, arg6, arg7); }
356 LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5, LValue arg6, LValue arg7, LValue arg8) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); }
357
358 template<typename FunctionType>
359 LValue operation(FunctionType function)
360 {
361 return intToPtr(constIntPtr(function), pointerType(operationType(function)));
362 }
363
364 void jump(LBasicBlock destination) { buildBr(m_builder, destination); }
365 void branch(LValue condition, LBasicBlock taken, Weight takenWeight, LBasicBlock notTaken, Weight notTakenWeight);
366 void branch(LValue condition, WeightedTarget taken, WeightedTarget notTaken)
367 {
368 branch(condition, taken.target(), taken.weight(), notTaken.target(), notTaken.weight());
369 }
370
371 template<typename VectorType>
372 void switchInstruction(LValue value, const VectorType& cases, LBasicBlock fallThrough, Weight fallThroughWeight)
373 {
374 LValue inst = buildSwitch(m_builder, value, cases, fallThrough);
375
376 double total = 0;
377 if (!fallThroughWeight)
378 return;
379 total += fallThroughWeight.value();
380 for (unsigned i = cases.size(); i--;) {
381 if (!cases[i].weight())
382 return;
383 total += cases[i].weight().value();
384 }
385
386 Vector<LValue> mdArgs;
387 mdArgs.append(branchWeights);
388 mdArgs.append(constInt32(fallThroughWeight.scaleToTotal(total)));
389 for (unsigned i = 0; i < cases.size(); ++i)
390 mdArgs.append(constInt32(cases[i].weight().scaleToTotal(total)));
391
392 setMetadata(inst, profKind, mdNode(m_context, mdArgs));
393 }
394
395 void ret(LValue value) { buildRet(m_builder, value); }
396
397 void unreachable() { buildUnreachable(m_builder); }
398
399 void trap()
400 {
401 call(trapIntrinsic());
402 }
403
404 void crashNonTerminal();
405
406 void crash()
407 {
408 crashNonTerminal();
409 unreachable();
410 }
411
412 ValueFromBlock anchor(LValue value)
413 {
414 return ValueFromBlock(value, m_block);
415 }
416
417 LValue m_function;
418 AbstractHeapRepository* m_heaps;
419 LBuilder m_builder;
420 LBasicBlock m_block;
421 LBasicBlock m_nextBlock;
422 };
423
424 #define FTL_NEW_BLOCK(output, nameArguments) \
425 (LIKELY(!verboseCompilationEnabled()) \
426 ? (output).newBlock() \
427 : (output).newBlock((toCString nameArguments).data()))
428
429 } } // namespace JSC::FTL
430
431 #endif // ENABLE(FTL_JIT)
432
433 #endif // FTLOutput_h
434