Chromium Code Reviews| 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())), | |
| 30 testing_type_errors_(false), | 33 testing_type_errors_(false), |
| 31 type_error_(false) {} | 34 type_error_(false) {} |
| 32 | 35 |
| 33 // TODO(titzer): should Word64 also be implicitly convertable to others? | 36 // TODO(titzer): should Word64 also be implicitly convertable to others? |
| 34 static const MachineTypeUnion rWord = | 37 static const MachineTypeUnion rWord = kRepWord8 | kRepWord16 | kRepWord32; |
| 35 kRepBit | kRepWord8 | kRepWord16 | kRepWord32; | |
| 36 | 38 |
| 37 Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type, | 39 Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type, |
| 38 MachineTypeUnion use_type) { | 40 MachineTypeUnion use_type) { |
| 39 if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) { | 41 if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) { |
| 40 // There should be only one output representation. | 42 // There should be only one output representation. |
| 41 return TypeError(node, output_type, use_type); | 43 return TypeError(node, output_type, use_type); |
| 42 } | 44 } |
| 43 if ((use_type & kRepMask) == (output_type & kRepMask)) { | 45 if ((use_type & kRepMask) == (output_type & kRepMask)) { |
| 44 // Representations are the same. That's a no-op. | 46 // Representations are the same. That's a no-op. |
| 45 return node; | 47 return node; |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 255 return node; // No change necessary. | 257 return node; // No change necessary. |
| 256 case IrOpcode::kFloat32Constant: | 258 case IrOpcode::kFloat32Constant: |
| 257 return MakeInt32Constant(OpParameter<float>(node)); | 259 return MakeInt32Constant(OpParameter<float>(node)); |
| 258 case IrOpcode::kNumberConstant: | 260 case IrOpcode::kNumberConstant: |
| 259 case IrOpcode::kFloat64Constant: | 261 case IrOpcode::kFloat64Constant: |
| 260 return MakeInt32Constant(OpParameter<double>(node)); | 262 return MakeInt32Constant(OpParameter<double>(node)); |
| 261 default: | 263 default: |
| 262 break; | 264 break; |
| 263 } | 265 } |
| 264 // Select the correct X -> Word32 operator. | 266 // Select the correct X -> Word32 operator. |
| 265 const Operator* op = NULL; | 267 const Operator* op; |
| 266 if (output_type & kRepFloat64) { | 268 if (output_type & kRepBit) { |
| 269 return node; // No change necessary. | |
| 270 } else if (output_type & kRepFloat64) { | |
| 267 if (output_type & kTypeUint32 || use_unsigned) { | 271 if (output_type & kTypeUint32 || use_unsigned) { |
| 268 op = machine()->ChangeFloat64ToUint32(); | 272 op = machine()->ChangeFloat64ToUint32(); |
| 269 } else { | 273 } else { |
| 270 op = machine()->ChangeFloat64ToInt32(); | 274 op = machine()->ChangeFloat64ToInt32(); |
| 271 } | 275 } |
| 272 } else if (output_type & kRepFloat32) { | 276 } else if (output_type & kRepFloat32) { |
| 273 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 | 277 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 |
| 274 if (output_type & kTypeUint32 || use_unsigned) { | 278 if (output_type & kTypeUint32 || use_unsigned) { |
| 275 op = machine()->ChangeFloat64ToUint32(); | 279 op = machine()->ChangeFloat64ToUint32(); |
| 276 } else { | 280 } else { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 291 Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) { | 295 Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) { |
| 292 // Eagerly fold representation changes for constants. | 296 // Eagerly fold representation changes for constants. |
| 293 switch (node->opcode()) { | 297 switch (node->opcode()) { |
| 294 case IrOpcode::kInt32Constant: { | 298 case IrOpcode::kInt32Constant: { |
| 295 int32_t value = OpParameter<int32_t>(node); | 299 int32_t value = OpParameter<int32_t>(node); |
| 296 if (value == 0 || value == 1) return node; | 300 if (value == 0 || value == 1) return node; |
| 297 return jsgraph()->Int32Constant(1); // value != 0 | 301 return jsgraph()->Int32Constant(1); // value != 0 |
| 298 } | 302 } |
| 299 case IrOpcode::kNumberConstant: { | 303 case IrOpcode::kNumberConstant: { |
| 300 double value = OpParameter<double>(node); | 304 double value = OpParameter<double>(node); |
| 301 if (std::isnan(value) || value == 0.0) { | 305 if (value == 0.0 || value != value) return jsgraph()->Int32Constant(0); |
|
Jarin
2015/01/08 09:18:13
Just for my education: why is value != value bette
Benedikt Meurer
2015/01/08 09:20:01
It's not...
| |
| 302 return jsgraph()->Int32Constant(0); | 306 return jsgraph()->Int32Constant(1); // value != +0.0, -0.0, NaN |
| 303 } | |
| 304 return jsgraph()->Int32Constant(1); | |
| 305 } | 307 } |
| 306 case IrOpcode::kHeapConstant: { | 308 case IrOpcode::kHeapConstant: { |
| 307 Handle<Object> handle = OpParameter<Unique<Object> >(node).handle(); | 309 Handle<Object> object = OpParameter<Unique<Object>>(node).handle(); |
| 308 DCHECK(*handle == isolate()->heap()->true_value() || | 310 return jsgraph()->Int32Constant(object->BooleanValue() ? 1 : 0); |
| 309 *handle == isolate()->heap()->false_value()); | |
| 310 return jsgraph()->Int32Constant( | |
| 311 *handle == isolate()->heap()->true_value() ? 1 : 0); | |
| 312 } | 311 } |
| 313 default: | 312 default: |
| 314 break; | 313 break; |
| 315 } | 314 } |
| 316 // Select the correct X -> Bit operator. | 315 // Select the correct X -> Bit operator. |
| 317 const Operator* op; | 316 const Operator* op; |
| 318 if (output_type & rWord) { | 317 if (output_type & rWord) { |
| 319 return node; // No change necessary. | 318 op = simplified()->ChangeWord32ToBit(); |
| 320 } else if (output_type & kRepWord64) { | 319 } else if (output_type & kRepWord64) { |
| 321 return node; // TODO(titzer): No change necessary, on 64-bit. | 320 op = simplified()->ChangeWord64ToBit(); |
| 322 } else if (output_type & kRepTagged) { | 321 } else if (output_type & kRepTagged) { |
| 323 op = simplified()->ChangeBoolToBit(); | 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 } | |
| 324 } else { | 336 } else { |
| 325 return TypeError(node, output_type, kRepBit); | 337 return TypeError(node, output_type, kRepBit); |
| 326 } | 338 } |
| 327 return jsgraph()->graph()->NewNode(op, node); | 339 return graph()->NewNode(op, node); |
| 328 } | 340 } |
| 329 | 341 |
| 330 Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) { | 342 Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) { |
| 331 if (output_type & kRepBit) { | 343 if (output_type & kRepBit) { |
| 332 return node; // Sloppy comparison -> word64 | 344 return node; // Sloppy comparison -> word64 |
| 333 } | 345 } |
| 334 // Can't really convert Word64 to anything else. Purported to be internal. | 346 // Can't really convert Word64 to anything else. Purported to be internal. |
| 335 return TypeError(node, output_type, kRepWord64); | 347 return TypeError(node, output_type, kRepWord64); |
| 336 } | 348 } |
| 337 | 349 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 422 if (type->Is(Type::Unsigned32())) return kTypeUint32; | 434 if (type->Is(Type::Unsigned32())) return kTypeUint32; |
| 423 if (type->Is(Type::Number())) return kTypeNumber; | 435 if (type->Is(Type::Number())) return kTypeNumber; |
| 424 if (type->Is(Type::Boolean())) return kTypeBool; | 436 if (type->Is(Type::Boolean())) return kTypeBool; |
| 425 return kTypeAny; | 437 return kTypeAny; |
| 426 } | 438 } |
| 427 | 439 |
| 428 private: | 440 private: |
| 429 JSGraph* jsgraph_; | 441 JSGraph* jsgraph_; |
| 430 SimplifiedOperatorBuilder* simplified_; | 442 SimplifiedOperatorBuilder* simplified_; |
| 431 Isolate* isolate_; | 443 Isolate* isolate_; |
| 444 Type* bit_range_; | |
| 432 | 445 |
| 433 friend class RepresentationChangerTester; // accesses the below fields. | 446 friend class RepresentationChangerTester; // accesses the below fields. |
| 434 | 447 |
| 435 bool testing_type_errors_; // If {true}, don't abort on a type error. | 448 bool testing_type_errors_; // If {true}, don't abort on a type error. |
| 436 bool type_error_; // Set when a type error is detected. | 449 bool type_error_; // Set when a type error is detected. |
| 437 | 450 |
| 438 Node* TypeError(Node* node, MachineTypeUnion output_type, | 451 Node* TypeError(Node* node, MachineTypeUnion output_type, |
| 439 MachineTypeUnion use) { | 452 MachineTypeUnion use) { |
| 440 type_error_ = true; | 453 type_error_ = true; |
| 441 if (!testing_type_errors_) { | 454 if (!testing_type_errors_) { |
| 442 std::ostringstream out_str; | 455 std::ostringstream out_str; |
| 443 out_str << static_cast<MachineType>(output_type); | 456 out_str << static_cast<MachineType>(output_type); |
| 444 | 457 |
| 445 std::ostringstream use_str; | 458 std::ostringstream use_str; |
| 446 use_str << static_cast<MachineType>(use); | 459 use_str << static_cast<MachineType>(use); |
| 447 | 460 |
| 448 V8_Fatal(__FILE__, __LINE__, | 461 V8_Fatal(__FILE__, __LINE__, |
| 449 "RepresentationChangerError: node #%d:%s of " | 462 "RepresentationChangerError: node #%d:%s of " |
| 450 "%s cannot be changed to %s", | 463 "%s cannot be changed to %s", |
| 451 node->id(), node->op()->mnemonic(), out_str.str().c_str(), | 464 node->id(), node->op()->mnemonic(), out_str.str().c_str(), |
| 452 use_str.str().c_str()); | 465 use_str.str().c_str()); |
| 453 } | 466 } |
| 454 return node; | 467 return node; |
| 455 } | 468 } |
| 456 | 469 |
| 457 Node* InsertChangeFloat32ToFloat64(Node* node) { | 470 Node* InsertChangeFloat32ToFloat64(Node* node) { |
| 458 return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), | 471 return graph()->NewNode(machine()->ChangeFloat32ToFloat64(), node); |
| 459 node); | |
| 460 } | 472 } |
| 461 | 473 |
| 462 Node* InsertChangeTaggedToFloat64(Node* node) { | 474 Node* InsertChangeTaggedToFloat64(Node* node) { |
| 463 return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(), | 475 return graph()->NewNode(simplified()->ChangeTaggedToFloat64(), node); |
| 464 node); | |
| 465 } | 476 } |
| 466 | 477 |
| 467 JSGraph* jsgraph() { return jsgraph_; } | 478 Node* InsertChangeTaggedToInt32(Node* node) { |
| 468 Isolate* isolate() { return isolate_; } | 479 return graph()->NewNode(simplified()->ChangeTaggedToInt32(), node); |
| 469 SimplifiedOperatorBuilder* simplified() { return simplified_; } | 480 } |
| 470 MachineOperatorBuilder* machine() { return jsgraph()->machine(); } | 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_; } | |
| 488 Isolate* isolate() const { return isolate_; } | |
| 489 SimplifiedOperatorBuilder* simplified() const { return simplified_; } | |
| 490 MachineOperatorBuilder* machine() const { return jsgraph()->machine(); } | |
| 471 }; | 491 }; |
| 472 | 492 |
| 473 } // namespace compiler | 493 } // namespace compiler |
| 474 } // namespace internal | 494 } // namespace internal |
| 475 } // namespace v8 | 495 } // namespace v8 |
| 476 | 496 |
| 477 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ | 497 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ |
| OLD | NEW |