diff options
Diffstat (limited to 'deps/v8/test/unittests/compiler/branch-elimination-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/compiler/branch-elimination-unittest.cc | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc b/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc new file mode 100644 index 0000000000..efa490d7ec --- /dev/null +++ b/deps/v8/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 |