Index: src/compiler/common-operator-reducer.cc |
diff --git a/src/compiler/common-operator-reducer.cc b/src/compiler/common-operator-reducer.cc |
index 23b2fc16a8bc5b87d7e050c70bb4fb6e534e0b8f..35f405bf3d82f4de9e1c9ef4ceb34e3b1cf4fb40 100644 |
--- a/src/compiler/common-operator-reducer.cc |
+++ b/src/compiler/common-operator-reducer.cc |
@@ -16,8 +16,39 @@ 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<HeapObject> mcond(cond); |
+ return mcond.Value().handle()->BooleanValue() ? Decision::kTrue |
+ : Decision::kFalse; |
+ } |
+ default: |
+ return Decision::kUnknown; |
+ } |
+} |
+ |
+} // namespace |
+ |
+ |
Reduction CommonOperatorReducer::Reduce(Node* node) { |
switch (node->opcode()) { |
+ case IrOpcode::kBranch: |
+ return ReduceBranch(node); |
+ case IrOpcode::kMerge: |
+ return ReduceMerge(node); |
case IrOpcode::kEffectPhi: |
return ReduceEffectPhi(node); |
case IrOpcode::kPhi: |
@@ -31,6 +62,66 @@ Reduction CommonOperatorReducer::Reduce(Node* node) { |
} |
+Reduction CommonOperatorReducer::ReduceBranch(Node* node) { |
+ DCHECK_EQ(IrOpcode::kBranch, node->opcode()); |
+ Node* const cond = node->InputAt(0); |
+ Decision const decision = DecideCondition(cond); |
+ if (decision == Decision::kUnknown) return NoChange(); |
+ Node* const control = node->InputAt(1); |
+ node->set_op(common()->Dead()); |
+ node->TrimInputCount(0); |
+ for (Node* const use : node->uses()) { |
+ switch (use->opcode()) { |
+ case IrOpcode::kIfTrue: |
+ Replace(use, (decision == Decision::kTrue) ? control : node); |
+ break; |
+ case IrOpcode::kIfFalse: |
+ Replace(use, (decision == Decision::kFalse) ? control : node); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+ return Changed(node); |
+} |
+ |
+ |
+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->set_op(common()->Dead()); |
+ branch->TrimInputCount(0); |
+ return Replace(control); |
+ } |
+ } |
+ return NoChange(); |
+} |
+ |
+ |
Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) { |
DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); |
int const input_count = node->InputCount() - 1; |
@@ -146,11 +237,15 @@ Reduction CommonOperatorReducer::ReduceSelect(Node* node) { |
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::kHeapConstant: { |
- HeapObjectMatcher<HeapObject> mcond(cond); |
- return Replace(mcond.Value().handle()->BooleanValue() ? vtrue : vfalse); |
- } |
case IrOpcode::kFloat32LessThan: { |
Float32BinopMatcher mcond(cond); |
if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) && |