1 // Copyright 2014 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/machine-operator.h" 6 7 #include "src/base/lazy-instance.h" 8 #include "src/compiler/opcodes.h" 9 #include "src/compiler/operator.h" 10 11 namespace v8 { 12 namespace internal { 13 namespace compiler { 14 15 std::ostream& operator<<(std::ostream& os, TruncationMode mode) { 16 switch (mode) { 17 case TruncationMode::kJavaScript: 18 return os << "JavaScript"; 19 case TruncationMode::kRoundToZero: 20 return os << "RoundToZero"; 21 } 22 UNREACHABLE(); 23 return os; 24 } 25 26 27 TruncationMode TruncationModeOf(Operator const* op) { 28 DCHECK_EQ(IrOpcode::kTruncateFloat64ToInt32, op->opcode()); 29 return OpParameter<TruncationMode>(op); 30 } 31 32 33 std::ostream& operator<<(std::ostream& os, WriteBarrierKind kind) { 34 switch (kind) { 35 case kNoWriteBarrier: 36 return os << "NoWriteBarrier"; 37 case kMapWriteBarrier: 38 return os << "MapWriteBarrier"; 39 case kPointerWriteBarrier: 40 return os << "PointerWriteBarrier"; 41 case kFullWriteBarrier: 42 return os << "FullWriteBarrier"; 43 } 44 UNREACHABLE(); 45 return os; 46 } 47 48 49 bool operator==(StoreRepresentation lhs, StoreRepresentation rhs) { 50 return lhs.representation() == rhs.representation() && 51 lhs.write_barrier_kind() == rhs.write_barrier_kind(); 52 } 53 54 55 bool operator!=(StoreRepresentation lhs, StoreRepresentation rhs) { 56 return !(lhs == rhs); 57 } 58 59 60 size_t hash_value(StoreRepresentation rep) { 61 return base::hash_combine(rep.representation(), rep.write_barrier_kind()); 62 } 63 64 65 std::ostream& operator<<(std::ostream& os, StoreRepresentation rep) { 66 return os << "(" << rep.representation() << " : " << rep.write_barrier_kind() 67 << ")"; 68 } 69 70 71 LoadRepresentation LoadRepresentationOf(Operator const* op) { 72 DCHECK_EQ(IrOpcode::kLoad, op->opcode()); 73 return OpParameter<LoadRepresentation>(op); 74 } 75 76 77 StoreRepresentation const& StoreRepresentationOf(Operator const* op) { 78 DCHECK_EQ(IrOpcode::kStore, op->opcode()); 79 return OpParameter<StoreRepresentation>(op); 80 } 81 82 83 CheckedLoadRepresentation CheckedLoadRepresentationOf(Operator const* op) { 84 DCHECK_EQ(IrOpcode::kCheckedLoad, op->opcode()); 85 return OpParameter<CheckedLoadRepresentation>(op); 86 } 87 88 89 CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) { 90 DCHECK_EQ(IrOpcode::kCheckedStore, op->opcode()); 91 return OpParameter<CheckedStoreRepresentation>(op); 92 } 93 94 95 #define PURE_OP_LIST(V) \ 96 V(Word32And, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 97 V(Word32Or, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 98 V(Word32Xor, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 99 V(Word32Shl, Operator::kNoProperties, 2, 0, 1) \ 100 V(Word32Shr, Operator::kNoProperties, 2, 0, 1) \ 101 V(Word32Sar, Operator::kNoProperties, 2, 0, 1) \ 102 V(Word32Ror, Operator::kNoProperties, 2, 0, 1) \ 103 V(Word32Equal, Operator::kCommutative, 2, 0, 1) \ 104 V(Word32Clz, Operator::kNoProperties, 1, 0, 1) \ 105 V(Word64And, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 106 V(Word64Or, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 107 V(Word64Xor, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 108 V(Word64Shl, Operator::kNoProperties, 2, 0, 1) \ 109 V(Word64Shr, Operator::kNoProperties, 2, 0, 1) \ 110 V(Word64Sar, Operator::kNoProperties, 2, 0, 1) \ 111 V(Word64Ror, Operator::kNoProperties, 2, 0, 1) \ 112 V(Word64Clz, Operator::kNoProperties, 1, 0, 1) \ 113 V(Word64Equal, Operator::kCommutative, 2, 0, 1) \ 114 V(Int32Add, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 115 V(Int32AddWithOverflow, Operator::kAssociative | Operator::kCommutative, 2, \ 116 0, 2) \ 117 V(Int32Sub, Operator::kNoProperties, 2, 0, 1) \ 118 V(Int32SubWithOverflow, Operator::kNoProperties, 2, 0, 2) \ 119 V(Int32Mul, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 120 V(Int32MulHigh, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 121 V(Int32Div, Operator::kNoProperties, 2, 1, 1) \ 122 V(Int32Mod, Operator::kNoProperties, 2, 1, 1) \ 123 V(Int32LessThan, Operator::kNoProperties, 2, 0, 1) \ 124 V(Int32LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \ 125 V(Uint32Div, Operator::kNoProperties, 2, 1, 1) \ 126 V(Uint32LessThan, Operator::kNoProperties, 2, 0, 1) \ 127 V(Uint32LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \ 128 V(Uint32Mod, Operator::kNoProperties, 2, 1, 1) \ 129 V(Uint32MulHigh, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 130 V(Int64Add, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 131 V(Int64AddWithOverflow, Operator::kAssociative | Operator::kCommutative, 2, \ 132 0, 2) \ 133 V(Int64Sub, Operator::kNoProperties, 2, 0, 1) \ 134 V(Int64SubWithOverflow, Operator::kNoProperties, 2, 0, 2) \ 135 V(Int64Mul, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ 136 V(Int64Div, Operator::kNoProperties, 2, 1, 1) \ 137 V(Int64Mod, Operator::kNoProperties, 2, 1, 1) \ 138 V(Int64LessThan, Operator::kNoProperties, 2, 0, 1) \ 139 V(Int64LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \ 140 V(Uint64Div, Operator::kNoProperties, 2, 1, 1) \ 141 V(Uint64Mod, Operator::kNoProperties, 2, 1, 1) \ 142 V(Uint64LessThan, Operator::kNoProperties, 2, 0, 1) \ 143 V(Uint64LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \ 144 V(ChangeFloat32ToFloat64, Operator::kNoProperties, 1, 0, 1) \ 145 V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 0, 1) \ 146 V(ChangeFloat64ToUint32, Operator::kNoProperties, 1, 0, 1) \ 147 V(TryTruncateFloat32ToInt64, Operator::kNoProperties, 1, 0, 2) \ 148 V(TryTruncateFloat64ToInt64, Operator::kNoProperties, 1, 0, 2) \ 149 V(TryTruncateFloat32ToUint64, Operator::kNoProperties, 1, 0, 2) \ 150 V(TryTruncateFloat64ToUint64, Operator::kNoProperties, 1, 0, 2) \ 151 V(ChangeInt32ToFloat64, Operator::kNoProperties, 1, 0, 1) \ 152 V(RoundInt64ToFloat32, Operator::kNoProperties, 1, 0, 1) \ 153 V(RoundInt64ToFloat64, Operator::kNoProperties, 1, 0, 1) \ 154 V(RoundUint64ToFloat32, Operator::kNoProperties, 1, 0, 1) \ 155 V(RoundUint64ToFloat64, Operator::kNoProperties, 1, 0, 1) \ 156 V(ChangeInt32ToInt64, Operator::kNoProperties, 1, 0, 1) \ 157 V(ChangeUint32ToFloat64, Operator::kNoProperties, 1, 0, 1) \ 158 V(ChangeUint32ToUint64, Operator::kNoProperties, 1, 0, 1) \ 159 V(TruncateFloat64ToFloat32, Operator::kNoProperties, 1, 0, 1) \ 160 V(TruncateInt64ToInt32, Operator::kNoProperties, 1, 0, 1) \ 161 V(BitcastFloat32ToInt32, Operator::kNoProperties, 1, 0, 1) \ 162 V(BitcastFloat64ToInt64, Operator::kNoProperties, 1, 0, 1) \ 163 V(BitcastInt32ToFloat32, Operator::kNoProperties, 1, 0, 1) \ 164 V(BitcastInt64ToFloat64, Operator::kNoProperties, 1, 0, 1) \ 165 V(Float32Abs, Operator::kNoProperties, 1, 0, 1) \ 166 V(Float32Add, Operator::kCommutative, 2, 0, 1) \ 167 V(Float32Sub, Operator::kNoProperties, 2, 0, 1) \ 168 V(Float32Mul, Operator::kCommutative, 2, 0, 1) \ 169 V(Float32Div, Operator::kNoProperties, 2, 0, 1) \ 170 V(Float32Sqrt, Operator::kNoProperties, 1, 0, 1) \ 171 V(Float64Abs, Operator::kNoProperties, 1, 0, 1) \ 172 V(Float64Add, Operator::kCommutative, 2, 0, 1) \ 173 V(Float64Sub, Operator::kNoProperties, 2, 0, 1) \ 174 V(Float64Mul, Operator::kCommutative, 2, 0, 1) \ 175 V(Float64Div, Operator::kNoProperties, 2, 0, 1) \ 176 V(Float64Mod, Operator::kNoProperties, 2, 0, 1) \ 177 V(Float64Sqrt, Operator::kNoProperties, 1, 0, 1) \ 178 V(Float32Equal, Operator::kCommutative, 2, 0, 1) \ 179 V(Float32LessThan, Operator::kNoProperties, 2, 0, 1) \ 180 V(Float32LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \ 181 V(Float64Equal, Operator::kCommutative, 2, 0, 1) \ 182 V(Float64LessThan, Operator::kNoProperties, 2, 0, 1) \ 183 V(Float64LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \ 184 V(Float64ExtractLowWord32, Operator::kNoProperties, 1, 0, 1) \ 185 V(Float64ExtractHighWord32, Operator::kNoProperties, 1, 0, 1) \ 186 V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1) \ 187 V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1) \ 188 V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) \ 189 V(LoadFramePointer, Operator::kNoProperties, 0, 0, 1) 190 191 #define PURE_OPTIONAL_OP_LIST(V) \ 192 V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \ 193 V(Word64Ctz, Operator::kNoProperties, 1, 0, 1) \ 194 V(Word32Popcnt, Operator::kNoProperties, 1, 0, 1) \ 195 V(Word64Popcnt, Operator::kNoProperties, 1, 0, 1) \ 196 V(Float32Max, Operator::kNoProperties, 2, 0, 1) \ 197 V(Float32Min, Operator::kNoProperties, 2, 0, 1) \ 198 V(Float64Max, Operator::kNoProperties, 2, 0, 1) \ 199 V(Float64Min, Operator::kNoProperties, 2, 0, 1) \ 200 V(Float32RoundDown, Operator::kNoProperties, 1, 0, 1) \ 201 V(Float64RoundDown, Operator::kNoProperties, 1, 0, 1) \ 202 V(Float32RoundUp, Operator::kNoProperties, 1, 0, 1) \ 203 V(Float64RoundUp, Operator::kNoProperties, 1, 0, 1) \ 204 V(Float32RoundTruncate, Operator::kNoProperties, 1, 0, 1) \ 205 V(Float64RoundTruncate, Operator::kNoProperties, 1, 0, 1) \ 206 V(Float64RoundTiesAway, Operator::kNoProperties, 1, 0, 1) \ 207 V(Float32RoundTiesEven, Operator::kNoProperties, 1, 0, 1) \ 208 V(Float64RoundTiesEven, Operator::kNoProperties, 1, 0, 1) 209 210 211 #define MACHINE_TYPE_LIST(V) \ 212 V(Float32) \ 213 V(Float64) \ 214 V(Int8) \ 215 V(Uint8) \ 216 V(Int16) \ 217 V(Uint16) \ 218 V(Int32) \ 219 V(Uint32) \ 220 V(Int64) \ 221 V(Uint64) \ 222 V(Pointer) \ 223 V(AnyTagged) 224 225 226 #define MACHINE_REPRESENTATION_LIST(V) \ 227 V(kFloat32) \ 228 V(kFloat64) \ 229 V(kWord8) \ 230 V(kWord16) \ 231 V(kWord32) \ 232 V(kWord64) \ 233 V(kTagged) 234 235 236 struct MachineOperatorGlobalCache { 237 #define PURE(Name, properties, value_input_count, control_input_count, \ 238 output_count) \ 239 struct Name##Operator final : public Operator { \ 240 Name##Operator() \ 241 : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \ 242 value_input_count, 0, control_input_count, output_count, 0, \ 243 0) {} \ 244 }; \ 245 Name##Operator k##Name; 246 PURE_OP_LIST(PURE) 247 PURE_OPTIONAL_OP_LIST(PURE) 248 #undef PURE 249 250 template <TruncationMode kMode> 251 struct TruncateFloat64ToInt32Operator final 252 : public Operator1<TruncationMode> { 253 TruncateFloat64ToInt32Operator() 254 : Operator1<TruncationMode>(IrOpcode::kTruncateFloat64ToInt32, 255 Operator::kPure, "TruncateFloat64ToInt32", 256 1, 0, 0, 1, 0, 0, kMode) {} 257 }; 258 TruncateFloat64ToInt32Operator<TruncationMode::kJavaScript> 259 kTruncateFloat64ToInt32JavaScript; 260 TruncateFloat64ToInt32Operator<TruncationMode::kRoundToZero> 261 kTruncateFloat64ToInt32RoundToZero; 262 263 #define LOAD(Type) \ 264 struct Load##Type##Operator final : public Operator1<LoadRepresentation> { \ 265 Load##Type##Operator() \ 266 : Operator1<LoadRepresentation>( \ 267 IrOpcode::kLoad, Operator::kNoThrow | Operator::kNoWrite, \ 268 "Load", 2, 1, 1, 1, 1, 0, MachineType::Type()) {} \ 269 }; \ 270 struct CheckedLoad##Type##Operator final \ 271 : public Operator1<CheckedLoadRepresentation> { \ 272 CheckedLoad##Type##Operator() \ 273 : Operator1<CheckedLoadRepresentation>( \ 274 IrOpcode::kCheckedLoad, Operator::kNoThrow | Operator::kNoWrite, \ 275 "CheckedLoad", 3, 1, 1, 1, 1, 0, MachineType::Type()) {} \ 276 }; \ 277 Load##Type##Operator kLoad##Type; \ 278 CheckedLoad##Type##Operator kCheckedLoad##Type; 279 MACHINE_TYPE_LIST(LOAD) 280 #undef LOAD 281 282 #define STORE(Type) \ 283 struct Store##Type##Operator : public Operator1<StoreRepresentation> { \ 284 explicit Store##Type##Operator(WriteBarrierKind write_barrier_kind) \ 285 : Operator1<StoreRepresentation>( \ 286 IrOpcode::kStore, Operator::kNoRead | Operator::kNoThrow, \ 287 "Store", 3, 1, 1, 0, 1, 0, \ 288 StoreRepresentation(MachineRepresentation::Type, \ 289 write_barrier_kind)) {} \ 290 }; \ 291 struct Store##Type##NoWriteBarrier##Operator final \ 292 : public Store##Type##Operator { \ 293 Store##Type##NoWriteBarrier##Operator() \ 294 : Store##Type##Operator(kNoWriteBarrier) {} \ 295 }; \ 296 struct Store##Type##MapWriteBarrier##Operator final \ 297 : public Store##Type##Operator { \ 298 Store##Type##MapWriteBarrier##Operator() \ 299 : Store##Type##Operator(kMapWriteBarrier) {} \ 300 }; \ 301 struct Store##Type##PointerWriteBarrier##Operator final \ 302 : public Store##Type##Operator { \ 303 Store##Type##PointerWriteBarrier##Operator() \ 304 : Store##Type##Operator(kPointerWriteBarrier) {} \ 305 }; \ 306 struct Store##Type##FullWriteBarrier##Operator final \ 307 : public Store##Type##Operator { \ 308 Store##Type##FullWriteBarrier##Operator() \ 309 : Store##Type##Operator(kFullWriteBarrier) {} \ 310 }; \ 311 struct CheckedStore##Type##Operator final \ 312 : public Operator1<CheckedStoreRepresentation> { \ 313 CheckedStore##Type##Operator() \ 314 : Operator1<CheckedStoreRepresentation>( \ 315 IrOpcode::kCheckedStore, Operator::kNoRead | Operator::kNoThrow, \ 316 "CheckedStore", 4, 1, 1, 0, 1, 0, MachineRepresentation::Type) { \ 317 } \ 318 }; \ 319 Store##Type##NoWriteBarrier##Operator kStore##Type##NoWriteBarrier; \ 320 Store##Type##MapWriteBarrier##Operator kStore##Type##MapWriteBarrier; \ 321 Store##Type##PointerWriteBarrier##Operator \ 322 kStore##Type##PointerWriteBarrier; \ 323 Store##Type##FullWriteBarrier##Operator kStore##Type##FullWriteBarrier; \ 324 CheckedStore##Type##Operator kCheckedStore##Type; 325 MACHINE_REPRESENTATION_LIST(STORE) 326 #undef STORE 327 }; 328 329 330 static base::LazyInstance<MachineOperatorGlobalCache>::type kCache = 331 LAZY_INSTANCE_INITIALIZER; 332 333 334 MachineOperatorBuilder::MachineOperatorBuilder(Zone* zone, 335 MachineRepresentation word, 336 Flags flags) 337 : cache_(kCache.Get()), word_(word), flags_(flags) { 338 DCHECK(word == MachineRepresentation::kWord32 || 339 word == MachineRepresentation::kWord64); 340 } 341 342 343 #define PURE(Name, properties, value_input_count, control_input_count, \ 344 output_count) \ 345 const Operator* MachineOperatorBuilder::Name() { return &cache_.k##Name; } 346 PURE_OP_LIST(PURE) 347 #undef PURE 348 349 #define PURE(Name, properties, value_input_count, control_input_count, \ 350 output_count) \ 351 const OptionalOperator MachineOperatorBuilder::Name() { \ 352 return OptionalOperator(flags_ & k##Name ? &cache_.k##Name : nullptr); \ 353 } 354 PURE_OPTIONAL_OP_LIST(PURE) 355 #undef PURE 356 357 358 const Operator* MachineOperatorBuilder::TruncateFloat64ToInt32( 359 TruncationMode mode) { 360 switch (mode) { 361 case TruncationMode::kJavaScript: 362 return &cache_.kTruncateFloat64ToInt32JavaScript; 363 case TruncationMode::kRoundToZero: 364 return &cache_.kTruncateFloat64ToInt32RoundToZero; 365 } 366 UNREACHABLE(); 367 return nullptr; 368 } 369 370 371 const Operator* MachineOperatorBuilder::Load(LoadRepresentation rep) { 372 #define LOAD(Type) \ 373 if (rep == MachineType::Type()) { \ 374 return &cache_.kLoad##Type; \ 375 } 376 MACHINE_TYPE_LIST(LOAD) 377 #undef LOAD 378 UNREACHABLE(); 379 return nullptr; 380 } 381 382 383 const Operator* MachineOperatorBuilder::Store(StoreRepresentation store_rep) { 384 switch (store_rep.representation()) { 385 #define STORE(kRep) \ 386 case MachineRepresentation::kRep: \ 387 switch (store_rep.write_barrier_kind()) { \ 388 case kNoWriteBarrier: \ 389 return &cache_.k##Store##kRep##NoWriteBarrier; \ 390 case kMapWriteBarrier: \ 391 return &cache_.k##Store##kRep##MapWriteBarrier; \ 392 case kPointerWriteBarrier: \ 393 return &cache_.k##Store##kRep##PointerWriteBarrier; \ 394 case kFullWriteBarrier: \ 395 return &cache_.k##Store##kRep##FullWriteBarrier; \ 396 } \ 397 break; 398 MACHINE_REPRESENTATION_LIST(STORE) 399 #undef STORE 400 case MachineRepresentation::kBit: 401 case MachineRepresentation::kNone: 402 break; 403 } 404 UNREACHABLE(); 405 return nullptr; 406 } 407 408 409 const Operator* MachineOperatorBuilder::CheckedLoad( 410 CheckedLoadRepresentation rep) { 411 #define LOAD(Type) \ 412 if (rep == MachineType::Type()) { \ 413 return &cache_.kCheckedLoad##Type; \ 414 } 415 MACHINE_TYPE_LIST(LOAD) 416 #undef LOAD 417 UNREACHABLE(); 418 return nullptr; 419 } 420 421 422 const Operator* MachineOperatorBuilder::CheckedStore( 423 CheckedStoreRepresentation rep) { 424 switch (rep) { 425 #define STORE(kRep) \ 426 case MachineRepresentation::kRep: \ 427 return &cache_.kCheckedStore##kRep; 428 MACHINE_REPRESENTATION_LIST(STORE) 429 #undef STORE 430 case MachineRepresentation::kBit: 431 case MachineRepresentation::kNone: 432 break; 433 } 434 UNREACHABLE(); 435 return nullptr; 436 } 437 438 } // namespace compiler 439 } // namespace internal 440 } // namespace v8 441