Index: src/compiler/representation-change.h |
diff --git a/src/compiler/representation-change.h b/src/compiler/representation-change.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..824e22ba29f1a42070b62084f9b8ac9b9f8570e9 |
--- /dev/null |
+++ b/src/compiler/representation-change.h |
@@ -0,0 +1,383 @@ |
+// Copyright 2014 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_ |
+#define V8_COMPILER_REPRESENTATION_CHANGE_H_ |
+ |
+#include "src/compiler/js-graph.h" |
+#include "src/compiler/machine-operator.h" |
+#include "src/compiler/node-properties-inl.h" |
+#include "src/compiler/simplified-operator.h" |
+ |
+namespace v8 { |
+namespace internal { |
+namespace compiler { |
+ |
+// The types and representations tracked during representation inference |
+// and change insertion. |
+// TODO(titzer): First, merge MachineRepresentation and RepType. |
+// TODO(titzer): Second, Use the real type system instead of RepType. |
+enum RepType { |
+ // Representations. |
+ rBit = 1 << 0, |
+ rWord32 = 1 << 1, |
+ rWord64 = 1 << 2, |
+ rFloat64 = 1 << 3, |
+ rTagged = 1 << 4, |
+ |
+ // Types. |
+ tBool = 1 << 5, |
+ tInt32 = 1 << 6, |
+ tUint32 = 1 << 7, |
+ tInt64 = 1 << 8, |
+ tUint64 = 1 << 9, |
+ tNumber = 1 << 10, |
+ tAny = 1 << 11 |
+}; |
+ |
+typedef uint16_t RepTypeUnion; |
+ |
+const RepTypeUnion rMask = rBit | rWord32 | rWord64 | rFloat64 | rTagged; |
+const RepTypeUnion tMask = |
+ tBool | tInt32 | tUint32 | tInt64 | tUint64 | tNumber | tAny; |
+const RepType rPtr = kPointerSize == 4 ? rWord32 : rWord64; |
+ |
+ |
+// Contains logic related to changing the representation of values for constants |
+// and other nodes, as well as lowering Simplified->Machine operators. |
+// Eagerly folds any representation changes for constants. |
+class RepresentationChanger { |
+ public: |
+ RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified, |
+ MachineOperatorBuilder* machine, Isolate* isolate) |
+ : jsgraph_(jsgraph), |
+ simplified_(simplified), |
+ machine_(machine), |
+ isolate_(isolate), |
+ testing_type_errors_(false), |
+ type_error_(false) {} |
+ |
+ |
+ Node* GetRepresentationFor(Node* node, RepTypeUnion output_type, |
+ RepTypeUnion use_type) { |
+ if (!IsPowerOf2(output_type & rMask)) { |
+ // There should be only one output representation. |
+ return TypeError(node, output_type, use_type); |
+ } |
+ if ((use_type & rMask) == (output_type & rMask)) { |
+ // Representations are the same. That's a no-op. |
+ return node; |
+ } |
+ if (use_type & rTagged) { |
+ return GetTaggedRepresentationFor(node, output_type); |
+ } else if (use_type & rFloat64) { |
+ return GetFloat64RepresentationFor(node, output_type); |
+ } else if (use_type & rWord32) { |
+ return GetWord32RepresentationFor(node, output_type); |
+ } else if (use_type & rBit) { |
+ return GetBitRepresentationFor(node, output_type); |
+ } else if (use_type & rWord64) { |
+ return GetWord64RepresentationFor(node, output_type); |
+ } else { |
+ return node; |
+ } |
+ } |
+ |
+ Node* GetTaggedRepresentationFor(Node* node, RepTypeUnion 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 & tUint32) { |
+ uint32_t value = ValueOf<uint32_t>(node->op()); |
+ return jsgraph()->Constant(static_cast<double>(value)); |
+ } else if (output_type & tInt32) { |
+ int32_t value = ValueOf<int32_t>(node->op()); |
+ return jsgraph()->Constant(value); |
+ } else if (output_type & rBit) { |
+ return ValueOf<int32_t>(node->op()) == 0 ? jsgraph()->FalseConstant() |
+ : jsgraph()->TrueConstant(); |
+ } else { |
+ return TypeError(node, output_type, rTagged); |
+ } |
+ case IrOpcode::kFloat64Constant: |
+ return jsgraph()->Constant(ValueOf<double>(node->op())); |
+ default: |
+ break; |
+ } |
+ // Select the correct X -> Tagged operator. |
+ Operator* op; |
+ if (output_type & rBit) { |
+ op = simplified()->ChangeBitToBool(); |
+ } else if (output_type & rWord32) { |
+ if (output_type & tUint32) { |
+ op = simplified()->ChangeUint32ToTagged(); |
+ } else if (output_type & tInt32) { |
+ op = simplified()->ChangeInt32ToTagged(); |
+ } else { |
+ return TypeError(node, output_type, rTagged); |
+ } |
+ } else if (output_type & rFloat64) { |
+ op = simplified()->ChangeFloat64ToTagged(); |
+ } else { |
+ return TypeError(node, output_type, rTagged); |
+ } |
+ return jsgraph()->graph()->NewNode(op, node); |
+ } |
+ |
+ Node* GetFloat64RepresentationFor(Node* node, RepTypeUnion output_type) { |
+ // Eagerly fold representation changes for constants. |
+ switch (node->opcode()) { |
+ case IrOpcode::kNumberConstant: |
+ return jsgraph()->Float64Constant(ValueOf<double>(node->op())); |
+ case IrOpcode::kInt32Constant: |
+ if (output_type & tUint32) { |
+ uint32_t value = ValueOf<uint32_t>(node->op()); |
+ return jsgraph()->Float64Constant(static_cast<double>(value)); |
+ } else { |
+ int32_t value = ValueOf<int32_t>(node->op()); |
+ return jsgraph()->Float64Constant(value); |
+ } |
+ case IrOpcode::kFloat64Constant: |
+ return node; // No change necessary. |
+ default: |
+ break; |
+ } |
+ // Select the correct X -> Float64 operator. |
+ Operator* op; |
+ if (output_type & rWord32) { |
+ if (output_type & tUint32) { |
+ op = machine()->ConvertUint32ToFloat64(); |
+ } else if (output_type & tInt32) { |
+ op = machine()->ConvertInt32ToFloat64(); |
+ } else { |
+ return TypeError(node, output_type, rFloat64); |
+ } |
+ } else if (output_type & rTagged) { |
+ op = simplified()->ChangeTaggedToFloat64(); |
+ } else { |
+ return TypeError(node, output_type, rFloat64); |
+ } |
+ return jsgraph()->graph()->NewNode(op, node); |
+ } |
+ |
+ Node* GetWord32RepresentationFor(Node* node, RepTypeUnion output_type) { |
+ // Eagerly fold representation changes for constants. |
+ switch (node->opcode()) { |
+ case IrOpcode::kInt32Constant: |
+ return node; // No change necessary. |
+ case IrOpcode::kNumberConstant: |
+ case IrOpcode::kFloat64Constant: { |
+ if (output_type & tUint32) { |
+ int32_t value = static_cast<int32_t>( |
+ static_cast<uint32_t>(ValueOf<double>(node->op()))); |
+ return jsgraph()->Int32Constant(value); |
+ } else if (output_type & tInt32) { |
+ int32_t value = FastD2I(ValueOf<double>(node->op())); |
+ return jsgraph()->Int32Constant(value); |
+ } else { |
+ return TypeError(node, output_type, rWord32); |
+ } |
+ } |
+ default: |
+ break; |
+ } |
+ // Select the correct X -> Word32 operator. |
+ Operator* op = NULL; |
+ if (output_type & rFloat64) { |
+ // TODO(turbofan): could have cheaper float64 conversions that don't do |
+ // the full JavaScript truncation here. |
+ if (output_type & tUint32) { |
+ op = machine()->ConvertFloat64ToUint32(); |
+ } else if (output_type & tInt32) { |
+ op = machine()->ConvertFloat64ToInt32(); |
+ } else { |
+ return TypeError(node, output_type, rWord32); |
+ } |
+ } else if (output_type & rTagged) { |
+ if (output_type & tUint32) { |
+ op = simplified()->ChangeTaggedToUint32(); |
+ } else if (output_type & tInt32) { |
+ op = simplified()->ChangeTaggedToInt32(); |
+ } else { |
+ return TypeError(node, output_type, rWord32); |
+ } |
+ } else if (output_type & rBit) { |
+ return node; // Sloppy comparison -> word32. |
+ } else { |
+ return TypeError(node, output_type, rWord32); |
+ } |
+ return jsgraph()->graph()->NewNode(op, node); |
+ } |
+ |
+ Node* GetBitRepresentationFor(Node* node, RepTypeUnion output_type) { |
+ // Eagerly fold representation changes for constants. |
+ switch (node->opcode()) { |
+ case IrOpcode::kInt32Constant: { |
+ int32_t value = ValueOf<int32_t>(node->op()); |
+ if (value == 0 || value == 1) return node; |
+ return jsgraph()->OneConstant(); // value != 0 |
+ } |
+ case IrOpcode::kHeapConstant: { |
+ Handle<Object> handle = ValueOf<Handle<Object> >(node->op()); |
+ ASSERT(*handle == isolate()->heap()->true_value() || |
+ *handle == isolate()->heap()->false_value()); |
+ return jsgraph()->Int32Constant( |
+ *handle == isolate()->heap()->true_value() ? 1 : 0); |
+ } |
+ default: |
+ break; |
+ } |
+ // Select the correct X -> Bit operator. |
+ Operator* op; |
+ if (output_type & rWord32) { |
+ return node; // No change necessary. |
+ } else if (output_type & rWord64) { |
+ return node; // TODO(titzer): No change necessary, on 64-bit. |
+ } else if (output_type & rTagged) { |
+ op = simplified()->ChangeBoolToBit(); |
+ } else { |
+ return TypeError(node, output_type, rBit); |
+ } |
+ return jsgraph()->graph()->NewNode(op, node); |
+ } |
+ |
+ Node* GetWord64RepresentationFor(Node* node, RepTypeUnion output_type) { |
+ if (output_type & rBit) { |
+ return node; // Sloppy comparison -> word64 |
+ } |
+ // Can't really convert Word64 to anything else. Purported to be internal. |
+ return TypeError(node, output_type, rWord64); |
+ } |
+ |
+ static RepType TypeForMachineRepresentation(MachineRepresentation rep) { |
+ // TODO(titzer): merge MachineRepresentation and RepType. |
+ switch (rep) { |
+ case kMachineWord8: |
+ return rWord32; |
+ case kMachineWord16: |
+ return rWord32; |
+ case kMachineWord32: |
+ return rWord32; |
+ case kMachineWord64: |
+ return rWord64; |
+ case kMachineFloat64: |
+ return rFloat64; |
+ case kMachineTagged: |
+ return rTagged; |
+ default: |
+ UNREACHABLE(); |
+ return static_cast<RepType>(0); |
+ } |
+ } |
+ |
+ Operator* Int32OperatorFor(IrOpcode::Value opcode) { |
+ switch (opcode) { |
+ case IrOpcode::kNumberAdd: |
+ return machine()->Int32Add(); |
+ case IrOpcode::kNumberSubtract: |
+ return machine()->Int32Sub(); |
+ case IrOpcode::kNumberEqual: |
+ return machine()->Word32Equal(); |
+ case IrOpcode::kNumberLessThan: |
+ return machine()->Int32LessThan(); |
+ case IrOpcode::kNumberLessThanOrEqual: |
+ return machine()->Int32LessThanOrEqual(); |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+ } |
+ |
+ Operator* Uint32OperatorFor(IrOpcode::Value opcode) { |
+ switch (opcode) { |
+ case IrOpcode::kNumberAdd: |
+ return machine()->Int32Add(); |
+ case IrOpcode::kNumberSubtract: |
+ return machine()->Int32Sub(); |
+ case IrOpcode::kNumberEqual: |
+ return machine()->Word32Equal(); |
+ case IrOpcode::kNumberLessThan: |
+ return machine()->Uint32LessThan(); |
+ case IrOpcode::kNumberLessThanOrEqual: |
+ return machine()->Uint32LessThanOrEqual(); |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+ } |
+ |
+ 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; |
+ } |
+ } |
+ |
+ RepType TypeForField(const FieldAccess& access) { |
+ RepType tElement = static_cast<RepType>(0); // TODO(titzer) |
+ RepType rElement = TypeForMachineRepresentation(access.representation); |
+ return static_cast<RepType>(tElement | rElement); |
+ } |
+ |
+ RepType TypeForElement(const ElementAccess& access) { |
+ RepType tElement = static_cast<RepType>(0); // TODO(titzer) |
+ RepType rElement = TypeForMachineRepresentation(access.representation); |
+ return static_cast<RepType>(tElement | rElement); |
+ } |
+ |
+ RepType TypeForBasePointer(Node* node) { |
+ Type* upper = NodeProperties::GetBounds(node).upper; |
+ if (upper->Is(Type::UntaggedPtr())) return rPtr; |
+ return static_cast<RepType>(tAny | rTagged); |
+ } |
+ |
+ private: |
+ JSGraph* jsgraph_; |
+ SimplifiedOperatorBuilder* simplified_; |
+ MachineOperatorBuilder* machine_; |
+ Isolate* isolate_; |
+ |
+ friend class RepresentationChangerTester; // accesses the below fields. |
+ |
+ bool testing_type_errors_; // If {true}, don't abort on a type error. |
+ bool type_error_; // Set when a type error is detected. |
+ |
+ Node* TypeError(Node* node, RepTypeUnion output_type, RepTypeUnion use) { |
+ type_error_ = true; |
+ if (!testing_type_errors_) { |
+ UNREACHABLE(); // TODO(titzer): report nicer type error |
+ } |
+ return node; |
+ } |
+ |
+ JSGraph* jsgraph() { return jsgraph_; } |
+ Isolate* isolate() { return isolate_; } |
+ SimplifiedOperatorBuilder* simplified() { return simplified_; } |
+ MachineOperatorBuilder* machine() { return machine_; } |
+}; |
+} |
+} |
+} // namespace v8::internal::compiler |
+ |
+#endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ |