From 9fb5f564a935034a21743766dfd984c39a32783a Mon Sep 17 00:00:00 2001 From: "titzer@chromium.org" Date: Wed, 24 Sep 2014 11:55:07 +0000 Subject: [PATCH] Add support for Float32 representation changes. R=bmeurer@chromium.org BUG=v8:3589 LOG=n Review URL: https://codereview.chromium.org/598963002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24180 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/compiler/js-graph.cc | 6 ++ src/compiler/js-graph.h | 3 + src/compiler/js-typed-lowering.cc | 14 +--- src/compiler/representation-change.h | 88 +++++++++++++++++----- test/cctest/compiler/test-representation-change.cc | 53 ++++++++++++- 5 files changed, 132 insertions(+), 32 deletions(-) diff --git a/src/compiler/js-graph.cc b/src/compiler/js-graph.cc index 1309531..c403721 100644 --- a/src/compiler/js-graph.cc +++ b/src/compiler/js-graph.cc @@ -165,6 +165,12 @@ Node* JSGraph::NumberConstant(double value) { } +Node* JSGraph::Float32Constant(float value) { + // TODO(turbofan): cache float32 constants. + return NewNode(common()->Float32Constant(value)); +} + + Node* JSGraph::Float64Constant(double value) { Node** loc = cache_.FindFloat64Constant(value); if (*loc == NULL) { diff --git a/src/compiler/js-graph.h b/src/compiler/js-graph.h index 2b2dfd1..fd3de12 100644 --- a/src/compiler/js-graph.h +++ b/src/compiler/js-graph.h @@ -69,6 +69,9 @@ class JSGraph : public ZoneObject { return Int32Constant(bit_cast(value)); } + // Creates a Float32Constant node, usually canonicalized. + Node* Float32Constant(float value); + // Creates a Float64Constant node, usually canonicalized. Node* Float64Constant(double value); diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 8fe899c..8d4bd20 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -559,14 +559,6 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { graph()->NewNode(simplified()->LoadElement(element_access), elements, key, jsgraph()->Uint32Constant(length), NodeProperties::GetEffectInput(node)); - // TODO(titzer): Remove this hack once float32 is properly supported in - // simplified lowering. - if (element_access.machine_type == kRepFloat32) { - Node* change = - graph()->NewNode(machine()->ChangeFloat32ToFloat64(), value); - NodeProperties::ReplaceWithValue(node, change, value); - return Changed(value); - } return ReplaceEagerly(node, value); } return NoChange(); @@ -610,11 +602,7 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { NodeProperties::GetControlInput(node)); Node* if_true = graph()->NewNode(common()->IfTrue(), branch); - // TODO(titzer): Remove this hack once float32 is properly supported in - // simplified lowering. - if (element_access.machine_type == kRepFloat32) { - value = graph()->NewNode(machine()->TruncateFloat64ToFloat32(), value); - } + Node* store = graph()->NewNode(simplified()->StoreElement(element_access), elements, key, jsgraph()->Uint32Constant(length), value, diff --git a/src/compiler/representation-change.h b/src/compiler/representation-change.h index e9486f3..8c1467f 100644 --- a/src/compiler/representation-change.h +++ b/src/compiler/representation-change.h @@ -88,6 +88,8 @@ class RepresentationChanger { } case IrOpcode::kFloat64Constant: return jsgraph()->Constant(OpParameter(node)); + case IrOpcode::kFloat32Constant: + return jsgraph()->Constant(OpParameter(node)); default: break; } @@ -103,9 +105,8 @@ class RepresentationChanger { } else { return TypeError(node, output_type, kRepTagged); } - } else if (output_type & kRepFloat32) { - node = jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), - node); + } else if (output_type & kRepFloat32) { // float32 -> float64 -> tagged + node = InsertChangeFloat32ToFloat64(node); op = simplified()->ChangeFloat64ToTagged(); } else if (output_type & kRepFloat64) { op = simplified()->ChangeFloat64ToTagged(); @@ -118,14 +119,47 @@ class RepresentationChanger { Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type) { // Eagerly fold representation changes for constants. switch (node->opcode()) { - // TODO(turbofan): NumberConstant, Int32Constant, and Float64Constant? + case IrOpcode::kFloat64Constant: + case IrOpcode::kNumberConstant: + return jsgraph()->Float32Constant( + DoubleToFloat32(OpParameter(node))); + case IrOpcode::kInt32Constant: + if (output_type & kTypeUint32) { + uint32_t value = OpParameter(node); + return jsgraph()->Float32Constant(value); + } else { + int32_t value = OpParameter(node); + return jsgraph()->Float32Constant(value); + } case IrOpcode::kFloat32Constant: return node; // No change necessary. default: break; } - // TODO(turbofan): Select the correct X -> Float32 operator. - return TypeError(node, output_type, kRepFloat32); + // Select the correct X -> Float32 operator. + const Operator* op; + if (output_type & kRepBit) { + return TypeError(node, output_type, kRepFloat32); + } else if (output_type & rWord) { + if (output_type & kTypeUint32) { + op = machine()->ChangeUint32ToFloat64(); + } else { + 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()->ChangeFloat32ToFloat64(); + } else { + return TypeError(node, output_type, kRepFloat32); + } + return jsgraph()->graph()->NewNode(op, node); } Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type) { @@ -143,6 +177,8 @@ class RepresentationChanger { } case IrOpcode::kFloat64Constant: return node; // No change necessary. + case IrOpcode::kFloat32Constant: + return jsgraph()->Float64Constant(OpParameter(node)); default: break; } @@ -166,6 +202,18 @@ class RepresentationChanger { return jsgraph()->graph()->NewNode(op, node); } + Node* MakeInt32Constant(double value) { + if (value < 0) { + DCHECK(IsInt32Double(value)); + int32_t iv = static_cast(value); + return jsgraph()->Int32Constant(iv); + } else { + DCHECK(IsUint32Double(value)); + int32_t iv = static_cast(static_cast(value)); + return jsgraph()->Int32Constant(iv); + } + } + Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type, bool use_unsigned) { // Eagerly fold representation changes for constants. @@ -173,18 +221,10 @@ class RepresentationChanger { case IrOpcode::kInt32Constant: return node; // No change necessary. case IrOpcode::kNumberConstant: - case IrOpcode::kFloat64Constant: { - double value = OpParameter(node); - if (value < 0) { - DCHECK(IsInt32Double(value)); - int32_t iv = static_cast(value); - return jsgraph()->Int32Constant(iv); - } else { - DCHECK(IsUint32Double(value)); - int32_t iv = static_cast(static_cast(value)); - return jsgraph()->Int32Constant(iv); - } - } + case IrOpcode::kFloat32Constant: + return MakeInt32Constant(OpParameter(node)); + case IrOpcode::kFloat64Constant: + return MakeInt32Constant(OpParameter(node)); default: break; } @@ -196,6 +236,13 @@ class RepresentationChanger { } else { op = machine()->ChangeFloat64ToInt32(); } + } else if (output_type & kRepFloat32) { + node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 + if (output_type & kTypeUint32 || use_unsigned) { + op = machine()->ChangeFloat64ToUint32(); + } else { + op = machine()->ChangeFloat64ToInt32(); + } } else if (output_type & kRepTagged) { if (output_type & kTypeUint32 || use_unsigned) { op = simplified()->ChangeTaggedToUint32(); @@ -367,6 +414,11 @@ class RepresentationChanger { return node; } + Node* InsertChangeFloat32ToFloat64(Node* node) { + return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), + node); + } + JSGraph* jsgraph() { return jsgraph_; } Isolate* isolate() { return isolate_; } SimplifiedOperatorBuilder* simplified() { return simplified_; } diff --git a/test/cctest/compiler/test-representation-change.cc b/test/cctest/compiler/test-representation-change.cc index b49157e..24e47a8 100644 --- a/test/cctest/compiler/test-representation-change.cc +++ b/test/cctest/compiler/test-representation-change.cc @@ -88,7 +88,6 @@ class RepresentationChangerTester : public HandleAndZoneScope, } // namespace v8::internal::compiler -// TODO(titzer): add kRepFloat32 when fully supported. static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64, kRepFloat32, kRepFloat64, kRepTagged}; @@ -148,6 +147,13 @@ TEST(ToTagged_constant) { r.CheckNumberConstant(c, double_inputs[i]); } + for (size_t i = 0; i < arraysize(double_inputs); i++) { + volatile float fval = static_cast(double_inputs[i]); + Node* n = r.jsgraph()->Float32Constant(fval); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepTagged); + r.CheckNumberConstant(c, fval); + } + for (size_t i = 0; i < arraysize(int32_inputs); i++) { Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]); Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, @@ -177,6 +183,23 @@ static void CheckChange(IrOpcode::Value expected, MachineTypeUnion from, } +static void CheckTwoChanges(IrOpcode::Value expected2, + IrOpcode::Value expected1, MachineTypeUnion from, + MachineTypeUnion to) { + RepresentationChangerTester r; + + Node* n = r.Parameter(); + Node* c1 = r.changer()->GetRepresentationFor(n, from, to); + + CHECK_NE(c1, n); + CHECK_EQ(expected1, c1->opcode()); + Node* c2 = c1->InputAt(0); + CHECK_NE(c2, n); + CHECK_EQ(expected2, c2->opcode()); + CHECK_EQ(n, c2->InputAt(0)); +} + + TEST(SingleChanges) { CheckChange(IrOpcode::kChangeBoolToBit, kRepTagged, kRepBit); CheckChange(IrOpcode::kChangeBitToBool, kRepBit, kRepTagged); @@ -202,9 +225,32 @@ TEST(SingleChanges) { kRepWord32); CheckChange(IrOpcode::kChangeFloat64ToUint32, kRepFloat64 | kTypeUint32, kRepWord32); + + // Int32,Uint32 <-> Float32 require two changes. + CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64, + IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeInt32, + kRepFloat32); + CheckTwoChanges(IrOpcode::kChangeUint32ToFloat64, + IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeUint32, + kRepFloat32); + CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, + IrOpcode::kChangeFloat64ToInt32, kRepFloat32 | kTypeInt32, + kRepWord32); + CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, + IrOpcode::kChangeFloat64ToUint32, kRepFloat32 | kTypeUint32, + kRepWord32); + + // Float32 <-> Tagged require two changes. + CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, + IrOpcode::kChangeFloat64ToTagged, kRepFloat32, kRepTagged); + CheckTwoChanges(IrOpcode::kChangeTaggedToFloat64, + IrOpcode::kTruncateFloat64ToFloat32, kRepTagged, kRepFloat32); } +// TODO(titzer): test constant folding of changes between int/float + + TEST(SignednessInWord32) { RepresentationChangerTester r; @@ -215,6 +261,11 @@ TEST(SignednessInWord32) { kRepWord32 | kTypeUint32); CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64); CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32); + + CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64, + IrOpcode::kTruncateFloat64ToFloat32, kRepWord32, kRepFloat32); + CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, + IrOpcode::kChangeFloat64ToInt32, kRepFloat32, kRepWord32); } -- 2.7.4