Index: src/compiler/representation-change.h |
diff --git a/src/compiler/representation-change.h b/src/compiler/representation-change.h |
index dfb82960a02317431005d6190d5a8a7eb443abc5..5503b76cc4e94f2cab515baed20a21bd98e1c5bd 100644 |
--- a/src/compiler/representation-change.h |
+++ b/src/compiler/representation-change.h |
@@ -5,11 +5,7 @@ |
#ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_ |
#define V8_COMPILER_REPRESENTATION_CHANGE_H_ |
-#include <sstream> |
- |
-#include "src/base/bits.h" |
#include "src/compiler/js-graph.h" |
-#include "src/compiler/machine-operator.h" |
#include "src/compiler/simplified-operator.h" |
namespace v8 { |
@@ -35,12 +31,10 @@ class Truncation final { |
bool TruncatesToWord32() const { |
return LessGeneral(kind_, TruncationKind::kWord32); |
} |
- |
bool TruncatesNaNToZero() { |
return LessGeneral(kind_, TruncationKind::kWord32) || |
LessGeneral(kind_, TruncationKind::kBool); |
} |
- |
bool TruncatesUndefinedToZeroOrNaN() { |
return LessGeneral(kind_, TruncationKind::kFloat64) || |
LessGeneral(kind_, TruncationKind::kWord64); |
@@ -51,26 +45,7 @@ class Truncation final { |
bool operator!=(Truncation other) const { return !(*this == other); } |
// Debug utilities. |
- const char* description() { |
- switch (kind()) { |
- case TruncationKind::kNone: |
- return "no-value-use"; |
- case TruncationKind::kBool: |
- return "truncate-to-bool"; |
- case TruncationKind::kWord32: |
- return "truncate-to-word32"; |
- case TruncationKind::kWord64: |
- return "truncate-to-word64"; |
- case TruncationKind::kFloat32: |
- return "truncate-to-float32"; |
- case TruncationKind::kFloat64: |
- return "truncate-to-float64"; |
- case TruncationKind::kAny: |
- return "no-truncation"; |
- } |
- UNREACHABLE(); |
- return nullptr; |
- } |
+ const char* description() const; |
private: |
enum class TruncationKind : uint8_t { |
@@ -88,58 +63,8 @@ class Truncation final { |
TruncationKind kind_; |
- // Partial order for truncations: |
- // |
- // kWord64 kAny |
- // ^ ^ |
- // \ | |
- // \ kFloat64 <--+ |
- // \ ^ ^ | |
- // \ / | | |
- // kWord32 kFloat32 kBool |
- // ^ ^ ^ |
- // \ | / |
- // \ | / |
- // \ | / |
- // \ | / |
- // \ | / |
- // kNone |
- static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2) { |
- if (LessGeneral(rep1, rep2)) return rep2; |
- if (LessGeneral(rep2, rep1)) return rep1; |
- // Handle the generalization of float64-representable values. |
- if (LessGeneral(rep1, TruncationKind::kFloat64) && |
- LessGeneral(rep2, TruncationKind::kFloat64)) { |
- return TruncationKind::kFloat64; |
- } |
- // All other combinations are illegal. |
- FATAL("Tried to combine incompatible representations"); |
- return TruncationKind::kNone; |
- } |
- |
- static bool LessGeneral(TruncationKind rep1, TruncationKind rep2) { |
- switch (rep1) { |
- case TruncationKind::kNone: |
- return true; |
- case TruncationKind::kBool: |
- return rep2 == TruncationKind::kBool || rep2 == TruncationKind::kAny; |
- case TruncationKind::kWord32: |
- return rep2 == TruncationKind::kWord32 || |
- rep2 == TruncationKind::kWord64 || |
- rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny; |
- case TruncationKind::kWord64: |
- return rep2 == TruncationKind::kWord64; |
- case TruncationKind::kFloat32: |
- return rep2 == TruncationKind::kFloat32 || |
- rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny; |
- case TruncationKind::kFloat64: |
- return rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny; |
- case TruncationKind::kAny: |
- return rep2 == TruncationKind::kAny; |
- } |
- UNREACHABLE(); |
- return false; |
- } |
+ static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2); |
+ static bool LessGeneral(TruncationKind rep1, TruncationKind rep2); |
}; |
@@ -154,388 +79,17 @@ class RepresentationChanger final { |
testing_type_errors_(false), |
type_error_(false) {} |
- // TODO(titzer): should Word64 also be implicitly convertable to others? |
- static bool IsWord(MachineTypeUnion type) { |
- return (type & (kRepWord8 | kRepWord16 | kRepWord32)) != 0; |
- } |
- |
// Changes representation from {output_type} to {use_rep}. The {truncation} |
// parameter is only used for sanity checking - if the changer cannot figure |
// out signedness for the word32->float64 conversion, then we check that the |
// uses truncate to word32 (so they do not care about signedness). |
Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type, |
MachineTypeUnion use_rep, |
- Truncation truncation = Truncation::None()) { |
- DCHECK((use_rep & kRepMask) == use_rep); |
- if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) { |
- // There should be only one output representation. |
- return TypeError(node, output_type, use_rep); |
- } |
- if (use_rep == (output_type & kRepMask)) { |
- // Representations are the same. That's a no-op. |
- return node; |
- } |
- if (IsWord(use_rep) && IsWord(output_type)) { |
- // Both are words less than or equal to 32-bits. |
- // Since loads of integers from memory implicitly sign or zero extend the |
- // value to the full machine word size and stores implicitly truncate, |
- // no representation change is necessary. |
- return node; |
- } |
- if (use_rep & kRepTagged) { |
- return GetTaggedRepresentationFor(node, output_type); |
- } else if (use_rep & kRepFloat32) { |
- return GetFloat32RepresentationFor(node, output_type, truncation); |
- } else if (use_rep & kRepFloat64) { |
- return GetFloat64RepresentationFor(node, output_type, truncation); |
- } else if (use_rep & kRepBit) { |
- return GetBitRepresentationFor(node, output_type); |
- } else if (IsWord(use_rep)) { |
- return GetWord32RepresentationFor(node, output_type); |
- } else if (use_rep & kRepWord64) { |
- return GetWord64RepresentationFor(node, output_type); |
- } else { |
- return node; |
- } |
- } |
- |
- Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type) { |
- // Eagerly fold representation changes for constants. |
- switch (node->opcode()) { |
- case IrOpcode::kNumberConstant: |
- case IrOpcode::kHeapConstant: |
- return node; // No change necessary. |
- case IrOpcode::kInt32Constant: |
- if (output_type & kTypeUint32) { |
- uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); |
- return jsgraph()->Constant(static_cast<double>(value)); |
- } else if (output_type & kTypeInt32) { |
- int32_t value = OpParameter<int32_t>(node); |
- return jsgraph()->Constant(value); |
- } else if (output_type & kRepBit) { |
- return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant() |
- : jsgraph()->TrueConstant(); |
- } else { |
- return TypeError(node, output_type, kRepTagged); |
- } |
- case IrOpcode::kFloat64Constant: |
- return jsgraph()->Constant(OpParameter<double>(node)); |
- case IrOpcode::kFloat32Constant: |
- return jsgraph()->Constant(OpParameter<float>(node)); |
- default: |
- break; |
- } |
- // Select the correct X -> Tagged operator. |
- const Operator* op; |
- if (output_type & kRepBit) { |
- op = simplified()->ChangeBitToBool(); |
- } else if (IsWord(output_type)) { |
- if (output_type & kTypeUint32) { |
- op = simplified()->ChangeUint32ToTagged(); |
- } else if (output_type & kTypeInt32) { |
- op = simplified()->ChangeInt32ToTagged(); |
- } else { |
- return TypeError(node, output_type, kRepTagged); |
- } |
- } else if (output_type & kRepFloat32) { // float32 -> float64 -> tagged |
- node = InsertChangeFloat32ToFloat64(node); |
- op = simplified()->ChangeFloat64ToTagged(); |
- } else if (output_type & kRepFloat64) { |
- op = simplified()->ChangeFloat64ToTagged(); |
- } else { |
- return TypeError(node, output_type, kRepTagged); |
- } |
- return jsgraph()->graph()->NewNode(op, node); |
- } |
- |
- Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type, |
- Truncation truncation) { |
- // Eagerly fold representation changes for constants. |
- switch (node->opcode()) { |
- case IrOpcode::kFloat64Constant: |
- case IrOpcode::kNumberConstant: |
- return jsgraph()->Float32Constant( |
- DoubleToFloat32(OpParameter<double>(node))); |
- case IrOpcode::kInt32Constant: |
- if (output_type & kTypeUint32) { |
- uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); |
- return jsgraph()->Float32Constant(static_cast<float>(value)); |
- } else { |
- int32_t value = OpParameter<int32_t>(node); |
- return jsgraph()->Float32Constant(static_cast<float>(value)); |
- } |
- case IrOpcode::kFloat32Constant: |
- return node; // No change necessary. |
- default: |
- break; |
- } |
- // Select the correct X -> Float32 operator. |
- const Operator* op; |
- if (output_type & kRepBit) { |
- return TypeError(node, output_type, kRepFloat32); |
- } else if (IsWord(output_type)) { |
- if (output_type & kTypeUint32) { |
- op = machine()->ChangeUint32ToFloat64(); |
- } else { |
- // Either the output is int32 or the uses only care about the |
- // low 32 bits (so we can pick int32 safely). |
- DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32()); |
- op = machine()->ChangeInt32ToFloat64(); |
- } |
- // int32 -> float64 -> float32 |
- node = jsgraph()->graph()->NewNode(op, node); |
- op = machine()->TruncateFloat64ToFloat32(); |
- } else if (output_type & kRepTagged) { |
- op = simplified() |
- ->ChangeTaggedToFloat64(); // tagged -> float64 -> float32 |
- node = jsgraph()->graph()->NewNode(op, node); |
- op = machine()->TruncateFloat64ToFloat32(); |
- } else if (output_type & kRepFloat64) { |
- op = machine()->TruncateFloat64ToFloat32(); |
- } else { |
- return TypeError(node, output_type, kRepFloat32); |
- } |
- return jsgraph()->graph()->NewNode(op, node); |
- } |
- |
- Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type, |
- Truncation truncation) { |
- // Eagerly fold representation changes for constants. |
- switch (node->opcode()) { |
- case IrOpcode::kNumberConstant: |
- return jsgraph()->Float64Constant(OpParameter<double>(node)); |
- case IrOpcode::kInt32Constant: |
- if (output_type & kTypeUint32) { |
- uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); |
- return jsgraph()->Float64Constant(static_cast<double>(value)); |
- } else { |
- int32_t value = OpParameter<int32_t>(node); |
- return jsgraph()->Float64Constant(value); |
- } |
- case IrOpcode::kFloat64Constant: |
- return node; // No change necessary. |
- case IrOpcode::kFloat32Constant: |
- return jsgraph()->Float64Constant(OpParameter<float>(node)); |
- default: |
- break; |
- } |
- // Select the correct X -> Float64 operator. |
- const Operator* op; |
- if (output_type & kRepBit) { |
- return TypeError(node, output_type, kRepFloat64); |
- } else if (IsWord(output_type)) { |
- if (output_type & kTypeUint32) { |
- op = machine()->ChangeUint32ToFloat64(); |
- } else { |
- // Either the output is int32 or the uses only care about the |
- // low 32 bits (so we can pick int32 safely). |
- DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32()); |
- op = machine()->ChangeInt32ToFloat64(); |
- } |
- } else if (output_type & kRepTagged) { |
- op = simplified()->ChangeTaggedToFloat64(); |
- } else if (output_type & kRepFloat32) { |
- op = machine()->ChangeFloat32ToFloat64(); |
- } else { |
- return TypeError(node, output_type, kRepFloat64); |
- } |
- return jsgraph()->graph()->NewNode(op, node); |
- } |
- |
- Node* MakeTruncatedInt32Constant(double value) { |
- return jsgraph()->Int32Constant(DoubleToInt32(value)); |
- } |
- |
- Node* GetTruncatedWord32For(Node* node, MachineTypeUnion output_type) { |
- // Eagerly fold truncations for constants. |
- switch (node->opcode()) { |
- case IrOpcode::kInt32Constant: |
- return node; // No change necessary. |
- case IrOpcode::kFloat32Constant: |
- return jsgraph()->Int32Constant( |
- DoubleToInt32(OpParameter<float>(node))); |
- case IrOpcode::kNumberConstant: |
- case IrOpcode::kFloat64Constant: |
- return jsgraph()->Int32Constant( |
- DoubleToInt32(OpParameter<double>(node))); |
- default: |
- break; |
- } |
- // Select the correct X -> Word32 truncation operator. |
- const Operator* op = NULL; |
- if (output_type & kRepFloat64) { |
- op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); |
- } else if (output_type & kRepFloat32) { |
- node = InsertChangeFloat32ToFloat64(node); |
- op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); |
- } else if (output_type & kRepTagged) { |
- node = InsertChangeTaggedToFloat64(node); |
- op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); |
- } else { |
- return TypeError(node, output_type, kRepWord32); |
- } |
- return jsgraph()->graph()->NewNode(op, node); |
- } |
- |
- Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type) { |
- // Eagerly fold representation changes for constants. |
- switch (node->opcode()) { |
- case IrOpcode::kInt32Constant: |
- return node; // No change necessary. |
- case IrOpcode::kFloat32Constant: |
- return MakeTruncatedInt32Constant(OpParameter<float>(node)); |
- case IrOpcode::kNumberConstant: |
- case IrOpcode::kFloat64Constant: |
- return MakeTruncatedInt32Constant(OpParameter<double>(node)); |
- default: |
- break; |
- } |
- // Select the correct X -> Word32 operator. |
- const Operator* op; |
- Type* type = NodeProperties::GetType(node); |
- |
- if (output_type & kRepBit) { |
- return node; // Sloppy comparison -> word32 |
- } else if (output_type & kRepFloat64) { |
- if (output_type & kTypeUint32 || type->Is(Type::Unsigned32())) { |
- op = machine()->ChangeFloat64ToUint32(); |
- } else if (output_type & kTypeInt32 || type->Is(Type::Signed32())) { |
- op = machine()->ChangeFloat64ToInt32(); |
- } else { |
- op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); |
- } |
- } else if (output_type & kRepFloat32) { |
- node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 |
- if (output_type & kTypeUint32 || type->Is(Type::Unsigned32())) { |
- op = machine()->ChangeFloat64ToUint32(); |
- } else if (output_type & kTypeInt32 || type->Is(Type::Signed32())) { |
- op = machine()->ChangeFloat64ToInt32(); |
- } else { |
- op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); |
- } |
- } else if (output_type & kRepTagged) { |
- if (output_type & kTypeUint32 || type->Is(Type::Unsigned32())) { |
- op = simplified()->ChangeTaggedToUint32(); |
- } else if (output_type & kTypeInt32 || type->Is(Type::Signed32())) { |
- op = simplified()->ChangeTaggedToInt32(); |
- } else { |
- node = InsertChangeTaggedToFloat64(node); |
- op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); |
- } |
- } else { |
- return TypeError(node, output_type, kRepWord32); |
- } |
- return jsgraph()->graph()->NewNode(op, node); |
- } |
- |
- Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) { |
- // Eagerly fold representation changes for constants. |
- switch (node->opcode()) { |
- case IrOpcode::kHeapConstant: { |
- Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node); |
- DCHECK(value.is_identical_to(factory()->true_value()) || |
- value.is_identical_to(factory()->false_value())); |
- return jsgraph()->Int32Constant( |
- value.is_identical_to(factory()->true_value()) ? 1 : 0); |
- } |
- default: |
- break; |
- } |
- // Select the correct X -> Bit operator. |
- const Operator* op; |
- if (output_type & kRepTagged) { |
- op = simplified()->ChangeBoolToBit(); |
- } else { |
- return TypeError(node, output_type, kRepBit); |
- } |
- return jsgraph()->graph()->NewNode(op, node); |
- } |
- |
- Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) { |
- if (output_type & kRepBit) { |
- return node; // Sloppy comparison -> word64 |
- } |
- // Can't really convert Word64 to anything else. Purported to be internal. |
- return TypeError(node, output_type, kRepWord64); |
- } |
- |
- const Operator* Int32OperatorFor(IrOpcode::Value opcode) { |
- switch (opcode) { |
- case IrOpcode::kNumberAdd: |
- return machine()->Int32Add(); |
- case IrOpcode::kNumberSubtract: |
- return machine()->Int32Sub(); |
- case IrOpcode::kNumberMultiply: |
- return machine()->Int32Mul(); |
- case IrOpcode::kNumberDivide: |
- return machine()->Int32Div(); |
- case IrOpcode::kNumberModulus: |
- return machine()->Int32Mod(); |
- case IrOpcode::kNumberBitwiseOr: |
- return machine()->Word32Or(); |
- case IrOpcode::kNumberBitwiseXor: |
- return machine()->Word32Xor(); |
- case IrOpcode::kNumberBitwiseAnd: |
- return machine()->Word32And(); |
- case IrOpcode::kNumberEqual: |
- return machine()->Word32Equal(); |
- case IrOpcode::kNumberLessThan: |
- return machine()->Int32LessThan(); |
- case IrOpcode::kNumberLessThanOrEqual: |
- return machine()->Int32LessThanOrEqual(); |
- default: |
- UNREACHABLE(); |
- return NULL; |
- } |
- } |
- |
- const Operator* Uint32OperatorFor(IrOpcode::Value opcode) { |
- switch (opcode) { |
- case IrOpcode::kNumberAdd: |
- return machine()->Int32Add(); |
- case IrOpcode::kNumberSubtract: |
- return machine()->Int32Sub(); |
- case IrOpcode::kNumberMultiply: |
- return machine()->Int32Mul(); |
- case IrOpcode::kNumberDivide: |
- return machine()->Uint32Div(); |
- case IrOpcode::kNumberModulus: |
- return machine()->Uint32Mod(); |
- case IrOpcode::kNumberEqual: |
- return machine()->Word32Equal(); |
- case IrOpcode::kNumberLessThan: |
- return machine()->Uint32LessThan(); |
- case IrOpcode::kNumberLessThanOrEqual: |
- return machine()->Uint32LessThanOrEqual(); |
- default: |
- UNREACHABLE(); |
- return NULL; |
- } |
- } |
- |
- const Operator* Float64OperatorFor(IrOpcode::Value opcode) { |
- switch (opcode) { |
- case IrOpcode::kNumberAdd: |
- return machine()->Float64Add(); |
- case IrOpcode::kNumberSubtract: |
- return machine()->Float64Sub(); |
- case IrOpcode::kNumberMultiply: |
- return machine()->Float64Mul(); |
- case IrOpcode::kNumberDivide: |
- return machine()->Float64Div(); |
- case IrOpcode::kNumberModulus: |
- return machine()->Float64Mod(); |
- case IrOpcode::kNumberEqual: |
- return machine()->Float64Equal(); |
- case IrOpcode::kNumberLessThan: |
- return machine()->Float64LessThan(); |
- case IrOpcode::kNumberLessThanOrEqual: |
- return machine()->Float64LessThanOrEqual(); |
- default: |
- UNREACHABLE(); |
- return NULL; |
- } |
- } |
+ Truncation truncation = Truncation::None()); |
+ const Operator* Int32OperatorFor(IrOpcode::Value opcode); |
+ const Operator* Uint32OperatorFor(IrOpcode::Value opcode); |
+ const Operator* Float64OperatorFor(IrOpcode::Value opcode); |
+ MachineType TypeFromUpperBound(Type* type); |
MachineType TypeForBasePointer(const FieldAccess& access) { |
return access.tag() != 0 ? kMachAnyTagged : kMachPtr; |
@@ -545,16 +99,6 @@ class RepresentationChanger final { |
return access.tag() != 0 ? kMachAnyTagged : kMachPtr; |
} |
- MachineType TypeFromUpperBound(Type* type) { |
- if (type->Is(Type::None())) |
- return kTypeAny; // TODO(titzer): should be an error |
- if (type->Is(Type::Signed32())) return kTypeInt32; |
- if (type->Is(Type::Unsigned32())) return kTypeUint32; |
- if (type->Is(Type::Number())) return kTypeNumber; |
- if (type->Is(Type::Boolean())) return kTypeBool; |
- return kTypeAny; |
- } |
- |
private: |
JSGraph* jsgraph_; |
Isolate* isolate_; |
@@ -564,34 +108,19 @@ class RepresentationChanger final { |
bool testing_type_errors_; // If {true}, don't abort on a type error. |
bool type_error_; // Set when a type error is detected. |
+ Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type); |
+ Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type, |
+ Truncation truncation); |
+ Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type, |
+ Truncation truncation); |
+ Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type); |
+ Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type); |
+ Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type); |
Node* TypeError(Node* node, MachineTypeUnion output_type, |
- MachineTypeUnion use) { |
- type_error_ = true; |
- if (!testing_type_errors_) { |
- std::ostringstream out_str; |
- out_str << static_cast<MachineType>(output_type); |
- |
- std::ostringstream use_str; |
- use_str << static_cast<MachineType>(use); |
- |
- V8_Fatal(__FILE__, __LINE__, |
- "RepresentationChangerError: node #%d:%s of " |
- "%s cannot be changed to %s", |
- node->id(), node->op()->mnemonic(), out_str.str().c_str(), |
- use_str.str().c_str()); |
- } |
- return node; |
- } |
- |
- Node* InsertChangeFloat32ToFloat64(Node* node) { |
- return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), |
- node); |
- } |
- |
- Node* InsertChangeTaggedToFloat64(Node* node) { |
- return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(), |
- node); |
- } |
+ MachineTypeUnion use); |
+ Node* MakeTruncatedInt32Constant(double value); |
+ Node* InsertChangeFloat32ToFloat64(Node* node); |
+ Node* InsertChangeTaggedToFloat64(Node* node); |
JSGraph* jsgraph() const { return jsgraph_; } |
Isolate* isolate() const { return isolate_; } |