Index: test/unittests/compiler/branch-elimination-unittest.cc |
diff --git a/test/unittests/compiler/branch-elimination-unittest.cc b/test/unittests/compiler/branch-elimination-unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..efa490d7ec264854932965a209ec546c5500630b |
--- /dev/null |
+++ b/test/unittests/compiler/branch-elimination-unittest.cc |
@@ -0,0 +1,204 @@ |
+// Copyright 2015 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "src/compiler/branch-elimination.h" |
+#include "src/compiler/js-graph.h" |
+#include "src/compiler/linkage.h" |
+#include "src/compiler/node-properties.h" |
+#include "test/unittests/compiler/compiler-test-utils.h" |
+#include "test/unittests/compiler/graph-unittest.h" |
+#include "test/unittests/compiler/node-test-utils.h" |
+#include "testing/gmock-support.h" |
+ |
+namespace v8 { |
+namespace internal { |
+namespace compiler { |
+ |
+class BranchEliminationTest : public TypedGraphTest { |
+ public: |
+ BranchEliminationTest() |
+ : machine_(zone(), kMachPtr, MachineOperatorBuilder::kNoFlags) {} |
+ |
+ MachineOperatorBuilder* machine() { return &machine_; } |
+ |
+ void Reduce() { |
+ JSOperatorBuilder javascript(zone()); |
+ JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr, |
+ machine()); |
+ GraphReducer graph_reducer(zone(), graph(), jsgraph.Dead()); |
+ BranchElimination branch_condition_elimination(&graph_reducer, &jsgraph, |
+ zone()); |
+ graph_reducer.AddReducer(&branch_condition_elimination); |
+ graph_reducer.ReduceGraph(); |
+ } |
+ |
+ private: |
+ MachineOperatorBuilder machine_; |
+}; |
+ |
+ |
+TEST_F(BranchEliminationTest, NestedBranchSameTrue) { |
+ // { return (x ? (x ? 1 : 2) : 3; } |
+ // should be reduced to |
+ // { return (x ? 1 : 3; } |
+ Node* condition = Parameter(0); |
+ Node* outer_branch = |
+ graph()->NewNode(common()->Branch(), condition, graph()->start()); |
+ |
+ Node* outer_if_true = graph()->NewNode(common()->IfTrue(), outer_branch); |
+ Node* inner_branch = |
+ graph()->NewNode(common()->Branch(), condition, outer_if_true); |
+ Node* inner_if_true = graph()->NewNode(common()->IfTrue(), inner_branch); |
+ Node* inner_if_false = graph()->NewNode(common()->IfFalse(), inner_branch); |
+ Node* inner_merge = |
+ graph()->NewNode(common()->Merge(2), inner_if_true, inner_if_false); |
+ Node* inner_phi = |
+ graph()->NewNode(common()->Phi(kMachInt32, 2), Int32Constant(1), |
+ Int32Constant(2), inner_merge); |
+ |
+ Node* outer_if_false = graph()->NewNode(common()->IfFalse(), outer_branch); |
+ Node* outer_merge = |
+ graph()->NewNode(common()->Merge(2), inner_merge, outer_if_false); |
+ Node* outer_phi = graph()->NewNode(common()->Phi(kMachInt32, 2), inner_phi, |
+ Int32Constant(3), outer_merge); |
+ |
+ Node* ret = graph()->NewNode(common()->Return(), outer_phi, graph()->start(), |
+ outer_merge); |
+ graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); |
+ |
+ Reduce(); |
+ |
+ // Outer branch should not be rewritten, the inner branch should be discarded. |
+ EXPECT_THAT(outer_branch, IsBranch(condition, graph()->start())); |
+ EXPECT_THAT(inner_phi, |
+ IsPhi(kMachInt32, IsInt32Constant(1), IsInt32Constant(2), |
+ IsMerge(outer_if_true, IsDead()))); |
+} |
+ |
+ |
+TEST_F(BranchEliminationTest, NestedBranchSameFalse) { |
+ // { return (x ? 1 : (x ? 2 : 3); } |
+ // should be reduced to |
+ // { return (x ? 1 : 3; } |
+ Node* condition = Parameter(0); |
+ Node* outer_branch = |
+ graph()->NewNode(common()->Branch(), condition, graph()->start()); |
+ |
+ Node* outer_if_true = graph()->NewNode(common()->IfTrue(), outer_branch); |
+ |
+ Node* outer_if_false = graph()->NewNode(common()->IfFalse(), outer_branch); |
+ Node* inner_branch = |
+ graph()->NewNode(common()->Branch(), condition, outer_if_false); |
+ Node* inner_if_true = graph()->NewNode(common()->IfTrue(), inner_branch); |
+ Node* inner_if_false = graph()->NewNode(common()->IfFalse(), inner_branch); |
+ Node* inner_merge = |
+ graph()->NewNode(common()->Merge(2), inner_if_true, inner_if_false); |
+ Node* inner_phi = |
+ graph()->NewNode(common()->Phi(kMachInt32, 2), Int32Constant(2), |
+ Int32Constant(3), inner_merge); |
+ |
+ Node* outer_merge = |
+ graph()->NewNode(common()->Merge(2), outer_if_true, inner_merge); |
+ Node* outer_phi = graph()->NewNode(common()->Phi(kMachInt32, 2), |
+ Int32Constant(1), inner_phi, outer_merge); |
+ |
+ Node* ret = graph()->NewNode(common()->Return(), outer_phi, graph()->start(), |
+ outer_merge); |
+ graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); |
+ |
+ Reduce(); |
+ |
+ // Outer branch should not be rewritten, the inner branch should be discarded. |
+ EXPECT_THAT(outer_branch, IsBranch(condition, graph()->start())); |
+ EXPECT_THAT(inner_phi, |
+ IsPhi(kMachInt32, IsInt32Constant(2), IsInt32Constant(3), |
+ IsMerge(IsDead(), outer_if_false))); |
+} |
+ |
+ |
+TEST_F(BranchEliminationTest, BranchAfterDiamond) { |
+ // { var y = x ? 1 : 2; return y + x ? 3 : 4; } |
+ // should not be reduced. |
+ Node* condition = Parameter(0); |
+ |
+ Node* branch1 = |
+ graph()->NewNode(common()->Branch(), condition, graph()->start()); |
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
+ Node* merge1 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
+ Node* phi1 = graph()->NewNode(common()->Phi(kMachInt32, 2), Int32Constant(1), |
+ Int32Constant(2), merge1); |
+ |
+ Node* branch2 = graph()->NewNode(common()->Branch(), condition, merge1); |
+ Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
+ Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
+ Node* merge2 = graph()->NewNode(common()->Merge(2), if_true2, if_false2); |
+ Node* phi2 = graph()->NewNode(common()->Phi(kMachInt32, 2), Int32Constant(3), |
+ Int32Constant(4), merge1); |
+ |
+ |
+ Node* add = graph()->NewNode(machine()->Int32Add(), phi1, phi2); |
+ Node* ret = |
+ graph()->NewNode(common()->Return(), add, graph()->start(), merge2); |
+ graph()->SetEnd(graph()->NewNode(common()->End(1), ret)); |
+ |
+ Reduce(); |
+ |
+ // Outer branch should not be rewritten, the inner branch condition should |
+ // be true. |
+ EXPECT_THAT(branch1, IsBranch(condition, graph()->start())); |
+ EXPECT_THAT(branch2, IsBranch(condition, merge1)); |
+} |
+ |
+ |
+TEST_F(BranchEliminationTest, BranchInsideLoopSame) { |
+ // if (x) while (x) { return 2; } else { return 1; } |
+ // should be rewritten to |
+ // if (x) while (true) { return 2; } else { return 1; } |
+ |
+ Node* condition = Parameter(0); |
+ |
+ Node* outer_branch = |
+ graph()->NewNode(common()->Branch(), condition, graph()->start()); |
+ Node* outer_if_true = graph()->NewNode(common()->IfTrue(), outer_branch); |
+ |
+ |
+ Node* loop = graph()->NewNode(common()->Loop(1), outer_if_true); |
+ Node* effect = |
+ graph()->NewNode(common()->EffectPhi(1), graph()->start(), loop); |
+ |
+ Node* inner_branch = graph()->NewNode(common()->Branch(), condition, loop); |
+ |
+ Node* inner_if_true = graph()->NewNode(common()->IfTrue(), inner_branch); |
+ Node* ret1 = graph()->NewNode(common()->Return(), Int32Constant(2), effect, |
+ inner_if_true); |
+ |
+ Node* inner_if_false = graph()->NewNode(common()->IfFalse(), inner_branch); |
+ loop->AppendInput(zone(), inner_if_false); |
+ NodeProperties::ChangeOp(loop, common()->Loop(2)); |
+ effect->InsertInput(zone(), 1, effect); |
+ NodeProperties::ChangeOp(effect, common()->EffectPhi(2)); |
+ |
+ Node* outer_if_false = graph()->NewNode(common()->IfFalse(), outer_branch); |
+ Node* outer_merge = |
+ graph()->NewNode(common()->Merge(2), loop, outer_if_false); |
+ Node* outer_ephi = graph()->NewNode(common()->EffectPhi(2), effect, |
+ graph()->start(), outer_merge); |
+ |
+ Node* ret2 = graph()->NewNode(common()->Return(), Int32Constant(1), |
+ outer_ephi, outer_merge); |
+ |
+ Node* terminate = graph()->NewNode(common()->Terminate(), effect, loop); |
+ graph()->SetEnd(graph()->NewNode(common()->End(3), ret1, ret2, terminate)); |
+ |
+ Reduce(); |
+ |
+ // Outer branch should not be rewritten, the inner branch should be discarded. |
+ EXPECT_THAT(outer_branch, IsBranch(condition, graph()->start())); |
+ EXPECT_THAT(ret1, IsReturn(IsInt32Constant(2), effect, loop)); |
+} |
+ |
+} // namespace compiler |
+} // namespace internal |
+} // namespace v8 |