Home | History | Annotate | Download | only in compiler
      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