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/types-inl.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace compiler {
     15 
     16 std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
     17   switch (base_taggedness) {
     18     case kUntaggedBase:
     19       return os << "untagged base";
     20     case kTaggedBase:
     21       return os << "tagged base";
     22   }
     23   UNREACHABLE();
     24   return os;
     25 }
     26 
     27 
     28 MachineType BufferAccess::machine_type() const {
     29   switch (external_array_type_) {
     30     case kExternalUint8Array:
     31     case kExternalUint8ClampedArray:
     32       return MachineType::Uint8();
     33     case kExternalInt8Array:
     34       return MachineType::Int8();
     35     case kExternalUint16Array:
     36       return MachineType::Uint16();
     37     case kExternalInt16Array:
     38       return MachineType::Int16();
     39     case kExternalUint32Array:
     40       return MachineType::Uint32();
     41     case kExternalInt32Array:
     42       return MachineType::Int32();
     43     case kExternalFloat32Array:
     44       return MachineType::Float32();
     45     case kExternalFloat64Array:
     46       return MachineType::Float64();
     47   }
     48   UNREACHABLE();
     49   return MachineType::None();
     50 }
     51 
     52 
     53 bool operator==(BufferAccess lhs, BufferAccess rhs) {
     54   return lhs.external_array_type() == rhs.external_array_type();
     55 }
     56 
     57 
     58 bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }
     59 
     60 
     61 size_t hash_value(BufferAccess access) {
     62   return base::hash<ExternalArrayType>()(access.external_array_type());
     63 }
     64 
     65 
     66 std::ostream& operator<<(std::ostream& os, BufferAccess access) {
     67   switch (access.external_array_type()) {
     68 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
     69   case kExternal##Type##Array:                          \
     70     return os << #Type;
     71     TYPED_ARRAYS(TYPED_ARRAY_CASE)
     72 #undef TYPED_ARRAY_CASE
     73   }
     74   UNREACHABLE();
     75   return os;
     76 }
     77 
     78 
     79 BufferAccess const BufferAccessOf(const Operator* op) {
     80   DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
     81          op->opcode() == IrOpcode::kStoreBuffer);
     82   return OpParameter<BufferAccess>(op);
     83 }
     84 
     85 
     86 bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
     87   return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
     88          lhs.machine_type == rhs.machine_type;
     89 }
     90 
     91 
     92 bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
     93   return !(lhs == rhs);
     94 }
     95 
     96 
     97 size_t hash_value(FieldAccess const& access) {
     98   return base::hash_combine(access.base_is_tagged, access.offset,
     99                             access.machine_type);
    100 }
    101 
    102 
    103 std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
    104   os << "[" << access.base_is_tagged << ", " << access.offset << ", ";
    105 #ifdef OBJECT_PRINT
    106   Handle<Name> name;
    107   if (access.name.ToHandle(&name)) {
    108     name->Print(os);
    109     os << ", ";
    110   }
    111 #endif
    112   access.type->PrintTo(os);
    113   os << ", " << access.machine_type << "]";
    114   return os;
    115 }
    116 
    117 
    118 bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
    119   return lhs.base_is_tagged == rhs.base_is_tagged &&
    120          lhs.header_size == rhs.header_size &&
    121          lhs.machine_type == rhs.machine_type;
    122 }
    123 
    124 
    125 bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
    126   return !(lhs == rhs);
    127 }
    128 
    129 
    130 size_t hash_value(ElementAccess const& access) {
    131   return base::hash_combine(access.base_is_tagged, access.header_size,
    132                             access.machine_type);
    133 }
    134 
    135 
    136 std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
    137   os << access.base_is_tagged << ", " << access.header_size << ", ";
    138   access.type->PrintTo(os);
    139   os << ", " << access.machine_type;
    140   return os;
    141 }
    142 
    143 
    144 const FieldAccess& FieldAccessOf(const Operator* op) {
    145   DCHECK_NOT_NULL(op);
    146   DCHECK(op->opcode() == IrOpcode::kLoadField ||
    147          op->opcode() == IrOpcode::kStoreField);
    148   return OpParameter<FieldAccess>(op);
    149 }
    150 
    151 
    152 const ElementAccess& ElementAccessOf(const Operator* op) {
    153   DCHECK_NOT_NULL(op);
    154   DCHECK(op->opcode() == IrOpcode::kLoadElement ||
    155          op->opcode() == IrOpcode::kStoreElement);
    156   return OpParameter<ElementAccess>(op);
    157 }
    158 
    159 
    160 #define PURE_OP_LIST(V)                                  \
    161   V(BooleanNot, Operator::kNoProperties, 1)              \
    162   V(BooleanToNumber, Operator::kNoProperties, 1)         \
    163   V(NumberEqual, Operator::kCommutative, 2)              \
    164   V(NumberLessThan, Operator::kNoProperties, 2)          \
    165   V(NumberLessThanOrEqual, Operator::kNoProperties, 2)   \
    166   V(NumberAdd, Operator::kCommutative, 2)                \
    167   V(NumberSubtract, Operator::kNoProperties, 2)          \
    168   V(NumberMultiply, Operator::kCommutative, 2)           \
    169   V(NumberDivide, Operator::kNoProperties, 2)            \
    170   V(NumberModulus, Operator::kNoProperties, 2)           \
    171   V(NumberBitwiseOr, Operator::kCommutative, 2)          \
    172   V(NumberBitwiseXor, Operator::kCommutative, 2)         \
    173   V(NumberBitwiseAnd, Operator::kCommutative, 2)         \
    174   V(NumberShiftLeft, Operator::kNoProperties, 2)         \
    175   V(NumberShiftRight, Operator::kNoProperties, 2)        \
    176   V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
    177   V(NumberToInt32, Operator::kNoProperties, 1)           \
    178   V(NumberToUint32, Operator::kNoProperties, 1)          \
    179   V(NumberIsHoleNaN, Operator::kNoProperties, 1)         \
    180   V(PlainPrimitiveToNumber, Operator::kNoProperties, 1)  \
    181   V(ChangeTaggedToInt32, Operator::kNoProperties, 1)     \
    182   V(ChangeTaggedToUint32, Operator::kNoProperties, 1)    \
    183   V(ChangeTaggedToFloat64, Operator::kNoProperties, 1)   \
    184   V(ChangeInt32ToTagged, Operator::kNoProperties, 1)     \
    185   V(ChangeUint32ToTagged, Operator::kNoProperties, 1)    \
    186   V(ChangeFloat64ToTagged, Operator::kNoProperties, 1)   \
    187   V(ChangeBoolToBit, Operator::kNoProperties, 1)         \
    188   V(ChangeBitToBool, Operator::kNoProperties, 1)         \
    189   V(ObjectIsNumber, Operator::kNoProperties, 1)          \
    190   V(ObjectIsSmi, Operator::kNoProperties, 1)
    191 
    192 #define NO_THROW_OP_LIST(V)                 \
    193   V(StringEqual, Operator::kCommutative, 2) \
    194   V(StringLessThan, Operator::kNoThrow, 2)  \
    195   V(StringLessThanOrEqual, Operator::kNoThrow, 2)
    196 
    197 struct SimplifiedOperatorGlobalCache final {
    198 #define PURE(Name, properties, input_count)                                \
    199   struct Name##Operator final : public Operator {                          \
    200     Name##Operator()                                                       \
    201         : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \
    202                    input_count, 0, 0, 1, 0, 0) {}                          \
    203   };                                                                       \
    204   Name##Operator k##Name;
    205   PURE_OP_LIST(PURE)
    206 #undef PURE
    207 
    208 #define NO_THROW(Name, properties, input_count)                               \
    209   struct Name##Operator final : public Operator {                             \
    210     Name##Operator()                                                          \
    211         : Operator(IrOpcode::k##Name, Operator::kNoThrow | properties, #Name, \
    212                    input_count, 1, 1, 1, 1, 0) {}                             \
    213   };                                                                          \
    214   Name##Operator k##Name;
    215   NO_THROW_OP_LIST(NO_THROW)
    216 #undef NO_THROW
    217 
    218 #define BUFFER_ACCESS(Type, type, TYPE, ctype, size)                          \
    219   struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> {  \
    220     LoadBuffer##Type##Operator()                                              \
    221         : Operator1<BufferAccess>(IrOpcode::kLoadBuffer,                      \
    222                                   Operator::kNoThrow | Operator::kNoWrite,    \
    223                                   "LoadBuffer", 3, 1, 1, 1, 1, 0,             \
    224                                   BufferAccess(kExternal##Type##Array)) {}    \
    225   };                                                                          \
    226   struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \
    227     StoreBuffer##Type##Operator()                                             \
    228         : Operator1<BufferAccess>(IrOpcode::kStoreBuffer,                     \
    229                                   Operator::kNoRead | Operator::kNoThrow,     \
    230                                   "StoreBuffer", 4, 1, 1, 0, 1, 0,            \
    231                                   BufferAccess(kExternal##Type##Array)) {}    \
    232   };                                                                          \
    233   LoadBuffer##Type##Operator kLoadBuffer##Type;                               \
    234   StoreBuffer##Type##Operator kStoreBuffer##Type;
    235   TYPED_ARRAYS(BUFFER_ACCESS)
    236 #undef BUFFER_ACCESS
    237 };
    238 
    239 
    240 static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
    241     LAZY_INSTANCE_INITIALIZER;
    242 
    243 
    244 SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
    245     : cache_(kCache.Get()), zone_(zone) {}
    246 
    247 
    248 #define GET_FROM_CACHE(Name, properties, input_count) \
    249   const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
    250 PURE_OP_LIST(GET_FROM_CACHE)
    251 NO_THROW_OP_LIST(GET_FROM_CACHE)
    252 #undef GET_FROM_CACHE
    253 
    254 
    255 const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
    256   // TODO(titzer): What about the type parameter?
    257   return new (zone()) Operator(IrOpcode::kReferenceEqual,
    258                                Operator::kCommutative | Operator::kPure,
    259                                "ReferenceEqual", 2, 0, 0, 1, 0, 0);
    260 }
    261 
    262 
    263 const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) {
    264   return new (zone())
    265       Operator1<PretenureFlag>(IrOpcode::kAllocate, Operator::kNoThrow,
    266                                "Allocate", 1, 1, 1, 1, 1, 0, pretenure);
    267 }
    268 
    269 
    270 const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) {
    271   switch (access.external_array_type()) {
    272 #define LOAD_BUFFER(Type, type, TYPE, ctype, size) \
    273   case kExternal##Type##Array:                     \
    274     return &cache_.kLoadBuffer##Type;
    275     TYPED_ARRAYS(LOAD_BUFFER)
    276 #undef LOAD_BUFFER
    277   }
    278   UNREACHABLE();
    279   return nullptr;
    280 }
    281 
    282 
    283 const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
    284   switch (access.external_array_type()) {
    285 #define STORE_BUFFER(Type, type, TYPE, ctype, size) \
    286   case kExternal##Type##Array:                      \
    287     return &cache_.kStoreBuffer##Type;
    288     TYPED_ARRAYS(STORE_BUFFER)
    289 #undef STORE_BUFFER
    290   }
    291   UNREACHABLE();
    292   return nullptr;
    293 }
    294 
    295 
    296 #define ACCESS_OP_LIST(V)                                    \
    297   V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1)     \
    298   V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0)     \
    299   V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
    300   V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0)
    301 
    302 
    303 #define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
    304                output_count)                                                   \
    305   const Operator* SimplifiedOperatorBuilder::Name(const Type& access) {        \
    306     return new (zone())                                                        \
    307         Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties,    \
    308                         #Name, value_input_count, 1, control_input_count,      \
    309                         output_count, 1, 0, access);                           \
    310   }
    311 ACCESS_OP_LIST(ACCESS)
    312 #undef ACCESS
    313 
    314 }  // namespace compiler
    315 }  // namespace internal
    316 }  // namespace v8
    317