| Index: test/unittests/compiler/branch-condition-elimination-unittest.cc
|
| diff --git a/test/unittests/compiler/branch-condition-elimination-unittest.cc b/test/unittests/compiler/branch-condition-elimination-unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..348f4df1a97e075d9f60268c175aa4f552a703a4
|
| --- /dev/null
|
| +++ b/test/unittests/compiler/branch-condition-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-condition-elimination.h"
|
| +#include "src/compiler/js-graph.h"
|
| +#include "src/compiler/linkage.h"
|
| +#include "src/compiler/node-properties.h"
|
| +#include "src/compiler/simplified-operator.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 BranchConditionEliminationTest : public TypedGraphTest {
|
| + public:
|
| + BranchConditionEliminationTest()
|
| + : machine_(zone(), kMachPtr, MachineOperatorBuilder::kNoFlags) {}
|
| +
|
| + MachineOperatorBuilder* machine() { return &machine_; }
|
| +
|
| + void Reduce() {
|
| + JSOperatorBuilder javascript(zone());
|
| + JSGraph jsgraph(isolate(), graph(), common(), &javascript, machine());
|
| + GraphReducer graph_reducer(zone(), graph(), jsgraph.Dead());
|
| + BranchConditionElimination branch_condition_elimination(&graph_reducer,
|
| + &jsgraph, zone());
|
| + graph_reducer.AddReducer(&branch_condition_elimination);
|
| + graph_reducer.ReduceGraph();
|
| + }
|
| +
|
| + private:
|
| + MachineOperatorBuilder machine_;
|
| +};
|
| +
|
| +
|
| +TEST_F(BranchConditionEliminationTest, 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(BranchConditionEliminationTest, 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(BranchConditionEliminationTest, 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(BranchConditionEliminationTest, 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
|
|
|