Add support for Float32 representation changes.
authortitzer@chromium.org <titzer@chromium.org>
Wed, 24 Sep 2014 11:55:07 +0000 (11:55 +0000)
committertitzer@chromium.org <titzer@chromium.org>
Wed, 24 Sep 2014 11:55:07 +0000 (11:55 +0000)
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
src/compiler/js-graph.h
src/compiler/js-typed-lowering.cc
src/compiler/representation-change.h
test/cctest/compiler/test-representation-change.cc

index 1309531..c403721 100644 (file)
@@ -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) {
index 2b2dfd1..fd3de12 100644 (file)
@@ -69,6 +69,9 @@ class JSGraph : public ZoneObject {
     return Int32Constant(bit_cast<int32_t>(value));
   }
 
+  // Creates a Float32Constant node, usually canonicalized.
+  Node* Float32Constant(float value);
+
   // Creates a Float64Constant node, usually canonicalized.
   Node* Float64Constant(double value);
 
index 8fe899c..8d4bd20 100644 (file)
@@ -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,
index e9486f3..8c1467f 100644 (file)
@@ -88,6 +88,8 @@ class RepresentationChanger {
         }
       case IrOpcode::kFloat64Constant:
         return jsgraph()->Constant(OpParameter<double>(node));
+      case IrOpcode::kFloat32Constant:
+        return jsgraph()->Constant(OpParameter<float>(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<double>(node)));
+      case IrOpcode::kInt32Constant:
+        if (output_type & kTypeUint32) {
+          uint32_t value = OpParameter<uint32_t>(node);
+          return jsgraph()->Float32Constant(value);
+        } else {
+          int32_t value = OpParameter<int32_t>(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<float>(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<int32_t>(value);
+      return jsgraph()->Int32Constant(iv);
+    } else {
+      DCHECK(IsUint32Double(value));
+      int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(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<double>(node);
-        if (value < 0) {
-          DCHECK(IsInt32Double(value));
-          int32_t iv = static_cast<int32_t>(value);
-          return jsgraph()->Int32Constant(iv);
-        } else {
-          DCHECK(IsUint32Double(value));
-          int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(value));
-          return jsgraph()->Int32Constant(iv);
-        }
-      }
+      case IrOpcode::kFloat32Constant:
+        return MakeInt32Constant(OpParameter<float>(node));
+      case IrOpcode::kFloat64Constant:
+        return MakeInt32Constant(OpParameter<double>(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_; }
index b49157e..24e47a8 100644 (file)
@@ -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<float>(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);
 }