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