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
This commit is contained in:
parent
50c466e883
commit
9fb5f564a9
@ -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* JSGraph::Float64Constant(double value) {
|
||||||
Node** loc = cache_.FindFloat64Constant(value);
|
Node** loc = cache_.FindFloat64Constant(value);
|
||||||
if (*loc == NULL) {
|
if (*loc == NULL) {
|
||||||
|
@ -69,6 +69,9 @@ class JSGraph : public ZoneObject {
|
|||||||
return Int32Constant(bit_cast<int32_t>(value));
|
return Int32Constant(bit_cast<int32_t>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a Float32Constant node, usually canonicalized.
|
||||||
|
Node* Float32Constant(float value);
|
||||||
|
|
||||||
// Creates a Float64Constant node, usually canonicalized.
|
// Creates a Float64Constant node, usually canonicalized.
|
||||||
Node* Float64Constant(double value);
|
Node* Float64Constant(double value);
|
||||||
|
|
||||||
|
@ -559,14 +559,6 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
|
|||||||
graph()->NewNode(simplified()->LoadElement(element_access), elements,
|
graph()->NewNode(simplified()->LoadElement(element_access), elements,
|
||||||
key, jsgraph()->Uint32Constant(length),
|
key, jsgraph()->Uint32Constant(length),
|
||||||
NodeProperties::GetEffectInput(node));
|
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 ReplaceEagerly(node, value);
|
||||||
}
|
}
|
||||||
return NoChange();
|
return NoChange();
|
||||||
@ -610,11 +602,7 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
|
|||||||
NodeProperties::GetControlInput(node));
|
NodeProperties::GetControlInput(node));
|
||||||
|
|
||||||
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
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 =
|
Node* store =
|
||||||
graph()->NewNode(simplified()->StoreElement(element_access), elements,
|
graph()->NewNode(simplified()->StoreElement(element_access), elements,
|
||||||
key, jsgraph()->Uint32Constant(length), value,
|
key, jsgraph()->Uint32Constant(length), value,
|
||||||
|
@ -88,6 +88,8 @@ class RepresentationChanger {
|
|||||||
}
|
}
|
||||||
case IrOpcode::kFloat64Constant:
|
case IrOpcode::kFloat64Constant:
|
||||||
return jsgraph()->Constant(OpParameter<double>(node));
|
return jsgraph()->Constant(OpParameter<double>(node));
|
||||||
|
case IrOpcode::kFloat32Constant:
|
||||||
|
return jsgraph()->Constant(OpParameter<float>(node));
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -103,9 +105,8 @@ class RepresentationChanger {
|
|||||||
} else {
|
} else {
|
||||||
return TypeError(node, output_type, kRepTagged);
|
return TypeError(node, output_type, kRepTagged);
|
||||||
}
|
}
|
||||||
} else if (output_type & kRepFloat32) {
|
} else if (output_type & kRepFloat32) { // float32 -> float64 -> tagged
|
||||||
node = jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(),
|
node = InsertChangeFloat32ToFloat64(node);
|
||||||
node);
|
|
||||||
op = simplified()->ChangeFloat64ToTagged();
|
op = simplified()->ChangeFloat64ToTagged();
|
||||||
} else if (output_type & kRepFloat64) {
|
} else if (output_type & kRepFloat64) {
|
||||||
op = simplified()->ChangeFloat64ToTagged();
|
op = simplified()->ChangeFloat64ToTagged();
|
||||||
@ -118,14 +119,47 @@ class RepresentationChanger {
|
|||||||
Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type) {
|
Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type) {
|
||||||
// Eagerly fold representation changes for constants.
|
// Eagerly fold representation changes for constants.
|
||||||
switch (node->opcode()) {
|
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:
|
case IrOpcode::kFloat32Constant:
|
||||||
return node; // No change necessary.
|
return node; // No change necessary.
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// TODO(turbofan): Select the correct X -> Float32 operator.
|
// Select the correct X -> Float32 operator.
|
||||||
return TypeError(node, output_type, kRepFloat32);
|
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) {
|
Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type) {
|
||||||
@ -143,6 +177,8 @@ class RepresentationChanger {
|
|||||||
}
|
}
|
||||||
case IrOpcode::kFloat64Constant:
|
case IrOpcode::kFloat64Constant:
|
||||||
return node; // No change necessary.
|
return node; // No change necessary.
|
||||||
|
case IrOpcode::kFloat32Constant:
|
||||||
|
return jsgraph()->Float64Constant(OpParameter<float>(node));
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -166,6 +202,18 @@ class RepresentationChanger {
|
|||||||
return jsgraph()->graph()->NewNode(op, node);
|
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,
|
Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type,
|
||||||
bool use_unsigned) {
|
bool use_unsigned) {
|
||||||
// Eagerly fold representation changes for constants.
|
// Eagerly fold representation changes for constants.
|
||||||
@ -173,18 +221,10 @@ class RepresentationChanger {
|
|||||||
case IrOpcode::kInt32Constant:
|
case IrOpcode::kInt32Constant:
|
||||||
return node; // No change necessary.
|
return node; // No change necessary.
|
||||||
case IrOpcode::kNumberConstant:
|
case IrOpcode::kNumberConstant:
|
||||||
case IrOpcode::kFloat64Constant: {
|
case IrOpcode::kFloat32Constant:
|
||||||
double value = OpParameter<double>(node);
|
return MakeInt32Constant(OpParameter<float>(node));
|
||||||
if (value < 0) {
|
case IrOpcode::kFloat64Constant:
|
||||||
DCHECK(IsInt32Double(value));
|
return MakeInt32Constant(OpParameter<double>(node));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -196,6 +236,13 @@ class RepresentationChanger {
|
|||||||
} else {
|
} else {
|
||||||
op = machine()->ChangeFloat64ToInt32();
|
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) {
|
} else if (output_type & kRepTagged) {
|
||||||
if (output_type & kTypeUint32 || use_unsigned) {
|
if (output_type & kTypeUint32 || use_unsigned) {
|
||||||
op = simplified()->ChangeTaggedToUint32();
|
op = simplified()->ChangeTaggedToUint32();
|
||||||
@ -367,6 +414,11 @@ class RepresentationChanger {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node* InsertChangeFloat32ToFloat64(Node* node) {
|
||||||
|
return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(),
|
||||||
|
node);
|
||||||
|
}
|
||||||
|
|
||||||
JSGraph* jsgraph() { return jsgraph_; }
|
JSGraph* jsgraph() { return jsgraph_; }
|
||||||
Isolate* isolate() { return isolate_; }
|
Isolate* isolate() { return isolate_; }
|
||||||
SimplifiedOperatorBuilder* simplified() { return simplified_; }
|
SimplifiedOperatorBuilder* simplified() { return simplified_; }
|
||||||
|
@ -88,7 +88,6 @@ class RepresentationChangerTester : public HandleAndZoneScope,
|
|||||||
} // namespace v8::internal::compiler
|
} // namespace v8::internal::compiler
|
||||||
|
|
||||||
|
|
||||||
// TODO(titzer): add kRepFloat32 when fully supported.
|
|
||||||
static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64,
|
static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64,
|
||||||
kRepFloat32, kRepFloat64, kRepTagged};
|
kRepFloat32, kRepFloat64, kRepTagged};
|
||||||
|
|
||||||
@ -148,6 +147,13 @@ TEST(ToTagged_constant) {
|
|||||||
r.CheckNumberConstant(c, double_inputs[i]);
|
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++) {
|
for (size_t i = 0; i < arraysize(int32_inputs); i++) {
|
||||||
Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]);
|
Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]);
|
||||||
Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
|
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) {
|
TEST(SingleChanges) {
|
||||||
CheckChange(IrOpcode::kChangeBoolToBit, kRepTagged, kRepBit);
|
CheckChange(IrOpcode::kChangeBoolToBit, kRepTagged, kRepBit);
|
||||||
CheckChange(IrOpcode::kChangeBitToBool, kRepBit, kRepTagged);
|
CheckChange(IrOpcode::kChangeBitToBool, kRepBit, kRepTagged);
|
||||||
@ -202,9 +225,32 @@ TEST(SingleChanges) {
|
|||||||
kRepWord32);
|
kRepWord32);
|
||||||
CheckChange(IrOpcode::kChangeFloat64ToUint32, kRepFloat64 | kTypeUint32,
|
CheckChange(IrOpcode::kChangeFloat64ToUint32, kRepFloat64 | kTypeUint32,
|
||||||
kRepWord32);
|
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) {
|
TEST(SignednessInWord32) {
|
||||||
RepresentationChangerTester r;
|
RepresentationChangerTester r;
|
||||||
|
|
||||||
@ -215,6 +261,11 @@ TEST(SignednessInWord32) {
|
|||||||
kRepWord32 | kTypeUint32);
|
kRepWord32 | kTypeUint32);
|
||||||
CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64);
|
CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64);
|
||||||
CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32);
|
CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32);
|
||||||
|
|
||||||
|
CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
|
||||||
|
IrOpcode::kTruncateFloat64ToFloat32, kRepWord32, kRepFloat32);
|
||||||
|
CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
|
||||||
|
IrOpcode::kChangeFloat64ToInt32, kRepFloat32, kRepWord32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user