Index: src/compiler/simplified-lowering.cc |
diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc |
index a5cf0be302bc6367b858622d49b037416b0c4c3f..7cd4a6274bc49e0e197ce815fecd5007a551aadd 100644 |
--- a/src/compiler/simplified-lowering.cc |
+++ b/src/compiler/simplified-lowering.cc |
@@ -8,6 +8,7 @@ |
#include "src/base/bits.h" |
#include "src/code-factory.h" |
+#include "src/compiler/access-builder.h" |
#include "src/compiler/common-operator.h" |
#include "src/compiler/diamond.h" |
#include "src/compiler/linkage.h" |
@@ -761,19 +762,23 @@ class RepresentationSelector { |
case IrOpcode::kCall: |
return VisitCall(node, lowering); |
-//------------------------------------------------------------------ |
-// JavaScript operators. |
-//------------------------------------------------------------------ |
-// For now, we assume that all JS operators were too complex to lower |
-// to Simplified and that they will always require tagged value inputs |
-// and produce tagged value outputs. |
-// TODO(turbofan): it might be possible to lower some JSOperators here, |
-// but that responsibility really lies in the typed lowering phase. |
-#define DEFINE_JS_CASE(x) case IrOpcode::k##x: |
- JS_OP_LIST(DEFINE_JS_CASE) |
-#undef DEFINE_JS_CASE |
+ //------------------------------------------------------------------ |
+ // JavaScript operators. |
+ //------------------------------------------------------------------ |
+ case IrOpcode::kJSToNumber: { |
VisitInputs(node); |
- return SetOutput(node, MachineRepresentation::kTagged); |
+ // TODO(bmeurer): Optimize somewhat based on input type? |
+ if (truncation.TruncatesToWord32()) { |
+ SetOutput(node, MachineRepresentation::kWord32); |
+ if (lower()) lowering->DoJSToNumberTruncatesToWord32(node, this); |
+ } else if (truncation.TruncatesToFloat64()) { |
+ SetOutput(node, MachineRepresentation::kFloat64); |
+ if (lower()) lowering->DoJSToNumberTruncatesToFloat64(node, this); |
+ } else { |
+ SetOutput(node, MachineRepresentation::kTagged); |
+ } |
+ break; |
+ } |
//------------------------------------------------------------------ |
// Simplified operators. |
@@ -1463,6 +1468,169 @@ void SimplifiedLowering::LowerAllNodes() { |
selector.Run(this); |
} |
+void SimplifiedLowering::DoJSToNumberTruncatesToFloat64( |
+ Node* node, RepresentationSelector* selector) { |
+ DCHECK_EQ(IrOpcode::kJSToNumber, node->opcode()); |
+ Node* value = node->InputAt(0); |
+ Node* context = node->InputAt(1); |
+ Node* frame_state = node->InputAt(2); |
+ Node* effect = node->InputAt(3); |
+ Node* control = node->InputAt(4); |
+ Node* throwing; |
+ |
+ Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value); |
+ Node* branch0 = |
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
+ |
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
+ Node* etrue0 = effect; |
+ Node* vtrue0; |
+ { |
+ vtrue0 = |
+ graph()->NewNode(simplified()->ChangeTaggedSignedToWord32(), value); |
+ vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0); |
+ } |
+ |
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
+ Node* efalse0 = effect; |
+ Node* vfalse0; |
+ { |
+ throwing = vfalse0 = efalse0 = |
+ graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context, |
+ frame_state, efalse0, if_false0); |
+ if_false0 = graph()->NewNode(common()->IfSuccess(), throwing); |
+ |
+ Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0); |
+ Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0); |
+ |
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
+ Node* etrue1 = efalse0; |
+ Node* vtrue1; |
+ { |
+ vtrue1 = |
+ graph()->NewNode(simplified()->ChangeTaggedSignedToWord32(), vfalse0); |
+ vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1); |
+ } |
+ |
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
+ Node* efalse1 = efalse0; |
+ Node* vfalse1; |
+ { |
+ vfalse1 = efalse1 = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0, |
+ efalse1, if_false1); |
+ } |
+ |
+ if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
+ efalse0 = |
+ graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); |
+ vfalse0 = |
+ graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
+ vtrue1, vfalse1, if_false0); |
+ } |
+ |
+ control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
+ value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), |
+ vtrue0, vfalse0, control); |
+ |
+ // Replace effect and control uses appropriately. |
+ for (Edge edge : node->use_edges()) { |
+ if (NodeProperties::IsControlEdge(edge)) { |
+ if (edge.from()->opcode() == IrOpcode::kIfSuccess) { |
+ edge.from()->ReplaceUses(control); |
+ edge.from()->Kill(); |
+ } else if (edge.from()->opcode() == IrOpcode::kIfException) { |
+ edge.UpdateTo(throwing); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ } else if (NodeProperties::IsEffectEdge(edge)) { |
+ edge.UpdateTo(effect); |
+ } |
+ } |
+ |
+ selector->DeferReplacement(node, value); |
+} |
+ |
+void SimplifiedLowering::DoJSToNumberTruncatesToWord32( |
+ Node* node, RepresentationSelector* selector) { |
+ DCHECK_EQ(IrOpcode::kJSToNumber, node->opcode()); |
+ Node* value = node->InputAt(0); |
+ Node* context = node->InputAt(1); |
+ Node* frame_state = node->InputAt(2); |
+ Node* effect = node->InputAt(3); |
+ Node* control = node->InputAt(4); |
+ Node* throwing; |
+ |
+ Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value); |
+ Node* branch0 = |
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
+ |
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
+ Node* etrue0 = effect; |
+ Node* vtrue0 = |
+ graph()->NewNode(simplified()->ChangeTaggedSignedToWord32(), value); |
+ |
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
+ Node* efalse0 = effect; |
+ Node* vfalse0; |
+ { |
+ throwing = vfalse0 = efalse0 = |
+ graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context, |
+ frame_state, efalse0, if_false0); |
+ if_false0 = graph()->NewNode(common()->IfSuccess(), throwing); |
+ |
+ Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0); |
+ Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0); |
+ |
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
+ Node* etrue1 = efalse0; |
+ Node* vtrue1 = |
+ graph()->NewNode(simplified()->ChangeTaggedSignedToWord32(), vfalse0); |
+ |
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
+ Node* efalse1 = efalse0; |
+ Node* vfalse1; |
+ { |
+ vfalse1 = efalse1 = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0, |
+ efalse1, if_false1); |
+ vfalse1 = graph()->NewNode( |
+ machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript), |
+ vfalse1); |
+ } |
+ |
+ if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
+ efalse0 = |
+ graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); |
+ vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
+ vtrue1, vfalse1, if_false0); |
+ } |
+ |
+ control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
+ value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), |
+ vtrue0, vfalse0, control); |
+ |
+ // Replace effect and control uses appropriately. |
+ for (Edge edge : node->use_edges()) { |
+ if (NodeProperties::IsControlEdge(edge)) { |
+ if (edge.from()->opcode() == IrOpcode::kIfSuccess) { |
+ edge.from()->ReplaceUses(control); |
+ edge.from()->Kill(); |
+ } else if (edge.from()->opcode() == IrOpcode::kIfException) { |
+ edge.UpdateTo(throwing); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ } else if (NodeProperties::IsEffectEdge(edge)) { |
+ edge.UpdateTo(effect); |
+ } |
+ } |
+ |
+ selector->DeferReplacement(node, value); |
+} |
void SimplifiedLowering::DoLoadBuffer(Node* node, |
MachineRepresentation output_rep, |
@@ -2183,6 +2351,26 @@ void SimplifiedLowering::DoShift(Node* node, Operator const* op, |
NodeProperties::ChangeOp(node, op); |
} |
+Node* SimplifiedLowering::ToNumberCode() { |
+ if (!to_number_code_.is_set()) { |
+ Callable callable = CodeFactory::ToNumber(isolate()); |
+ to_number_code_.set(jsgraph()->HeapConstant(callable.code())); |
+ } |
+ return to_number_code_.get(); |
+} |
+ |
+Operator const* SimplifiedLowering::ToNumberOperator() { |
+ if (!to_number_operator_.is_set()) { |
+ Callable callable = CodeFactory::ToNumber(isolate()); |
+ CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; |
+ CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
+ isolate(), graph()->zone(), callable.descriptor(), 0, flags, |
+ Operator::kIdempotent); |
+ to_number_operator_.set(common()->Call(desc)); |
+ } |
+ return to_number_operator_.get(); |
+} |
+ |
} // namespace compiler |
} // namespace internal |
} // namespace v8 |