]> git.saurik.com Git - apple/javascriptcore.git/blob - ftl/FTLOutput.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / ftl / FTLOutput.h
1 /*
2 * Copyright (C) 2013-2015 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); } // arithmetic = signed
137 LValue lShr(LValue left, LValue right) { return buildLShr(m_builder, left, right); } // logical = unsigned
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 ceil64(LValue operand)
143 {
144 return call(ceil64Intrinsic(), operand);
145 }
146 LValue ctlz32(LValue xOperand, LValue yOperand)
147 {
148 return call(ctlz32Intrinsic(), xOperand, yOperand);
149 }
150 LValue addWithOverflow32(LValue left, LValue right)
151 {
152 return call(addWithOverflow32Intrinsic(), left, right);
153 }
154 LValue subWithOverflow32(LValue left, LValue right)
155 {
156 return call(subWithOverflow32Intrinsic(), left, right);
157 }
158 LValue mulWithOverflow32(LValue left, LValue right)
159 {
160 return call(mulWithOverflow32Intrinsic(), left, right);
161 }
162 LValue addWithOverflow64(LValue left, LValue right)
163 {
164 return call(addWithOverflow64Intrinsic(), left, right);
165 }
166 LValue subWithOverflow64(LValue left, LValue right)
167 {
168 return call(subWithOverflow64Intrinsic(), left, right);
169 }
170 LValue mulWithOverflow64(LValue left, LValue right)
171 {
172 return call(mulWithOverflow64Intrinsic(), left, right);
173 }
174 LValue doubleAbs(LValue value)
175 {
176 return call(doubleAbsIntrinsic(), value);
177 }
178
179 LValue doubleSin(LValue value)
180 {
181 return call(doubleSinIntrinsic(), value);
182 }
183 LValue doubleCos(LValue value)
184 {
185 return call(doubleCosIntrinsic(), value);
186 }
187
188 LValue doublePow(LValue xOperand, LValue yOperand)
189 {
190 return call(doublePowIntrinsic(), xOperand, yOperand);
191 }
192
193 LValue doublePowi(LValue xOperand, LValue yOperand)
194 {
195 return call(doublePowiIntrinsic(), xOperand, yOperand);
196 }
197
198 LValue doubleSqrt(LValue value)
199 {
200 return call(doubleSqrtIntrinsic(), value);
201 }
202
203 LValue doubleLog(LValue value)
204 {
205 return call(doubleLogIntrinsic(), value);
206 }
207
208 static bool hasSensibleDoubleToInt() { return isX86(); }
209 LValue sensibleDoubleToInt(LValue);
210
211 LValue signExt(LValue value, LType type) { return buildSExt(m_builder, value, type); }
212 LValue zeroExt(LValue value, LType type) { return buildZExt(m_builder, value, type); }
213 LValue zeroExtPtr(LValue value) { return zeroExt(value, intPtr); }
214 LValue fpToInt(LValue value, LType type) { return buildFPToSI(m_builder, value, type); }
215 LValue fpToUInt(LValue value, LType type) { return buildFPToUI(m_builder, value, type); }
216 LValue fpToInt32(LValue value) { return fpToInt(value, int32); }
217 LValue fpToUInt32(LValue value) { return fpToUInt(value, int32); }
218 LValue intToFP(LValue value, LType type) { return buildSIToFP(m_builder, value, type); }
219 LValue intToDouble(LValue value) { return intToFP(value, doubleType); }
220 LValue unsignedToFP(LValue value, LType type) { return buildUIToFP(m_builder, value, type); }
221 LValue unsignedToDouble(LValue value) { return unsignedToFP(value, doubleType); }
222 LValue intCast(LValue value, LType type) { return buildIntCast(m_builder, value, type); }
223 LValue castToInt32(LValue value) { return intCast(value, int32); }
224 LValue fpCast(LValue value, LType type) { return buildFPCast(m_builder, value, type); }
225 LValue intToPtr(LValue value, LType type) { return buildIntToPtr(m_builder, value, type); }
226 LValue ptrToInt(LValue value, LType type) { return buildPtrToInt(m_builder, value, type); }
227 LValue bitCast(LValue value, LType type) { return buildBitCast(m_builder, value, type); }
228
229 // Hilariously, the #define machinery in the stdlib means that this method is actually called
230 // __builtin_alloca. So far this appears benign. :-|
231 LValue alloca(LType type) { return buildAlloca(m_builder, type); }
232
233 // Access the value of an alloca. Also used as a low-level implementation primitive for
234 // load(). Never use this to load from "pointers" in the FTL sense, since FTL pointers
235 // are actually integers. This requires an LLVM pointer. Broadly speaking, you don't
236 // have any LLVM pointers even if you really think you do. A TypedPointer is not an
237 // LLVM pointer. See comment block at top of this file to understand the distinction
238 // between LLVM pointers, FTL pointers, and FTL references.
239 LValue get(LValue reference) { return buildLoad(m_builder, reference); }
240 // Similar to get() but for storing to the value in an alloca.
241 LValue set(LValue value, LValue reference) { return buildStore(m_builder, value, reference); }
242
243 LValue load(TypedPointer, LType refType);
244 void store(LValue, TypedPointer, LType refType);
245
246 LValue load8(TypedPointer pointer) { return load(pointer, ref8); }
247 LValue load16(TypedPointer pointer) { return load(pointer, ref16); }
248 LValue load32(TypedPointer pointer) { return load(pointer, ref32); }
249 LValue load64(TypedPointer pointer) { return load(pointer, ref64); }
250 LValue loadPtr(TypedPointer pointer) { return load(pointer, refPtr); }
251 LValue loadFloat(TypedPointer pointer) { return load(pointer, refFloat); }
252 LValue loadDouble(TypedPointer pointer) { return load(pointer, refDouble); }
253 void store8(LValue value, TypedPointer pointer) { store(value, pointer, ref8); }
254 void store16(LValue value, TypedPointer pointer) { store(value, pointer, ref16); }
255 void store32(LValue value, TypedPointer pointer) { store(value, pointer, ref32); }
256 void store64(LValue value, TypedPointer pointer) { store(value, pointer, ref64); }
257 void storePtr(LValue value, TypedPointer pointer) { store(value, pointer, refPtr); }
258 void storeFloat(LValue value, TypedPointer pointer) { store(value, pointer, refFloat); }
259 void storeDouble(LValue value, TypedPointer pointer) { store(value, pointer, refDouble); }
260
261 LValue addPtr(LValue value, ptrdiff_t immediate = 0)
262 {
263 if (!immediate)
264 return value;
265 return add(value, constIntPtr(immediate));
266 }
267
268 // Construct an address by offsetting base by the requested amount and ascribing
269 // the requested abstract heap to it.
270 TypedPointer address(const AbstractHeap& heap, LValue base, ptrdiff_t offset = 0)
271 {
272 return TypedPointer(heap, addPtr(base, offset));
273 }
274 // Construct an address by offsetting base by the amount specified by the field,
275 // and optionally an additional amount (use this with care), and then creating
276 // a TypedPointer with the given field as the heap.
277 TypedPointer address(LValue base, const AbstractField& field, ptrdiff_t offset = 0)
278 {
279 return address(field, base, offset + field.offset());
280 }
281
282 LValue baseIndex(LValue base, LValue index, Scale, ptrdiff_t offset = 0);
283
284 TypedPointer baseIndex(const AbstractHeap& heap, LValue base, LValue index, Scale scale, ptrdiff_t offset = 0)
285 {
286 return TypedPointer(heap, baseIndex(base, index, scale, offset));
287 }
288 TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0)
289 {
290 return heap.baseIndex(*this, base, index, indexAsConstant, offset);
291 }
292
293 TypedPointer absolute(void* address)
294 {
295 return TypedPointer(m_heaps->absolute[address], constIntPtr(address));
296 }
297
298 LValue load8(LValue base, const AbstractField& field) { return load8(address(base, field)); }
299 LValue load16(LValue base, const AbstractField& field) { return load16(address(base, field)); }
300 LValue load32(LValue base, const AbstractField& field) { return load32(address(base, field)); }
301 LValue load64(LValue base, const AbstractField& field) { return load64(address(base, field)); }
302 LValue loadPtr(LValue base, const AbstractField& field) { return loadPtr(address(base, field)); }
303 LValue loadDouble(LValue base, const AbstractField& field) { return loadDouble(address(base, field)); }
304 void store8(LValue value, LValue base, const AbstractField& field) { store8(value, address(base, field)); }
305 void store32(LValue value, LValue base, const AbstractField& field) { store32(value, address(base, field)); }
306 void store64(LValue value, LValue base, const AbstractField& field) { store64(value, address(base, field)); }
307 void storePtr(LValue value, LValue base, const AbstractField& field) { storePtr(value, address(base, field)); }
308 void storeDouble(LValue value, LValue base, const AbstractField& field) { storeDouble(value, address(base, field)); }
309
310 void ascribeRange(LValue loadInstruction, const ValueRange& range)
311 {
312 range.decorateInstruction(m_context, loadInstruction, rangeKind);
313 }
314
315 LValue nonNegative32(LValue loadInstruction)
316 {
317 ascribeRange(loadInstruction, nonNegativeInt32);
318 return loadInstruction;
319 }
320
321 LValue load32NonNegative(TypedPointer pointer) { return nonNegative32(load32(pointer)); }
322 LValue load32NonNegative(LValue base, const AbstractField& field) { return nonNegative32(load32(base, field)); }
323
324 LValue icmp(LIntPredicate cond, LValue left, LValue right) { return buildICmp(m_builder, cond, left, right); }
325 LValue equal(LValue left, LValue right) { return icmp(LLVMIntEQ, left, right); }
326 LValue notEqual(LValue left, LValue right) { return icmp(LLVMIntNE, left, right); }
327 LValue above(LValue left, LValue right) { return icmp(LLVMIntUGT, left, right); }
328 LValue aboveOrEqual(LValue left, LValue right) { return icmp(LLVMIntUGE, left, right); }
329 LValue below(LValue left, LValue right) { return icmp(LLVMIntULT, left, right); }
330 LValue belowOrEqual(LValue left, LValue right) { return icmp(LLVMIntULE, left, right); }
331 LValue greaterThan(LValue left, LValue right) { return icmp(LLVMIntSGT, left, right); }
332 LValue greaterThanOrEqual(LValue left, LValue right) { return icmp(LLVMIntSGE, left, right); }
333 LValue lessThan(LValue left, LValue right) { return icmp(LLVMIntSLT, left, right); }
334 LValue lessThanOrEqual(LValue left, LValue right) { return icmp(LLVMIntSLE, left, right); }
335
336 LValue fcmp(LRealPredicate cond, LValue left, LValue right) { return buildFCmp(m_builder, cond, left, right); }
337 LValue doubleEqual(LValue left, LValue right) { return fcmp(LLVMRealOEQ, left, right); }
338 LValue doubleNotEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUNE, left, right); }
339 LValue doubleLessThan(LValue left, LValue right) { return fcmp(LLVMRealOLT, left, right); }
340 LValue doubleLessThanOrEqual(LValue left, LValue right) { return fcmp(LLVMRealOLE, left, right); }
341 LValue doubleGreaterThan(LValue left, LValue right) { return fcmp(LLVMRealOGT, left, right); }
342 LValue doubleGreaterThanOrEqual(LValue left, LValue right) { return fcmp(LLVMRealOGE, left, right); }
343 LValue doubleEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUEQ, left, right); }
344 LValue doubleNotEqual(LValue left, LValue right) { return fcmp(LLVMRealONE, left, right); }
345 LValue doubleLessThanOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealULT, left, right); }
346 LValue doubleLessThanOrEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealULE, left, right); }
347 LValue doubleGreaterThanOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUGT, left, right); }
348 LValue doubleGreaterThanOrEqualOrUnordered(LValue left, LValue right) { return fcmp(LLVMRealUGE, left, right); }
349
350 LValue isZero8(LValue value) { return equal(value, int8Zero); }
351 LValue notZero8(LValue value) { return notEqual(value, int8Zero); }
352 LValue isZero32(LValue value) { return equal(value, int32Zero); }
353 LValue notZero32(LValue value) { return notEqual(value, int32Zero); }
354 LValue isZero64(LValue value) { return equal(value, int64Zero); }
355 LValue notZero64(LValue value) { return notEqual(value, int64Zero); }
356 LValue isNull(LValue value) { return equal(value, intPtrZero); }
357 LValue notNull(LValue value) { return notEqual(value, intPtrZero); }
358
359 LValue testIsZero8(LValue value, LValue mask) { return isZero8(bitAnd(value, mask)); }
360 LValue testNonZero8(LValue value, LValue mask) { return notZero8(bitAnd(value, mask)); }
361 LValue testIsZero32(LValue value, LValue mask) { return isZero32(bitAnd(value, mask)); }
362 LValue testNonZero32(LValue value, LValue mask) { return notZero32(bitAnd(value, mask)); }
363 LValue testIsZero64(LValue value, LValue mask) { return isZero64(bitAnd(value, mask)); }
364 LValue testNonZero64(LValue value, LValue mask) { return notZero64(bitAnd(value, mask)); }
365
366 LValue select(LValue value, LValue taken, LValue notTaken) { return buildSelect(m_builder, value, taken, notTaken); }
367 LValue extractValue(LValue aggVal, unsigned index) { return buildExtractValue(m_builder, aggVal, index); }
368
369 LValue fence(LAtomicOrdering ordering = LLVMAtomicOrderingSequentiallyConsistent, SynchronizationScope scope = CrossThread) { return buildFence(m_builder, ordering, scope); }
370 LValue fenceAcqRel() { return fence(LLVMAtomicOrderingAcquireRelease); }
371
372 template<typename VectorType>
373 LValue call(LValue function, const VectorType& vector) { return buildCall(m_builder, function, vector); }
374 LValue call(LValue function) { return buildCall(m_builder, function); }
375 LValue call(LValue function, LValue arg1) { return buildCall(m_builder, function, arg1); }
376 template<typename... Args>
377 LValue call(LValue function, LValue arg1, Args... args) { return buildCall(m_builder, function, arg1, args...); }
378
379 template<typename FunctionType>
380 LValue operation(FunctionType function)
381 {
382 return intToPtr(constIntPtr(function), pointerType(operationType(function)));
383 }
384
385 void jump(LBasicBlock destination) { buildBr(m_builder, destination); }
386 void branch(LValue condition, LBasicBlock taken, Weight takenWeight, LBasicBlock notTaken, Weight notTakenWeight);
387 void branch(LValue condition, WeightedTarget taken, WeightedTarget notTaken)
388 {
389 branch(condition, taken.target(), taken.weight(), notTaken.target(), notTaken.weight());
390 }
391
392 // Branches to an already-created handler if true, "falls through" if false. Fall-through is
393 // simulated by creating a continuation for you.
394 void check(LValue condition, WeightedTarget taken, Weight notTakenWeight);
395
396 // Same as check(), but uses Weight::inverse() to compute the notTakenWeight.
397 void check(LValue condition, WeightedTarget taken);
398
399 template<typename VectorType>
400 void switchInstruction(LValue value, const VectorType& cases, LBasicBlock fallThrough, Weight fallThroughWeight)
401 {
402 LValue inst = buildSwitch(m_builder, value, cases, fallThrough);
403
404 double total = 0;
405 if (!fallThroughWeight)
406 return;
407 total += fallThroughWeight.value();
408 for (unsigned i = cases.size(); i--;) {
409 if (!cases[i].weight())
410 return;
411 total += cases[i].weight().value();
412 }
413
414 Vector<LValue> mdArgs;
415 mdArgs.append(branchWeights);
416 mdArgs.append(constInt32(fallThroughWeight.scaleToTotal(total)));
417 for (unsigned i = 0; i < cases.size(); ++i)
418 mdArgs.append(constInt32(cases[i].weight().scaleToTotal(total)));
419
420 setMetadata(inst, profKind, mdNode(m_context, mdArgs));
421 }
422
423 void ret(LValue value) { buildRet(m_builder, value); }
424
425 void unreachable() { buildUnreachable(m_builder); }
426
427 void trap()
428 {
429 call(trapIntrinsic());
430 }
431
432 ValueFromBlock anchor(LValue value)
433 {
434 return ValueFromBlock(value, m_block);
435 }
436
437 LValue m_function;
438 AbstractHeapRepository* m_heaps;
439 LBuilder m_builder;
440 LBasicBlock m_block;
441 LBasicBlock m_nextBlock;
442 };
443
444 #define FTL_NEW_BLOCK(output, nameArguments) \
445 (LIKELY(!verboseCompilationEnabled()) \
446 ? (output).newBlock() \
447 : (output).newBlock((toCString nameArguments).data()))
448
449 } } // namespace JSC::FTL
450
451 #endif // ENABLE(FTL_JIT)
452
453 #endif // FTLOutput_h
454