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 43namespace 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 68enum Scale { ScaleOne, ScaleTwo, ScaleFour, ScaleEight, ScalePtr }; 69 70class Output : public IntrinsicRepository { 71public: 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 435