| Index: src/compiler/simplified-lowering.cc
|
| diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
|
| index a5cf0be302bc6367b858622d49b037416b0c4c3f..931f87340fdc687b74c13657bf0ab432d9564a81 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,165 @@ 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()->ChangeSmiToInt32(), 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()->ChangeSmiToInt32(), 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()->ChangeSmiToInt32(), 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()->ChangeSmiToInt32(), 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 +2347,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::kNoProperties);
|
| + to_number_operator_.set(common()->Call(desc));
|
| + }
|
| + return to_number_operator_.get();
|
| +}
|
| +
|
| } // namespace compiler
|
| } // namespace internal
|
| } // namespace v8
|
|
|