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