1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/compiler/simplified-operator.h" 6 7 #include "src/base/lazy-instance.h" 8 #include "src/compiler/opcodes.h" 9 #include "src/compiler/operator.h" 10 #include "src/compiler/types.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace compiler { 15 16 size_t hash_value(BaseTaggedness base_taggedness) { 17 return static_cast<uint8_t>(base_taggedness); 18 } 19 20 std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) { 21 switch (base_taggedness) { 22 case kUntaggedBase: 23 return os << "untagged base"; 24 case kTaggedBase: 25 return os << "tagged base"; 26 } 27 UNREACHABLE(); 28 return os; 29 } 30 31 32 MachineType BufferAccess::machine_type() const { 33 switch (external_array_type_) { 34 case kExternalUint8Array: 35 case kExternalUint8ClampedArray: 36 return MachineType::Uint8(); 37 case kExternalInt8Array: 38 return MachineType::Int8(); 39 case kExternalUint16Array: 40 return MachineType::Uint16(); 41 case kExternalInt16Array: 42 return MachineType::Int16(); 43 case kExternalUint32Array: 44 return MachineType::Uint32(); 45 case kExternalInt32Array: 46 return MachineType::Int32(); 47 case kExternalFloat32Array: 48 return MachineType::Float32(); 49 case kExternalFloat64Array: 50 return MachineType::Float64(); 51 } 52 UNREACHABLE(); 53 return MachineType::None(); 54 } 55 56 57 bool operator==(BufferAccess lhs, BufferAccess rhs) { 58 return lhs.external_array_type() == rhs.external_array_type(); 59 } 60 61 62 bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); } 63 64 65 size_t hash_value(BufferAccess access) { 66 return base::hash<ExternalArrayType>()(access.external_array_type()); 67 } 68 69 70 std::ostream& operator<<(std::ostream& os, BufferAccess access) { 71 switch (access.external_array_type()) { 72 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 73 case kExternal##Type##Array: \ 74 return os << #Type; 75 TYPED_ARRAYS(TYPED_ARRAY_CASE) 76 #undef TYPED_ARRAY_CASE 77 } 78 UNREACHABLE(); 79 return os; 80 } 81 82 83 BufferAccess const BufferAccessOf(const Operator* op) { 84 DCHECK(op->opcode() == IrOpcode::kLoadBuffer || 85 op->opcode() == IrOpcode::kStoreBuffer); 86 return OpParameter<BufferAccess>(op); 87 } 88 89 90 bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) { 91 // On purpose we don't include the write barrier kind here, as this method is 92 // really only relevant for eliminating loads and they don't care about the 93 // write barrier mode. 94 return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset && 95 lhs.machine_type == rhs.machine_type; 96 } 97 98 99 bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) { 100 return !(lhs == rhs); 101 } 102 103 104 size_t hash_value(FieldAccess const& access) { 105 // On purpose we don't include the write barrier kind here, as this method is 106 // really only relevant for eliminating loads and they don't care about the 107 // write barrier mode. 108 return base::hash_combine(access.base_is_tagged, access.offset, 109 access.machine_type); 110 } 111 112 113 std::ostream& operator<<(std::ostream& os, FieldAccess const& access) { 114 os << "[" << access.base_is_tagged << ", " << access.offset << ", "; 115 #ifdef OBJECT_PRINT 116 Handle<Name> name; 117 if (access.name.ToHandle(&name)) { 118 name->Print(os); 119 os << ", "; 120 } 121 #endif 122 access.type->PrintTo(os); 123 os << ", " << access.machine_type << ", " << access.write_barrier_kind << "]"; 124 return os; 125 } 126 127 template <> 128 void Operator1<FieldAccess>::PrintParameter(std::ostream& os, 129 PrintVerbosity verbose) const { 130 if (verbose == PrintVerbosity::kVerbose) { 131 os << parameter(); 132 } else { 133 os << "[+" << parameter().offset << "]"; 134 } 135 } 136 137 bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) { 138 // On purpose we don't include the write barrier kind here, as this method is 139 // really only relevant for eliminating loads and they don't care about the 140 // write barrier mode. 141 return lhs.base_is_tagged == rhs.base_is_tagged && 142 lhs.header_size == rhs.header_size && 143 lhs.machine_type == rhs.machine_type; 144 } 145 146 147 bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) { 148 return !(lhs == rhs); 149 } 150 151 152 size_t hash_value(ElementAccess const& access) { 153 // On purpose we don't include the write barrier kind here, as this method is 154 // really only relevant for eliminating loads and they don't care about the 155 // write barrier mode. 156 return base::hash_combine(access.base_is_tagged, access.header_size, 157 access.machine_type); 158 } 159 160 161 std::ostream& operator<<(std::ostream& os, ElementAccess const& access) { 162 os << access.base_is_tagged << ", " << access.header_size << ", "; 163 access.type->PrintTo(os); 164 os << ", " << access.machine_type << ", " << access.write_barrier_kind; 165 return os; 166 } 167 168 169 const FieldAccess& FieldAccessOf(const Operator* op) { 170 DCHECK_NOT_NULL(op); 171 DCHECK(op->opcode() == IrOpcode::kLoadField || 172 op->opcode() == IrOpcode::kStoreField); 173 return OpParameter<FieldAccess>(op); 174 } 175 176 177 const ElementAccess& ElementAccessOf(const Operator* op) { 178 DCHECK_NOT_NULL(op); 179 DCHECK(op->opcode() == IrOpcode::kLoadElement || 180 op->opcode() == IrOpcode::kStoreElement); 181 return OpParameter<ElementAccess>(op); 182 } 183 184 ExternalArrayType ExternalArrayTypeOf(const Operator* op) { 185 DCHECK(op->opcode() == IrOpcode::kLoadTypedElement || 186 op->opcode() == IrOpcode::kStoreTypedElement); 187 return OpParameter<ExternalArrayType>(op); 188 } 189 190 size_t hash_value(CheckFloat64HoleMode mode) { 191 return static_cast<size_t>(mode); 192 } 193 194 std::ostream& operator<<(std::ostream& os, CheckFloat64HoleMode mode) { 195 switch (mode) { 196 case CheckFloat64HoleMode::kAllowReturnHole: 197 return os << "allow-return-hole"; 198 case CheckFloat64HoleMode::kNeverReturnHole: 199 return os << "never-return-hole"; 200 } 201 UNREACHABLE(); 202 return os; 203 } 204 205 CheckFloat64HoleMode CheckFloat64HoleModeOf(const Operator* op) { 206 DCHECK_EQ(IrOpcode::kCheckFloat64Hole, op->opcode()); 207 return OpParameter<CheckFloat64HoleMode>(op); 208 } 209 210 CheckForMinusZeroMode CheckMinusZeroModeOf(const Operator* op) { 211 DCHECK(op->opcode() == IrOpcode::kCheckedInt32Mul || 212 op->opcode() == IrOpcode::kCheckedFloat64ToInt32 || 213 op->opcode() == IrOpcode::kCheckedTaggedToInt32); 214 return OpParameter<CheckForMinusZeroMode>(op); 215 } 216 217 size_t hash_value(CheckForMinusZeroMode mode) { 218 return static_cast<size_t>(mode); 219 } 220 221 std::ostream& operator<<(std::ostream& os, CheckForMinusZeroMode mode) { 222 switch (mode) { 223 case CheckForMinusZeroMode::kCheckForMinusZero: 224 return os << "check-for-minus-zero"; 225 case CheckForMinusZeroMode::kDontCheckForMinusZero: 226 return os << "dont-check-for-minus-zero"; 227 } 228 UNREACHABLE(); 229 return os; 230 } 231 232 size_t hash_value(CheckTaggedInputMode mode) { 233 return static_cast<size_t>(mode); 234 } 235 236 std::ostream& operator<<(std::ostream& os, CheckTaggedInputMode mode) { 237 switch (mode) { 238 case CheckTaggedInputMode::kNumber: 239 return os << "Number"; 240 case CheckTaggedInputMode::kNumberOrOddball: 241 return os << "NumberOrOddball"; 242 } 243 UNREACHABLE(); 244 return os; 245 } 246 247 CheckTaggedInputMode CheckTaggedInputModeOf(const Operator* op) { 248 DCHECK_EQ(IrOpcode::kCheckedTaggedToFloat64, op->opcode()); 249 return OpParameter<CheckTaggedInputMode>(op); 250 } 251 252 std::ostream& operator<<(std::ostream& os, GrowFastElementsFlags flags) { 253 bool empty = true; 254 if (flags & GrowFastElementsFlag::kArrayObject) { 255 os << "ArrayObject"; 256 empty = false; 257 } 258 if (flags & GrowFastElementsFlag::kDoubleElements) { 259 if (!empty) os << "|"; 260 os << "DoubleElements"; 261 empty = false; 262 } 263 if (flags & GrowFastElementsFlag::kHoleyElements) { 264 if (!empty) os << "|"; 265 os << "HoleyElements"; 266 empty = false; 267 } 268 if (empty) os << "None"; 269 return os; 270 } 271 272 GrowFastElementsFlags GrowFastElementsFlagsOf(const Operator* op) { 273 DCHECK_EQ(IrOpcode::kMaybeGrowFastElements, op->opcode()); 274 return OpParameter<GrowFastElementsFlags>(op); 275 } 276 277 size_t hash_value(ElementsTransition transition) { 278 return static_cast<uint8_t>(transition); 279 } 280 281 std::ostream& operator<<(std::ostream& os, ElementsTransition transition) { 282 switch (transition) { 283 case ElementsTransition::kFastTransition: 284 return os << "fast-transition"; 285 case ElementsTransition::kSlowTransition: 286 return os << "slow-transition"; 287 } 288 UNREACHABLE(); 289 return os; 290 } 291 292 ElementsTransition ElementsTransitionOf(const Operator* op) { 293 DCHECK_EQ(IrOpcode::kTransitionElementsKind, op->opcode()); 294 return OpParameter<ElementsTransition>(op); 295 } 296 297 std::ostream& operator<<(std::ostream& os, NumberOperationHint hint) { 298 switch (hint) { 299 case NumberOperationHint::kSignedSmall: 300 return os << "SignedSmall"; 301 case NumberOperationHint::kSigned32: 302 return os << "Signed32"; 303 case NumberOperationHint::kNumber: 304 return os << "Number"; 305 case NumberOperationHint::kNumberOrOddball: 306 return os << "NumberOrOddball"; 307 } 308 UNREACHABLE(); 309 return os; 310 } 311 312 size_t hash_value(NumberOperationHint hint) { 313 return static_cast<uint8_t>(hint); 314 } 315 316 NumberOperationHint NumberOperationHintOf(const Operator* op) { 317 DCHECK(op->opcode() == IrOpcode::kSpeculativeNumberAdd || 318 op->opcode() == IrOpcode::kSpeculativeNumberSubtract || 319 op->opcode() == IrOpcode::kSpeculativeNumberMultiply || 320 op->opcode() == IrOpcode::kSpeculativeNumberDivide || 321 op->opcode() == IrOpcode::kSpeculativeNumberModulus || 322 op->opcode() == IrOpcode::kSpeculativeNumberShiftLeft || 323 op->opcode() == IrOpcode::kSpeculativeNumberShiftRight || 324 op->opcode() == IrOpcode::kSpeculativeNumberShiftRightLogical || 325 op->opcode() == IrOpcode::kSpeculativeNumberBitwiseAnd || 326 op->opcode() == IrOpcode::kSpeculativeNumberBitwiseOr || 327 op->opcode() == IrOpcode::kSpeculativeNumberBitwiseXor || 328 op->opcode() == IrOpcode::kSpeculativeNumberEqual || 329 op->opcode() == IrOpcode::kSpeculativeNumberLessThan || 330 op->opcode() == IrOpcode::kSpeculativeNumberLessThanOrEqual); 331 return OpParameter<NumberOperationHint>(op); 332 } 333 334 PretenureFlag PretenureFlagOf(const Operator* op) { 335 DCHECK_EQ(IrOpcode::kAllocate, op->opcode()); 336 return OpParameter<PretenureFlag>(op); 337 } 338 339 UnicodeEncoding UnicodeEncodingOf(const Operator* op) { 340 DCHECK(op->opcode() == IrOpcode::kStringFromCodePoint); 341 return OpParameter<UnicodeEncoding>(op); 342 } 343 344 #define PURE_OP_LIST(V) \ 345 V(BooleanNot, Operator::kNoProperties, 1, 0) \ 346 V(NumberEqual, Operator::kCommutative, 2, 0) \ 347 V(NumberLessThan, Operator::kNoProperties, 2, 0) \ 348 V(NumberLessThanOrEqual, Operator::kNoProperties, 2, 0) \ 349 V(NumberAdd, Operator::kCommutative, 2, 0) \ 350 V(NumberSubtract, Operator::kNoProperties, 2, 0) \ 351 V(NumberMultiply, Operator::kCommutative, 2, 0) \ 352 V(NumberDivide, Operator::kNoProperties, 2, 0) \ 353 V(NumberModulus, Operator::kNoProperties, 2, 0) \ 354 V(NumberBitwiseOr, Operator::kCommutative, 2, 0) \ 355 V(NumberBitwiseXor, Operator::kCommutative, 2, 0) \ 356 V(NumberBitwiseAnd, Operator::kCommutative, 2, 0) \ 357 V(NumberShiftLeft, Operator::kNoProperties, 2, 0) \ 358 V(NumberShiftRight, Operator::kNoProperties, 2, 0) \ 359 V(NumberShiftRightLogical, Operator::kNoProperties, 2, 0) \ 360 V(NumberImul, Operator::kCommutative, 2, 0) \ 361 V(NumberAbs, Operator::kNoProperties, 1, 0) \ 362 V(NumberClz32, Operator::kNoProperties, 1, 0) \ 363 V(NumberCeil, Operator::kNoProperties, 1, 0) \ 364 V(NumberFloor, Operator::kNoProperties, 1, 0) \ 365 V(NumberFround, Operator::kNoProperties, 1, 0) \ 366 V(NumberAcos, Operator::kNoProperties, 1, 0) \ 367 V(NumberAcosh, Operator::kNoProperties, 1, 0) \ 368 V(NumberAsin, Operator::kNoProperties, 1, 0) \ 369 V(NumberAsinh, Operator::kNoProperties, 1, 0) \ 370 V(NumberAtan, Operator::kNoProperties, 1, 0) \ 371 V(NumberAtan2, Operator::kNoProperties, 2, 0) \ 372 V(NumberAtanh, Operator::kNoProperties, 1, 0) \ 373 V(NumberCbrt, Operator::kNoProperties, 1, 0) \ 374 V(NumberCos, Operator::kNoProperties, 1, 0) \ 375 V(NumberCosh, Operator::kNoProperties, 1, 0) \ 376 V(NumberExp, Operator::kNoProperties, 1, 0) \ 377 V(NumberExpm1, Operator::kNoProperties, 1, 0) \ 378 V(NumberLog, Operator::kNoProperties, 1, 0) \ 379 V(NumberLog1p, Operator::kNoProperties, 1, 0) \ 380 V(NumberLog10, Operator::kNoProperties, 1, 0) \ 381 V(NumberLog2, Operator::kNoProperties, 1, 0) \ 382 V(NumberMax, Operator::kNoProperties, 2, 0) \ 383 V(NumberMin, Operator::kNoProperties, 2, 0) \ 384 V(NumberPow, Operator::kNoProperties, 2, 0) \ 385 V(NumberRound, Operator::kNoProperties, 1, 0) \ 386 V(NumberSign, Operator::kNoProperties, 1, 0) \ 387 V(NumberSin, Operator::kNoProperties, 1, 0) \ 388 V(NumberSinh, Operator::kNoProperties, 1, 0) \ 389 V(NumberSqrt, Operator::kNoProperties, 1, 0) \ 390 V(NumberTan, Operator::kNoProperties, 1, 0) \ 391 V(NumberTanh, Operator::kNoProperties, 1, 0) \ 392 V(NumberTrunc, Operator::kNoProperties, 1, 0) \ 393 V(NumberToBoolean, Operator::kNoProperties, 1, 0) \ 394 V(NumberToInt32, Operator::kNoProperties, 1, 0) \ 395 V(NumberToUint32, Operator::kNoProperties, 1, 0) \ 396 V(NumberToUint8Clamped, Operator::kNoProperties, 1, 0) \ 397 V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \ 398 V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \ 399 V(StringFromCharCode, Operator::kNoProperties, 1, 0) \ 400 V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \ 401 V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \ 402 V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \ 403 V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1, 0) \ 404 V(ChangeTaggedToInt32, Operator::kNoProperties, 1, 0) \ 405 V(ChangeTaggedToUint32, Operator::kNoProperties, 1, 0) \ 406 V(ChangeTaggedToFloat64, Operator::kNoProperties, 1, 0) \ 407 V(ChangeFloat64ToTagged, Operator::kNoProperties, 1, 0) \ 408 V(ChangeFloat64ToTaggedPointer, Operator::kNoProperties, 1, 0) \ 409 V(ChangeInt31ToTaggedSigned, Operator::kNoProperties, 1, 0) \ 410 V(ChangeInt32ToTagged, Operator::kNoProperties, 1, 0) \ 411 V(ChangeUint32ToTagged, Operator::kNoProperties, 1, 0) \ 412 V(ChangeTaggedToBit, Operator::kNoProperties, 1, 0) \ 413 V(ChangeBitToTagged, Operator::kNoProperties, 1, 0) \ 414 V(TruncateTaggedToBit, Operator::kNoProperties, 1, 0) \ 415 V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \ 416 V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \ 417 V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \ 418 V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \ 419 V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \ 420 V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \ 421 V(ObjectIsString, Operator::kNoProperties, 1, 0) \ 422 V(ObjectIsUndetectable, Operator::kNoProperties, 1, 0) \ 423 V(ConvertTaggedHoleToUndefined, Operator::kNoProperties, 1, 0) \ 424 V(ReferenceEqual, Operator::kCommutative, 2, 0) \ 425 V(StringEqual, Operator::kCommutative, 2, 0) \ 426 V(StringLessThan, Operator::kNoProperties, 2, 0) \ 427 V(StringLessThanOrEqual, Operator::kNoProperties, 2, 0) 428 429 #define SPECULATIVE_NUMBER_BINOP_LIST(V) \ 430 SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \ 431 V(SpeculativeNumberEqual) \ 432 V(SpeculativeNumberLessThan) \ 433 V(SpeculativeNumberLessThanOrEqual) 434 435 #define CHECKED_OP_LIST(V) \ 436 V(CheckBounds, 2, 1) \ 437 V(CheckHeapObject, 1, 1) \ 438 V(CheckIf, 1, 0) \ 439 V(CheckNumber, 1, 1) \ 440 V(CheckSmi, 1, 1) \ 441 V(CheckString, 1, 1) \ 442 V(CheckTaggedHole, 1, 1) \ 443 V(CheckedInt32Add, 2, 1) \ 444 V(CheckedInt32Sub, 2, 1) \ 445 V(CheckedInt32Div, 2, 1) \ 446 V(CheckedInt32Mod, 2, 1) \ 447 V(CheckedUint32Div, 2, 1) \ 448 V(CheckedUint32Mod, 2, 1) \ 449 V(CheckedUint32ToInt32, 1, 1) \ 450 V(CheckedUint32ToTaggedSigned, 1, 1) \ 451 V(CheckedInt32ToTaggedSigned, 1, 1) \ 452 V(CheckedTaggedSignedToInt32, 1, 1) \ 453 V(CheckedTaggedToTaggedSigned, 1, 1) \ 454 V(CheckedTaggedToTaggedPointer, 1, 1) \ 455 V(CheckedTruncateTaggedToWord32, 1, 1) 456 457 struct SimplifiedOperatorGlobalCache final { 458 #define PURE(Name, properties, value_input_count, control_input_count) \ 459 struct Name##Operator final : public Operator { \ 460 Name##Operator() \ 461 : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \ 462 value_input_count, 0, control_input_count, 1, 0, 0) {} \ 463 }; \ 464 Name##Operator k##Name; 465 PURE_OP_LIST(PURE) 466 #undef PURE 467 468 #define CHECKED(Name, value_input_count, value_output_count) \ 469 struct Name##Operator final : public Operator { \ 470 Name##Operator() \ 471 : Operator(IrOpcode::k##Name, \ 472 Operator::kFoldable | Operator::kNoThrow, #Name, \ 473 value_input_count, 1, 1, value_output_count, 1, 0) {} \ 474 }; \ 475 Name##Operator k##Name; 476 CHECKED_OP_LIST(CHECKED) 477 #undef CHECKED 478 479 template <UnicodeEncoding kEncoding> 480 struct StringFromCodePointOperator final : public Operator1<UnicodeEncoding> { 481 StringFromCodePointOperator() 482 : Operator1<UnicodeEncoding>(IrOpcode::kStringFromCodePoint, 483 Operator::kPure, "StringFromCodePoint", 1, 484 0, 0, 1, 0, 0, kEncoding) {} 485 }; 486 StringFromCodePointOperator<UnicodeEncoding::UTF16> 487 kStringFromCodePointOperatorUTF16; 488 StringFromCodePointOperator<UnicodeEncoding::UTF32> 489 kStringFromCodePointOperatorUTF32; 490 491 struct ArrayBufferWasNeuteredOperator final : public Operator { 492 ArrayBufferWasNeuteredOperator() 493 : Operator(IrOpcode::kArrayBufferWasNeutered, Operator::kEliminatable, 494 "ArrayBufferWasNeutered", 1, 1, 1, 1, 1, 0) {} 495 }; 496 ArrayBufferWasNeuteredOperator kArrayBufferWasNeutered; 497 498 template <CheckForMinusZeroMode kMode> 499 struct CheckedInt32MulOperator final 500 : public Operator1<CheckForMinusZeroMode> { 501 CheckedInt32MulOperator() 502 : Operator1<CheckForMinusZeroMode>( 503 IrOpcode::kCheckedInt32Mul, 504 Operator::kFoldable | Operator::kNoThrow, "CheckedInt32Mul", 2, 1, 505 1, 1, 1, 0, kMode) {} 506 }; 507 CheckedInt32MulOperator<CheckForMinusZeroMode::kCheckForMinusZero> 508 kCheckedInt32MulCheckForMinusZeroOperator; 509 CheckedInt32MulOperator<CheckForMinusZeroMode::kDontCheckForMinusZero> 510 kCheckedInt32MulDontCheckForMinusZeroOperator; 511 512 template <CheckForMinusZeroMode kMode> 513 struct CheckedFloat64ToInt32Operator final 514 : public Operator1<CheckForMinusZeroMode> { 515 CheckedFloat64ToInt32Operator() 516 : Operator1<CheckForMinusZeroMode>( 517 IrOpcode::kCheckedFloat64ToInt32, 518 Operator::kFoldable | Operator::kNoThrow, "CheckedFloat64ToInt32", 519 1, 1, 1, 1, 1, 0, kMode) {} 520 }; 521 CheckedFloat64ToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero> 522 kCheckedFloat64ToInt32CheckForMinusZeroOperator; 523 CheckedFloat64ToInt32Operator<CheckForMinusZeroMode::kDontCheckForMinusZero> 524 kCheckedFloat64ToInt32DontCheckForMinusZeroOperator; 525 526 template <CheckForMinusZeroMode kMode> 527 struct CheckedTaggedToInt32Operator final 528 : public Operator1<CheckForMinusZeroMode> { 529 CheckedTaggedToInt32Operator() 530 : Operator1<CheckForMinusZeroMode>( 531 IrOpcode::kCheckedTaggedToInt32, 532 Operator::kFoldable | Operator::kNoThrow, "CheckedTaggedToInt32", 533 1, 1, 1, 1, 1, 0, kMode) {} 534 }; 535 CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero> 536 kCheckedTaggedToInt32CheckForMinusZeroOperator; 537 CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kDontCheckForMinusZero> 538 kCheckedTaggedToInt32DontCheckForMinusZeroOperator; 539 540 template <CheckTaggedInputMode kMode> 541 struct CheckedTaggedToFloat64Operator final 542 : public Operator1<CheckTaggedInputMode> { 543 CheckedTaggedToFloat64Operator() 544 : Operator1<CheckTaggedInputMode>( 545 IrOpcode::kCheckedTaggedToFloat64, 546 Operator::kFoldable | Operator::kNoThrow, 547 "CheckedTaggedToFloat64", 1, 1, 1, 1, 1, 0, kMode) {} 548 }; 549 CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumber> 550 kCheckedTaggedToFloat64NumberOperator; 551 CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumberOrOddball> 552 kCheckedTaggedToFloat64NumberOrOddballOperator; 553 554 template <CheckFloat64HoleMode kMode> 555 struct CheckFloat64HoleNaNOperator final 556 : public Operator1<CheckFloat64HoleMode> { 557 CheckFloat64HoleNaNOperator() 558 : Operator1<CheckFloat64HoleMode>( 559 IrOpcode::kCheckFloat64Hole, 560 Operator::kFoldable | Operator::kNoThrow, "CheckFloat64Hole", 1, 561 1, 1, 1, 1, 0, kMode) {} 562 }; 563 CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kAllowReturnHole> 564 kCheckFloat64HoleAllowReturnHoleOperator; 565 CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kNeverReturnHole> 566 kCheckFloat64HoleNeverReturnHoleOperator; 567 568 template <PretenureFlag kPretenure> 569 struct AllocateOperator final : public Operator1<PretenureFlag> { 570 AllocateOperator() 571 : Operator1<PretenureFlag>( 572 IrOpcode::kAllocate, 573 Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, 574 "Allocate", 1, 1, 1, 1, 1, 0, kPretenure) {} 575 }; 576 AllocateOperator<NOT_TENURED> kAllocateNotTenuredOperator; 577 AllocateOperator<TENURED> kAllocateTenuredOperator; 578 579 struct EnsureWritableFastElementsOperator final : public Operator { 580 EnsureWritableFastElementsOperator() 581 : Operator( // -- 582 IrOpcode::kEnsureWritableFastElements, // opcode 583 Operator::kNoDeopt | Operator::kNoThrow, // flags 584 "EnsureWritableFastElements", // name 585 2, 1, 1, 1, 1, 0) {} // counts 586 }; 587 EnsureWritableFastElementsOperator kEnsureWritableFastElements; 588 589 #define SPECULATIVE_NUMBER_BINOP(Name) \ 590 template <NumberOperationHint kHint> \ 591 struct Name##Operator final : public Operator1<NumberOperationHint> { \ 592 Name##Operator() \ 593 : Operator1<NumberOperationHint>( \ 594 IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, \ 595 #Name, 2, 1, 1, 1, 1, 0, kHint) {} \ 596 }; \ 597 Name##Operator<NumberOperationHint::kSignedSmall> \ 598 k##Name##SignedSmallOperator; \ 599 Name##Operator<NumberOperationHint::kSigned32> k##Name##Signed32Operator; \ 600 Name##Operator<NumberOperationHint::kNumber> k##Name##NumberOperator; \ 601 Name##Operator<NumberOperationHint::kNumberOrOddball> \ 602 k##Name##NumberOrOddballOperator; 603 SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP) 604 #undef SPECULATIVE_NUMBER_BINOP 605 606 #define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \ 607 struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \ 608 LoadBuffer##Type##Operator() \ 609 : Operator1<BufferAccess>( \ 610 IrOpcode::kLoadBuffer, \ 611 Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, \ 612 "LoadBuffer", 3, 1, 1, 1, 1, 0, \ 613 BufferAccess(kExternal##Type##Array)) {} \ 614 }; \ 615 struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \ 616 StoreBuffer##Type##Operator() \ 617 : Operator1<BufferAccess>( \ 618 IrOpcode::kStoreBuffer, \ 619 Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow, \ 620 "StoreBuffer", 4, 1, 1, 0, 1, 0, \ 621 BufferAccess(kExternal##Type##Array)) {} \ 622 }; \ 623 LoadBuffer##Type##Operator kLoadBuffer##Type; \ 624 StoreBuffer##Type##Operator kStoreBuffer##Type; 625 TYPED_ARRAYS(BUFFER_ACCESS) 626 #undef BUFFER_ACCESS 627 }; 628 629 630 static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache = 631 LAZY_INSTANCE_INITIALIZER; 632 633 634 SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone) 635 : cache_(kCache.Get()), zone_(zone) {} 636 637 #define GET_FROM_CACHE(Name, ...) \ 638 const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; } 639 PURE_OP_LIST(GET_FROM_CACHE) 640 CHECKED_OP_LIST(GET_FROM_CACHE) 641 GET_FROM_CACHE(ArrayBufferWasNeutered) 642 #undef GET_FROM_CACHE 643 644 const Operator* SimplifiedOperatorBuilder::CheckedInt32Mul( 645 CheckForMinusZeroMode mode) { 646 switch (mode) { 647 case CheckForMinusZeroMode::kCheckForMinusZero: 648 return &cache_.kCheckedInt32MulCheckForMinusZeroOperator; 649 case CheckForMinusZeroMode::kDontCheckForMinusZero: 650 return &cache_.kCheckedInt32MulDontCheckForMinusZeroOperator; 651 } 652 UNREACHABLE(); 653 return nullptr; 654 } 655 656 const Operator* SimplifiedOperatorBuilder::CheckedFloat64ToInt32( 657 CheckForMinusZeroMode mode) { 658 switch (mode) { 659 case CheckForMinusZeroMode::kCheckForMinusZero: 660 return &cache_.kCheckedFloat64ToInt32CheckForMinusZeroOperator; 661 case CheckForMinusZeroMode::kDontCheckForMinusZero: 662 return &cache_.kCheckedFloat64ToInt32DontCheckForMinusZeroOperator; 663 } 664 UNREACHABLE(); 665 return nullptr; 666 } 667 668 const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt32( 669 CheckForMinusZeroMode mode) { 670 switch (mode) { 671 case CheckForMinusZeroMode::kCheckForMinusZero: 672 return &cache_.kCheckedTaggedToInt32CheckForMinusZeroOperator; 673 case CheckForMinusZeroMode::kDontCheckForMinusZero: 674 return &cache_.kCheckedTaggedToInt32DontCheckForMinusZeroOperator; 675 } 676 UNREACHABLE(); 677 return nullptr; 678 } 679 680 const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64( 681 CheckTaggedInputMode mode) { 682 switch (mode) { 683 case CheckTaggedInputMode::kNumber: 684 return &cache_.kCheckedTaggedToFloat64NumberOperator; 685 case CheckTaggedInputMode::kNumberOrOddball: 686 return &cache_.kCheckedTaggedToFloat64NumberOrOddballOperator; 687 } 688 UNREACHABLE(); 689 return nullptr; 690 } 691 692 const Operator* SimplifiedOperatorBuilder::CheckMaps(int map_input_count) { 693 // TODO(bmeurer): Cache the most important versions of this operator. 694 DCHECK_LT(0, map_input_count); 695 int const value_input_count = 1 + map_input_count; 696 return new (zone()) Operator1<int>( // -- 697 IrOpcode::kCheckMaps, // opcode 698 Operator::kNoThrow | Operator::kNoWrite, // flags 699 "CheckMaps", // name 700 value_input_count, 1, 1, 0, 1, 0, // counts 701 map_input_count); // parameter 702 } 703 704 const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole( 705 CheckFloat64HoleMode mode) { 706 switch (mode) { 707 case CheckFloat64HoleMode::kAllowReturnHole: 708 return &cache_.kCheckFloat64HoleAllowReturnHoleOperator; 709 case CheckFloat64HoleMode::kNeverReturnHole: 710 return &cache_.kCheckFloat64HoleNeverReturnHoleOperator; 711 } 712 UNREACHABLE(); 713 return nullptr; 714 } 715 716 const Operator* SimplifiedOperatorBuilder::EnsureWritableFastElements() { 717 return &cache_.kEnsureWritableFastElements; 718 } 719 720 const Operator* SimplifiedOperatorBuilder::MaybeGrowFastElements( 721 GrowFastElementsFlags flags) { 722 return new (zone()) Operator1<GrowFastElementsFlags>( // -- 723 IrOpcode::kMaybeGrowFastElements, // opcode 724 Operator::kNoThrow, // flags 725 "MaybeGrowFastElements", // name 726 4, 1, 1, 1, 1, 0, // counts 727 flags); // parameter 728 } 729 730 const Operator* SimplifiedOperatorBuilder::TransitionElementsKind( 731 ElementsTransition transition) { 732 return new (zone()) Operator1<ElementsTransition>( // -- 733 IrOpcode::kTransitionElementsKind, // opcode 734 Operator::kNoDeopt | Operator::kNoThrow, // flags 735 "TransitionElementsKind", // name 736 3, 1, 1, 0, 1, 0, // counts 737 transition); // parameter 738 } 739 740 const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) { 741 switch (pretenure) { 742 case NOT_TENURED: 743 return &cache_.kAllocateNotTenuredOperator; 744 case TENURED: 745 return &cache_.kAllocateTenuredOperator; 746 } 747 UNREACHABLE(); 748 return nullptr; 749 } 750 751 752 const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) { 753 switch (access.external_array_type()) { 754 #define LOAD_BUFFER(Type, type, TYPE, ctype, size) \ 755 case kExternal##Type##Array: \ 756 return &cache_.kLoadBuffer##Type; 757 TYPED_ARRAYS(LOAD_BUFFER) 758 #undef LOAD_BUFFER 759 } 760 UNREACHABLE(); 761 return nullptr; 762 } 763 764 765 const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) { 766 switch (access.external_array_type()) { 767 #define STORE_BUFFER(Type, type, TYPE, ctype, size) \ 768 case kExternal##Type##Array: \ 769 return &cache_.kStoreBuffer##Type; 770 TYPED_ARRAYS(STORE_BUFFER) 771 #undef STORE_BUFFER 772 } 773 UNREACHABLE(); 774 return nullptr; 775 } 776 777 const Operator* SimplifiedOperatorBuilder::StringFromCodePoint( 778 UnicodeEncoding encoding) { 779 switch (encoding) { 780 case UnicodeEncoding::UTF16: 781 return &cache_.kStringFromCodePointOperatorUTF16; 782 case UnicodeEncoding::UTF32: 783 return &cache_.kStringFromCodePointOperatorUTF32; 784 } 785 UNREACHABLE(); 786 return nullptr; 787 } 788 789 #define SPECULATIVE_NUMBER_BINOP(Name) \ 790 const Operator* SimplifiedOperatorBuilder::Name(NumberOperationHint hint) { \ 791 switch (hint) { \ 792 case NumberOperationHint::kSignedSmall: \ 793 return &cache_.k##Name##SignedSmallOperator; \ 794 case NumberOperationHint::kSigned32: \ 795 return &cache_.k##Name##Signed32Operator; \ 796 case NumberOperationHint::kNumber: \ 797 return &cache_.k##Name##NumberOperator; \ 798 case NumberOperationHint::kNumberOrOddball: \ 799 return &cache_.k##Name##NumberOrOddballOperator; \ 800 } \ 801 UNREACHABLE(); \ 802 return nullptr; \ 803 } 804 SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP) 805 #undef SPECULATIVE_NUMBER_BINOP 806 807 #define ACCESS_OP_LIST(V) \ 808 V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \ 809 V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \ 810 V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \ 811 V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0) \ 812 V(LoadTypedElement, ExternalArrayType, Operator::kNoWrite, 4, 1, 1) \ 813 V(StoreTypedElement, ExternalArrayType, Operator::kNoRead, 5, 1, 0) 814 815 #define ACCESS(Name, Type, properties, value_input_count, control_input_count, \ 816 output_count) \ 817 const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \ 818 return new (zone()) \ 819 Operator1<Type>(IrOpcode::k##Name, \ 820 Operator::kNoDeopt | Operator::kNoThrow | properties, \ 821 #Name, value_input_count, 1, control_input_count, \ 822 output_count, 1, 0, access); \ 823 } 824 ACCESS_OP_LIST(ACCESS) 825 #undef ACCESS 826 827 } // namespace compiler 828 } // namespace internal 829 } // namespace v8 830