blob: fcd702c428ffb8a343fce6560efdece8280bc61f [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/branch-elimination.h"
6#include "src/compiler/js-graph.h"
7#include "src/compiler/linkage.h"
8#include "src/compiler/node-properties.h"
9#include "test/unittests/compiler/compiler-test-utils.h"
10#include "test/unittests/compiler/graph-unittest.h"
11#include "test/unittests/compiler/node-test-utils.h"
12#include "testing/gmock-support.h"
13
14namespace v8 {
15namespace internal {
16namespace compiler {
17
18class BranchEliminationTest : public TypedGraphTest {
19 public:
20 BranchEliminationTest()
21 : machine_(zone(), MachineType::PointerRepresentation(),
22 MachineOperatorBuilder::kNoFlags) {}
23
24 MachineOperatorBuilder* machine() { return &machine_; }
25
26 void Reduce() {
27 JSOperatorBuilder javascript(zone());
28 JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
29 machine());
30 GraphReducer graph_reducer(zone(), graph(), jsgraph.Dead());
31 BranchElimination branch_condition_elimination(&graph_reducer, &jsgraph,
32 zone());
33 graph_reducer.AddReducer(&branch_condition_elimination);
34 graph_reducer.ReduceGraph();
35 }
36
37 private:
38 MachineOperatorBuilder machine_;
39};
40
41
42TEST_F(BranchEliminationTest, NestedBranchSameTrue) {
43 // { return (x ? (x ? 1 : 2) : 3; }
44 // should be reduced to
45 // { return (x ? 1 : 3; }
46 Node* condition = Parameter(0);
47 Node* outer_branch =
48 graph()->NewNode(common()->Branch(), condition, graph()->start());
49
50 Node* outer_if_true = graph()->NewNode(common()->IfTrue(), outer_branch);
51 Node* inner_branch =
52 graph()->NewNode(common()->Branch(), condition, outer_if_true);
53 Node* inner_if_true = graph()->NewNode(common()->IfTrue(), inner_branch);
54 Node* inner_if_false = graph()->NewNode(common()->IfFalse(), inner_branch);
55 Node* inner_merge =
56 graph()->NewNode(common()->Merge(2), inner_if_true, inner_if_false);
57 Node* inner_phi =
58 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
59 Int32Constant(1), Int32Constant(2), inner_merge);
60
61 Node* outer_if_false = graph()->NewNode(common()->IfFalse(), outer_branch);
62 Node* outer_merge =
63 graph()->NewNode(common()->Merge(2), inner_merge, outer_if_false);
64 Node* outer_phi =
65 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
66 inner_phi, Int32Constant(3), outer_merge);
67
68 Node* ret = graph()->NewNode(common()->Return(), outer_phi, graph()->start(),
69 outer_merge);
70 graph()->SetEnd(graph()->NewNode(common()->End(1), ret));
71
72 Reduce();
73
74 // Outer branch should not be rewritten, the inner branch should be discarded.
75 EXPECT_THAT(outer_branch, IsBranch(condition, graph()->start()));
76 EXPECT_THAT(inner_phi,
77 IsPhi(MachineRepresentation::kWord32, IsInt32Constant(1),
78 IsInt32Constant(2), IsMerge(outer_if_true, IsDead())));
79}
80
81
82TEST_F(BranchEliminationTest, NestedBranchSameFalse) {
83 // { return (x ? 1 : (x ? 2 : 3); }
84 // should be reduced to
85 // { return (x ? 1 : 3; }
86 Node* condition = Parameter(0);
87 Node* outer_branch =
88 graph()->NewNode(common()->Branch(), condition, graph()->start());
89
90 Node* outer_if_true = graph()->NewNode(common()->IfTrue(), outer_branch);
91
92 Node* outer_if_false = graph()->NewNode(common()->IfFalse(), outer_branch);
93 Node* inner_branch =
94 graph()->NewNode(common()->Branch(), condition, outer_if_false);
95 Node* inner_if_true = graph()->NewNode(common()->IfTrue(), inner_branch);
96 Node* inner_if_false = graph()->NewNode(common()->IfFalse(), inner_branch);
97 Node* inner_merge =
98 graph()->NewNode(common()->Merge(2), inner_if_true, inner_if_false);
99 Node* inner_phi =
100 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
101 Int32Constant(2), Int32Constant(3), inner_merge);
102
103 Node* outer_merge =
104 graph()->NewNode(common()->Merge(2), outer_if_true, inner_merge);
105 Node* outer_phi =
106 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
107 Int32Constant(1), inner_phi, outer_merge);
108
109 Node* ret = graph()->NewNode(common()->Return(), outer_phi, graph()->start(),
110 outer_merge);
111 graph()->SetEnd(graph()->NewNode(common()->End(1), ret));
112
113 Reduce();
114
115 // Outer branch should not be rewritten, the inner branch should be discarded.
116 EXPECT_THAT(outer_branch, IsBranch(condition, graph()->start()));
117 EXPECT_THAT(inner_phi,
118 IsPhi(MachineRepresentation::kWord32, IsInt32Constant(2),
119 IsInt32Constant(3), IsMerge(IsDead(), outer_if_false)));
120}
121
122
123TEST_F(BranchEliminationTest, BranchAfterDiamond) {
124 // { var y = x ? 1 : 2; return y + x ? 3 : 4; }
125 // should not be reduced.
126 Node* condition = Parameter(0);
127
128 Node* branch1 =
129 graph()->NewNode(common()->Branch(), condition, graph()->start());
130 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
131 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
132 Node* merge1 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
133 Node* phi1 =
134 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
135 Int32Constant(1), Int32Constant(2), merge1);
136
137 Node* branch2 = graph()->NewNode(common()->Branch(), condition, merge1);
138 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
139 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
140 Node* merge2 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
141 Node* phi2 =
142 graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
143 Int32Constant(3), Int32Constant(4), merge1);
144
145
146 Node* add = graph()->NewNode(machine()->Int32Add(), phi1, phi2);
147 Node* ret =
148 graph()->NewNode(common()->Return(), add, graph()->start(), merge2);
149 graph()->SetEnd(graph()->NewNode(common()->End(1), ret));
150
151 Reduce();
152
153 // Outer branch should not be rewritten, the inner branch condition should
154 // be true.
155 EXPECT_THAT(branch1, IsBranch(condition, graph()->start()));
156 EXPECT_THAT(branch2, IsBranch(condition, merge1));
157}
158
159
160TEST_F(BranchEliminationTest, BranchInsideLoopSame) {
161 // if (x) while (x) { return 2; } else { return 1; }
162 // should be rewritten to
163 // if (x) while (true) { return 2; } else { return 1; }
164
165 Node* condition = Parameter(0);
166
167 Node* outer_branch =
168 graph()->NewNode(common()->Branch(), condition, graph()->start());
169 Node* outer_if_true = graph()->NewNode(common()->IfTrue(), outer_branch);
170
171
172 Node* loop = graph()->NewNode(common()->Loop(1), outer_if_true);
173 Node* effect =
174 graph()->NewNode(common()->EffectPhi(1), graph()->start(), loop);
175
176 Node* inner_branch = graph()->NewNode(common()->Branch(), condition, loop);
177
178 Node* inner_if_true = graph()->NewNode(common()->IfTrue(), inner_branch);
179 Node* ret1 = graph()->NewNode(common()->Return(), Int32Constant(2), effect,
180 inner_if_true);
181
182 Node* inner_if_false = graph()->NewNode(common()->IfFalse(), inner_branch);
183 loop->AppendInput(zone(), inner_if_false);
184 NodeProperties::ChangeOp(loop, common()->Loop(2));
185 effect->InsertInput(zone(), 1, effect);
186 NodeProperties::ChangeOp(effect, common()->EffectPhi(2));
187
188 Node* outer_if_false = graph()->NewNode(common()->IfFalse(), outer_branch);
189 Node* outer_merge =
190 graph()->NewNode(common()->Merge(2), loop, outer_if_false);
191 Node* outer_ephi = graph()->NewNode(common()->EffectPhi(2), effect,
192 graph()->start(), outer_merge);
193
194 Node* ret2 = graph()->NewNode(common()->Return(), Int32Constant(1),
195 outer_ephi, outer_merge);
196
197 Node* terminate = graph()->NewNode(common()->Terminate(), effect, loop);
198 graph()->SetEnd(graph()->NewNode(common()->End(3), ret1, ret2, terminate));
199
200 Reduce();
201
202 // Outer branch should not be rewritten, the inner branch should be discarded.
203 EXPECT_THAT(outer_branch, IsBranch(condition, graph()->start()));
204 EXPECT_THAT(ret1, IsReturn(IsInt32Constant(2), effect, loop));
205}
206
207} // namespace compiler
208} // namespace internal
209} // namespace v8