| 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 | 
|  |