| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_ | 5 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_ |
| 6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_ | 6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_ |
| 7 | 7 |
| 8 #include <sstream> | 8 #include <sstream> |
| 9 | 9 |
| 10 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
| 11 #include "src/compiler/js-graph.h" | 11 #include "src/compiler/js-graph.h" |
| 12 #include "src/compiler/machine-operator.h" | 12 #include "src/compiler/machine-operator.h" |
| 13 #include "src/compiler/node-properties-inl.h" | 13 #include "src/compiler/node-properties-inl.h" |
| 14 #include "src/compiler/simplified-operator.h" | 14 #include "src/compiler/simplified-operator.h" |
| 15 | 15 |
| 16 namespace v8 { | 16 namespace v8 { |
| 17 namespace internal { | 17 namespace internal { |
| 18 namespace compiler { | 18 namespace compiler { |
| 19 | 19 |
| 20 // Contains logic related to changing the representation of values for constants | 20 // Contains logic related to changing the representation of values for constants |
| 21 // and other nodes, as well as lowering Simplified->Machine operators. | 21 // and other nodes, as well as lowering Simplified->Machine operators. |
| 22 // Eagerly folds any representation changes for constants. | 22 // Eagerly folds any representation changes for constants. |
| 23 class RepresentationChanger { | 23 class RepresentationChanger { |
| 24 public: | 24 public: |
| 25 RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified, | 25 RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified, |
| 26 Isolate* isolate) | 26 Isolate* isolate) |
| 27 : jsgraph_(jsgraph), | 27 : jsgraph_(jsgraph), |
| 28 simplified_(simplified), | 28 simplified_(simplified), |
| 29 isolate_(isolate), | 29 isolate_(isolate), |
| 30 bit_range_(Type::Range(isolate->factory()->NewNumber(0), | |
| 31 isolate->factory()->NewNumber(1), | |
| 32 jsgraph->zone())), | |
| 33 testing_type_errors_(false), | 30 testing_type_errors_(false), |
| 34 type_error_(false) {} | 31 type_error_(false) {} |
| 35 | 32 |
| 36 // TODO(titzer): should Word64 also be implicitly convertable to others? | 33 // TODO(titzer): should Word64 also be implicitly convertable to others? |
| 37 static const MachineTypeUnion rWord = kRepWord8 | kRepWord16 | kRepWord32; | 34 static const MachineTypeUnion rWord = kRepWord8 | kRepWord16 | kRepWord32; |
| 38 | 35 |
| 39 Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type, | 36 Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type, |
| 40 MachineTypeUnion use_type) { | 37 MachineTypeUnion use_type) { |
| 41 if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) { | 38 if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) { |
| 42 // There should be only one output representation. | 39 // There should be only one output representation. |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 return MakeInt32Constant(OpParameter<float>(node)); | 256 return MakeInt32Constant(OpParameter<float>(node)); |
| 260 case IrOpcode::kNumberConstant: | 257 case IrOpcode::kNumberConstant: |
| 261 case IrOpcode::kFloat64Constant: | 258 case IrOpcode::kFloat64Constant: |
| 262 return MakeInt32Constant(OpParameter<double>(node)); | 259 return MakeInt32Constant(OpParameter<double>(node)); |
| 263 default: | 260 default: |
| 264 break; | 261 break; |
| 265 } | 262 } |
| 266 // Select the correct X -> Word32 operator. | 263 // Select the correct X -> Word32 operator. |
| 267 const Operator* op; | 264 const Operator* op; |
| 268 if (output_type & kRepBit) { | 265 if (output_type & kRepBit) { |
| 269 return node; // No change necessary. | 266 return node; // Sloppy comparison -> word32 |
| 270 } else if (output_type & kRepFloat64) { | 267 } else if (output_type & kRepFloat64) { |
| 271 if (output_type & kTypeUint32 || use_unsigned) { | 268 if (output_type & kTypeUint32 || use_unsigned) { |
| 272 op = machine()->ChangeFloat64ToUint32(); | 269 op = machine()->ChangeFloat64ToUint32(); |
| 273 } else { | 270 } else { |
| 274 op = machine()->ChangeFloat64ToInt32(); | 271 op = machine()->ChangeFloat64ToInt32(); |
| 275 } | 272 } |
| 276 } else if (output_type & kRepFloat32) { | 273 } else if (output_type & kRepFloat32) { |
| 277 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 | 274 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 |
| 278 if (output_type & kTypeUint32 || use_unsigned) { | 275 if (output_type & kTypeUint32 || use_unsigned) { |
| 279 op = machine()->ChangeFloat64ToUint32(); | 276 op = machine()->ChangeFloat64ToUint32(); |
| 280 } else { | 277 } else { |
| 281 op = machine()->ChangeFloat64ToInt32(); | 278 op = machine()->ChangeFloat64ToInt32(); |
| 282 } | 279 } |
| 283 } else if (output_type & kRepTagged) { | 280 } else if (output_type & kRepTagged) { |
| 284 if (output_type & kTypeUint32 || use_unsigned) { | 281 if (output_type & kTypeUint32 || use_unsigned) { |
| 285 op = simplified()->ChangeTaggedToUint32(); | 282 op = simplified()->ChangeTaggedToUint32(); |
| 286 } else { | 283 } else { |
| 287 op = simplified()->ChangeTaggedToInt32(); | 284 op = simplified()->ChangeTaggedToInt32(); |
| 288 } | 285 } |
| 289 } else { | 286 } else { |
| 290 return TypeError(node, output_type, kRepWord32); | 287 return TypeError(node, output_type, kRepWord32); |
| 291 } | 288 } |
| 292 return jsgraph()->graph()->NewNode(op, node); | 289 return jsgraph()->graph()->NewNode(op, node); |
| 293 } | 290 } |
| 294 | 291 |
| 295 Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) { | 292 Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) { |
| 296 // Eagerly fold representation changes for constants. | 293 // Eagerly fold representation changes for constants. |
| 297 switch (node->opcode()) { | 294 switch (node->opcode()) { |
| 298 case IrOpcode::kInt32Constant: { | |
| 299 int32_t value = OpParameter<int32_t>(node); | |
| 300 if (value == 0 || value == 1) return node; | |
| 301 return jsgraph()->Int32Constant(1); // value != 0 | |
| 302 } | |
| 303 case IrOpcode::kNumberConstant: { | |
| 304 double value = OpParameter<double>(node); | |
| 305 if (value == 0 || std::isnan(value)) return jsgraph()->Int32Constant(0); | |
| 306 return jsgraph()->Int32Constant(1); // value != +0.0, -0.0, NaN | |
| 307 } | |
| 308 case IrOpcode::kHeapConstant: { | 295 case IrOpcode::kHeapConstant: { |
| 309 Handle<Object> object = OpParameter<Unique<Object>>(node).handle(); | 296 Handle<Object> value = OpParameter<Unique<Object> >(node).handle(); |
| 310 return jsgraph()->Int32Constant(object->BooleanValue() ? 1 : 0); | 297 DCHECK(value.is_identical_to(factory()->true_value()) || |
| 298 value.is_identical_to(factory()->false_value())); |
| 299 return jsgraph()->Int32Constant( |
| 300 value.is_identical_to(factory()->true_value()) ? 1 : 0); |
| 311 } | 301 } |
| 312 default: | 302 default: |
| 313 break; | 303 break; |
| 314 } | 304 } |
| 315 // Select the correct X -> Bit operator. | 305 // Select the correct X -> Bit operator. |
| 316 const Operator* op; | 306 const Operator* op; |
| 317 if (output_type & rWord) { | 307 if (output_type & kRepTagged) { |
| 318 op = simplified()->ChangeWord32ToBit(); | 308 op = simplified()->ChangeBoolToBit(); |
| 319 } else if (output_type & kRepWord64) { | |
| 320 op = simplified()->ChangeWord64ToBit(); | |
| 321 } else if (output_type & kRepTagged) { | |
| 322 Type* upper = NodeProperties::GetBounds(node).upper; | |
| 323 if (upper->Is(Type::Boolean())) { | |
| 324 op = simplified()->ChangeBoolToBit(); | |
| 325 } else if (upper->Is(Type::Signed32())) { | |
| 326 // Tagged -> Int32 -> Bit | |
| 327 node = InsertChangeTaggedToInt32(node); | |
| 328 op = simplified()->ChangeWord32ToBit(); | |
| 329 } else if (upper->Is(Type::Unsigned32())) { | |
| 330 // Tagged -> Uint32 -> Bit | |
| 331 node = InsertChangeTaggedToUint32(node); | |
| 332 op = simplified()->ChangeWord32ToBit(); | |
| 333 } else { | |
| 334 return TypeError(node, output_type, kRepBit); | |
| 335 } | |
| 336 } else { | 309 } else { |
| 337 return TypeError(node, output_type, kRepBit); | 310 return TypeError(node, output_type, kRepBit); |
| 338 } | 311 } |
| 339 return graph()->NewNode(op, node); | 312 return jsgraph()->graph()->NewNode(op, node); |
| 340 } | 313 } |
| 341 | 314 |
| 342 Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) { | 315 Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) { |
| 343 if (output_type & kRepBit) { | 316 if (output_type & kRepBit) { |
| 344 return node; // Sloppy comparison -> word64 | 317 return node; // Sloppy comparison -> word64 |
| 345 } | 318 } |
| 346 // Can't really convert Word64 to anything else. Purported to be internal. | 319 // Can't really convert Word64 to anything else. Purported to be internal. |
| 347 return TypeError(node, output_type, kRepWord64); | 320 return TypeError(node, output_type, kRepWord64); |
| 348 } | 321 } |
| 349 | 322 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 if (type->Is(Type::Unsigned32())) return kTypeUint32; | 407 if (type->Is(Type::Unsigned32())) return kTypeUint32; |
| 435 if (type->Is(Type::Number())) return kTypeNumber; | 408 if (type->Is(Type::Number())) return kTypeNumber; |
| 436 if (type->Is(Type::Boolean())) return kTypeBool; | 409 if (type->Is(Type::Boolean())) return kTypeBool; |
| 437 return kTypeAny; | 410 return kTypeAny; |
| 438 } | 411 } |
| 439 | 412 |
| 440 private: | 413 private: |
| 441 JSGraph* jsgraph_; | 414 JSGraph* jsgraph_; |
| 442 SimplifiedOperatorBuilder* simplified_; | 415 SimplifiedOperatorBuilder* simplified_; |
| 443 Isolate* isolate_; | 416 Isolate* isolate_; |
| 444 Type* bit_range_; | |
| 445 | 417 |
| 446 friend class RepresentationChangerTester; // accesses the below fields. | 418 friend class RepresentationChangerTester; // accesses the below fields. |
| 447 | 419 |
| 448 bool testing_type_errors_; // If {true}, don't abort on a type error. | 420 bool testing_type_errors_; // If {true}, don't abort on a type error. |
| 449 bool type_error_; // Set when a type error is detected. | 421 bool type_error_; // Set when a type error is detected. |
| 450 | 422 |
| 451 Node* TypeError(Node* node, MachineTypeUnion output_type, | 423 Node* TypeError(Node* node, MachineTypeUnion output_type, |
| 452 MachineTypeUnion use) { | 424 MachineTypeUnion use) { |
| 453 type_error_ = true; | 425 type_error_ = true; |
| 454 if (!testing_type_errors_) { | 426 if (!testing_type_errors_) { |
| 455 std::ostringstream out_str; | 427 std::ostringstream out_str; |
| 456 out_str << static_cast<MachineType>(output_type); | 428 out_str << static_cast<MachineType>(output_type); |
| 457 | 429 |
| 458 std::ostringstream use_str; | 430 std::ostringstream use_str; |
| 459 use_str << static_cast<MachineType>(use); | 431 use_str << static_cast<MachineType>(use); |
| 460 | 432 |
| 461 V8_Fatal(__FILE__, __LINE__, | 433 V8_Fatal(__FILE__, __LINE__, |
| 462 "RepresentationChangerError: node #%d:%s of " | 434 "RepresentationChangerError: node #%d:%s of " |
| 463 "%s cannot be changed to %s", | 435 "%s cannot be changed to %s", |
| 464 node->id(), node->op()->mnemonic(), out_str.str().c_str(), | 436 node->id(), node->op()->mnemonic(), out_str.str().c_str(), |
| 465 use_str.str().c_str()); | 437 use_str.str().c_str()); |
| 466 } | 438 } |
| 467 return node; | 439 return node; |
| 468 } | 440 } |
| 469 | 441 |
| 470 Node* InsertChangeFloat32ToFloat64(Node* node) { | 442 Node* InsertChangeFloat32ToFloat64(Node* node) { |
| 471 return graph()->NewNode(machine()->ChangeFloat32ToFloat64(), node); | 443 return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), |
| 444 node); |
| 472 } | 445 } |
| 473 | 446 |
| 474 Node* InsertChangeTaggedToFloat64(Node* node) { | 447 Node* InsertChangeTaggedToFloat64(Node* node) { |
| 475 return graph()->NewNode(simplified()->ChangeTaggedToFloat64(), node); | 448 return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(), |
| 449 node); |
| 476 } | 450 } |
| 477 | 451 |
| 478 Node* InsertChangeTaggedToInt32(Node* node) { | |
| 479 return graph()->NewNode(simplified()->ChangeTaggedToInt32(), node); | |
| 480 } | |
| 481 | |
| 482 Node* InsertChangeTaggedToUint32(Node* node) { | |
| 483 return graph()->NewNode(simplified()->ChangeTaggedToUint32(), node); | |
| 484 } | |
| 485 | |
| 486 Graph* graph() const { return jsgraph()->graph(); } | |
| 487 JSGraph* jsgraph() const { return jsgraph_; } | 452 JSGraph* jsgraph() const { return jsgraph_; } |
| 488 Isolate* isolate() const { return isolate_; } | 453 Isolate* isolate() const { return isolate_; } |
| 489 SimplifiedOperatorBuilder* simplified() const { return simplified_; } | 454 Factory* factory() const { return isolate()->factory(); } |
| 490 MachineOperatorBuilder* machine() const { return jsgraph()->machine(); } | 455 SimplifiedOperatorBuilder* simplified() { return simplified_; } |
| 456 MachineOperatorBuilder* machine() { return jsgraph()->machine(); } |
| 491 }; | 457 }; |
| 492 | 458 |
| 493 } // namespace compiler | 459 } // namespace compiler |
| 494 } // namespace internal | 460 } // namespace internal |
| 495 } // namespace v8 | 461 } // namespace v8 |
| 496 | 462 |
| 497 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ | 463 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ |
| OLD | NEW |