| 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_
|
|
|