Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/compiler/common-operator-reducer.cc b/src/compiler/common-operator-reducer.cc
index cf597ea..2334541 100644
--- a/src/compiler/common-operator-reducer.cc
+++ b/src/compiler/common-operator-reducer.cc
@@ -4,29 +4,354 @@
#include "src/compiler/common-operator-reducer.h"
+#include <algorithm>
+
#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
namespace v8 {
namespace internal {
namespace compiler {
+namespace {
+
+enum class Decision { kUnknown, kTrue, kFalse };
+
+Decision DecideCondition(Node* const cond) {
+ switch (cond->opcode()) {
+ case IrOpcode::kInt32Constant: {
+ Int32Matcher mcond(cond);
+ return mcond.Value() ? Decision::kTrue : Decision::kFalse;
+ }
+ case IrOpcode::kInt64Constant: {
+ Int64Matcher mcond(cond);
+ return mcond.Value() ? Decision::kTrue : Decision::kFalse;
+ }
+ case IrOpcode::kHeapConstant: {
+ HeapObjectMatcher mcond(cond);
+ return mcond.Value()->BooleanValue() ? Decision::kTrue : Decision::kFalse;
+ }
+ default:
+ return Decision::kUnknown;
+ }
+}
+
+} // namespace
+
+
+CommonOperatorReducer::CommonOperatorReducer(Editor* editor, Graph* graph,
+ CommonOperatorBuilder* common,
+ MachineOperatorBuilder* machine)
+ : AdvancedReducer(editor),
+ graph_(graph),
+ common_(common),
+ machine_(machine),
+ dead_(graph->NewNode(common->Dead())) {}
+
+
Reduction CommonOperatorReducer::Reduce(Node* node) {
switch (node->opcode()) {
+ case IrOpcode::kBranch:
+ return ReduceBranch(node);
+ case IrOpcode::kMerge:
+ return ReduceMerge(node);
case IrOpcode::kEffectPhi:
- case IrOpcode::kPhi: {
- int const input_count = node->InputCount();
- if (input_count > 1) {
- Node* const replacement = node->InputAt(0);
- for (int i = 1; i < input_count - 1; ++i) {
- if (node->InputAt(i) != replacement) return NoChange();
+ return ReduceEffectPhi(node);
+ case IrOpcode::kPhi:
+ return ReducePhi(node);
+ case IrOpcode::kReturn:
+ return ReduceReturn(node);
+ case IrOpcode::kSelect:
+ return ReduceSelect(node);
+ case IrOpcode::kGuard:
+ return ReduceGuard(node);
+ default:
+ break;
+ }
+ return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::ReduceBranch(Node* node) {
+ DCHECK_EQ(IrOpcode::kBranch, node->opcode());
+ Node* const cond = node->InputAt(0);
+ // Swap IfTrue/IfFalse on {branch} if {cond} is a BooleanNot and use the input
+ // to BooleanNot as new condition for {branch}. Note we assume that {cond} was
+ // already properly optimized before we get here (as guaranteed by the graph
+ // reduction logic).
+ if (cond->opcode() == IrOpcode::kBooleanNot) {
+ for (Node* const use : node->uses()) {
+ switch (use->opcode()) {
+ case IrOpcode::kIfTrue:
+ NodeProperties::ChangeOp(use, common()->IfFalse());
+ break;
+ case IrOpcode::kIfFalse:
+ NodeProperties::ChangeOp(use, common()->IfTrue());
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ // Update the condition of {branch}. No need to mark the uses for revisit,
+ // since we tell the graph reducer that the {branch} was changed and the
+ // graph reduction logic will ensure that the uses are revisited properly.
+ node->ReplaceInput(0, cond->InputAt(0));
+ // Negate the hint for {branch}.
+ NodeProperties::ChangeOp(
+ node, common()->Branch(NegateBranchHint(BranchHintOf(node->op()))));
+ return Changed(node);
+ }
+ Decision const decision = DecideCondition(cond);
+ if (decision == Decision::kUnknown) return NoChange();
+ Node* const control = node->InputAt(1);
+ for (Node* const use : node->uses()) {
+ switch (use->opcode()) {
+ case IrOpcode::kIfTrue:
+ Replace(use, (decision == Decision::kTrue) ? control : dead());
+ break;
+ case IrOpcode::kIfFalse:
+ Replace(use, (decision == Decision::kFalse) ? control : dead());
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ return Replace(dead());
+}
+
+
+Reduction CommonOperatorReducer::ReduceMerge(Node* node) {
+ DCHECK_EQ(IrOpcode::kMerge, node->opcode());
+ //
+ // Check if this is a merge that belongs to an unused diamond, which means
+ // that:
+ //
+ // a) the {Merge} has no {Phi} or {EffectPhi} uses, and
+ // b) the {Merge} has two inputs, one {IfTrue} and one {IfFalse}, which are
+ // both owned by the Merge, and
+ // c) and the {IfTrue} and {IfFalse} nodes point to the same {Branch}.
+ //
+ if (node->InputCount() == 2) {
+ for (Node* const use : node->uses()) {
+ if (IrOpcode::IsPhiOpcode(use->opcode())) return NoChange();
+ }
+ Node* if_true = node->InputAt(0);
+ Node* if_false = node->InputAt(1);
+ if (if_true->opcode() != IrOpcode::kIfTrue) std::swap(if_true, if_false);
+ if (if_true->opcode() == IrOpcode::kIfTrue &&
+ if_false->opcode() == IrOpcode::kIfFalse &&
+ if_true->InputAt(0) == if_false->InputAt(0) && if_true->OwnedBy(node) &&
+ if_false->OwnedBy(node)) {
+ Node* const branch = if_true->InputAt(0);
+ DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
+ DCHECK(branch->OwnedBy(if_true, if_false));
+ Node* const control = branch->InputAt(1);
+ // Mark the {branch} as {Dead}.
+ branch->TrimInputCount(0);
+ NodeProperties::ChangeOp(branch, common()->Dead());
+ return Replace(control);
+ }
+ }
+ return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) {
+ DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
+ int const input_count = node->InputCount() - 1;
+ DCHECK_LE(1, input_count);
+ Node* const merge = node->InputAt(input_count);
+ DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
+ DCHECK_EQ(input_count, merge->InputCount());
+ Node* const effect = node->InputAt(0);
+ DCHECK_NE(node, effect);
+ for (int i = 1; i < input_count; ++i) {
+ Node* const input = node->InputAt(i);
+ if (input == node) {
+ // Ignore redundant inputs.
+ DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
+ continue;
+ }
+ if (input != effect) return NoChange();
+ }
+ // We might now be able to further reduce the {merge} node.
+ Revisit(merge);
+ return Replace(effect);
+}
+
+
+Reduction CommonOperatorReducer::ReducePhi(Node* node) {
+ DCHECK_EQ(IrOpcode::kPhi, node->opcode());
+ int const input_count = node->InputCount() - 1;
+ DCHECK_LE(1, input_count);
+ Node* const merge = node->InputAt(input_count);
+ DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
+ DCHECK_EQ(input_count, merge->InputCount());
+ if (input_count == 2) {
+ Node* vtrue = node->InputAt(0);
+ Node* vfalse = node->InputAt(1);
+ Node* if_true = merge->InputAt(0);
+ Node* if_false = merge->InputAt(1);
+ if (if_true->opcode() != IrOpcode::kIfTrue) {
+ std::swap(if_true, if_false);
+ std::swap(vtrue, vfalse);
+ }
+ if (if_true->opcode() == IrOpcode::kIfTrue &&
+ if_false->opcode() == IrOpcode::kIfFalse &&
+ if_true->InputAt(0) == if_false->InputAt(0)) {
+ Node* const branch = if_true->InputAt(0);
+ // Check that the branch is not dead already.
+ if (branch->opcode() != IrOpcode::kBranch) return NoChange();
+ Node* const cond = branch->InputAt(0);
+ if (cond->opcode() == IrOpcode::kFloat32LessThan) {
+ Float32BinopMatcher mcond(cond);
+ if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+ vfalse->opcode() == IrOpcode::kFloat32Sub) {
+ Float32BinopMatcher mvfalse(vfalse);
+ if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+ // We might now be able to further reduce the {merge} node.
+ Revisit(merge);
+ return Change(node, machine()->Float32Abs(), vtrue);
+ }
}
- return Replace(replacement);
+ if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
+ machine()->Float32Min().IsSupported()) {
+ // We might now be able to further reduce the {merge} node.
+ Revisit(merge);
+ return Change(node, machine()->Float32Min().op(), vtrue, vfalse);
+ } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+ machine()->Float32Max().IsSupported()) {
+ // We might now be able to further reduce the {merge} node.
+ Revisit(merge);
+ return Change(node, machine()->Float32Max().op(), vtrue, vfalse);
+ }
+ } else if (cond->opcode() == IrOpcode::kFloat64LessThan) {
+ Float64BinopMatcher mcond(cond);
+ if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+ vfalse->opcode() == IrOpcode::kFloat64Sub) {
+ Float64BinopMatcher mvfalse(vfalse);
+ if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+ // We might now be able to further reduce the {merge} node.
+ Revisit(merge);
+ return Change(node, machine()->Float64Abs(), vtrue);
+ }
+ }
+ if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
+ machine()->Float64Min().IsSupported()) {
+ // We might now be able to further reduce the {merge} node.
+ Revisit(merge);
+ return Change(node, machine()->Float64Min().op(), vtrue, vfalse);
+ } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+ machine()->Float64Max().IsSupported()) {
+ // We might now be able to further reduce the {merge} node.
+ Revisit(merge);
+ return Change(node, machine()->Float64Max().op(), vtrue, vfalse);
+ }
+ }
+ }
+ }
+ Node* const value = node->InputAt(0);
+ DCHECK_NE(node, value);
+ for (int i = 1; i < input_count; ++i) {
+ Node* const input = node->InputAt(i);
+ if (input == node) {
+ // Ignore redundant inputs.
+ DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
+ continue;
+ }
+ if (input != value) return NoChange();
+ }
+ // We might now be able to further reduce the {merge} node.
+ Revisit(merge);
+ return Replace(value);
+}
+
+
+Reduction CommonOperatorReducer::ReduceReturn(Node* node) {
+ DCHECK_EQ(IrOpcode::kReturn, node->opcode());
+ Node* const value = node->InputAt(0);
+ Node* const effect = node->InputAt(1);
+ Node* const control = node->InputAt(2);
+ if (value->opcode() == IrOpcode::kPhi &&
+ NodeProperties::GetControlInput(value) == control &&
+ effect->opcode() == IrOpcode::kEffectPhi &&
+ NodeProperties::GetControlInput(effect) == control &&
+ control->opcode() == IrOpcode::kMerge) {
+ int const control_input_count = control->InputCount();
+ DCHECK_NE(0, control_input_count);
+ DCHECK_EQ(control_input_count, value->InputCount() - 1);
+ DCHECK_EQ(control_input_count, effect->InputCount() - 1);
+ DCHECK_EQ(IrOpcode::kEnd, graph()->end()->opcode());
+ DCHECK_NE(0, graph()->end()->InputCount());
+ for (int i = 0; i < control_input_count; ++i) {
+ // Create a new {Return} and connect it to {end}. We don't need to mark
+ // {end} as revisit, because we mark {node} as {Dead} below, which was
+ // previously connected to {end}, so we know for sure that at some point
+ // the reducer logic will visit {end} again.
+ Node* ret = graph()->NewNode(common()->Return(), value->InputAt(i),
+ effect->InputAt(i), control->InputAt(i));
+ NodeProperties::MergeControlToEnd(graph(), common(), ret);
+ }
+ // Mark the merge {control} and return {node} as {dead}.
+ Replace(control, dead());
+ return Replace(dead());
+ }
+ return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::ReduceSelect(Node* node) {
+ DCHECK_EQ(IrOpcode::kSelect, node->opcode());
+ Node* const cond = node->InputAt(0);
+ Node* const vtrue = node->InputAt(1);
+ Node* const vfalse = node->InputAt(2);
+ if (vtrue == vfalse) return Replace(vtrue);
+ switch (DecideCondition(cond)) {
+ case Decision::kTrue:
+ return Replace(vtrue);
+ case Decision::kFalse:
+ return Replace(vfalse);
+ case Decision::kUnknown:
+ break;
+ }
+ switch (cond->opcode()) {
+ case IrOpcode::kFloat32LessThan: {
+ Float32BinopMatcher mcond(cond);
+ if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+ vfalse->opcode() == IrOpcode::kFloat32Sub) {
+ Float32BinopMatcher mvfalse(vfalse);
+ if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+ return Change(node, machine()->Float32Abs(), vtrue);
+ }
+ }
+ if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
+ machine()->Float32Min().IsSupported()) {
+ return Change(node, machine()->Float32Min().op(), vtrue, vfalse);
+ } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+ machine()->Float32Max().IsSupported()) {
+ return Change(node, machine()->Float32Max().op(), vtrue, vfalse);
}
break;
}
- case IrOpcode::kSelect: {
- if (node->InputAt(1) == node->InputAt(2)) {
- return Replace(node->InputAt(1));
+ case IrOpcode::kFloat64LessThan: {
+ Float64BinopMatcher mcond(cond);
+ if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
+ vfalse->opcode() == IrOpcode::kFloat64Sub) {
+ Float64BinopMatcher mvfalse(vfalse);
+ if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
+ return Change(node, machine()->Float64Abs(), vtrue);
+ }
+ }
+ if (mcond.left().Equals(vtrue) && mcond.right().Equals(vfalse) &&
+ machine()->Float64Min().IsSupported()) {
+ return Change(node, machine()->Float64Min().op(), vtrue, vfalse);
+ } else if (mcond.left().Equals(vfalse) && mcond.right().Equals(vtrue) &&
+ machine()->Float64Max().IsSupported()) {
+ return Change(node, machine()->Float64Max().op(), vtrue, vfalse);
}
break;
}
@@ -36,6 +361,35 @@
return NoChange();
}
+
+Reduction CommonOperatorReducer::ReduceGuard(Node* node) {
+ DCHECK_EQ(IrOpcode::kGuard, node->opcode());
+ Node* const input = NodeProperties::GetValueInput(node, 0);
+ Type* const input_type = NodeProperties::GetTypeOrAny(input);
+ Type* const guard_type = OpParameter<Type*>(node);
+ if (input_type->Is(guard_type)) return Replace(input);
+ return NoChange();
+}
+
+
+Reduction CommonOperatorReducer::Change(Node* node, Operator const* op,
+ Node* a) {
+ node->ReplaceInput(0, a);
+ node->TrimInputCount(1);
+ NodeProperties::ChangeOp(node, op);
+ return Changed(node);
+}
+
+
+Reduction CommonOperatorReducer::Change(Node* node, Operator const* op, Node* a,
+ Node* b) {
+ node->ReplaceInput(0, a);
+ node->ReplaceInput(1, b);
+ node->TrimInputCount(2);
+ NodeProperties::ChangeOp(node, op);
+ return Changed(node);
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8