Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(872)

Side by Side Diff: test/unittests/compiler/loop-peeling-unittest.cc

Issue 816053002: [turbofan] First version of loop peeling. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « test/unittests/compiler/graph-unittest.h ('k') | test/unittests/compiler/node-test-utils.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // 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/access-builder.h"
6 #include "src/compiler/graph.h"
7 #include "src/compiler/graph-visualizer.h"
8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/loop-peeling.h"
10 #include "src/compiler/machine-operator.h"
11 #include "src/compiler/node.h"
12 #include "src/compiler/node-properties-inl.h"
13 #include "test/unittests/compiler/compiler-test-utils.h"
14 #include "test/unittests/compiler/graph-unittest.h"
15 #include "test/unittests/compiler/node-test-utils.h"
16 #include "testing/gmock-support.h"
17
18 using testing::AllOf;
19 using testing::BitEq;
20 using testing::Capture;
21 using testing::CaptureEq;
22
23 namespace v8 {
24 namespace internal {
25 namespace compiler {
26
27 struct While {
28 Node* loop;
29 Node* branch;
30 Node* if_true;
31 Node* exit;
32 };
33
34
35 // A helper for building branches.
36 struct Branch {
37 Node* branch;
38 Node* if_true;
39 Node* if_false;
40 };
41
42
43 // A helper for building counters attached to loops.
44 struct Counter {
45 Node* base;
46 Node* inc;
47 Node* phi;
48 Node* add;
49 };
50
51
52 class LoopPeelingTest : public GraphTest {
53 public:
54 LoopPeelingTest() : GraphTest(1), machine_(zone()) {}
55 ~LoopPeelingTest() OVERRIDE {}
56
57 protected:
58 MachineOperatorBuilder machine_;
59
60 MachineOperatorBuilder* machine() { return &machine_; }
61
62 LoopTree* GetLoopTree() {
63 if (FLAG_trace_turbo_graph) {
64 OFStream os(stdout);
65 os << AsRPO(*graph());
66 }
67 Zone zone(isolate());
68 return LoopFinder::BuildLoopTree(graph(), &zone);
69 }
70
71
72 PeeledIteration* PeelOne() {
73 LoopTree* loop_tree = GetLoopTree();
74 return Peel(loop_tree, loop_tree->outer_loops()[0]);
75 }
76
77 PeeledIteration* Peel(LoopTree* loop_tree, LoopTree::Loop* loop) {
78 PeeledIteration* peeled =
79 LoopPeeler::Peel(graph(), common(), loop_tree, loop, zone());
80 if (FLAG_trace_turbo_graph) {
81 OFStream os(stdout);
82 os << AsRPO(*graph());
83 }
84 return peeled;
85 }
86
87 Node* InsertReturn(Node* val, Node* effect, Node* control) {
88 Node* r = graph()->NewNode(common()->Return(), val, effect, control);
89 graph()->SetEnd(r);
90 return r;
91 }
92
93 Node* ExpectPeeled(Node* node, PeeledIteration* iter) {
94 Node* p = iter->map(node);
95 EXPECT_NE(node, p);
96 return p;
97 }
98
99 void ExpectNotPeeled(Node* node, PeeledIteration* iter) {
100 EXPECT_EQ(node, iter->map(node));
101 }
102
103 While NewWhile(Node* cond, Node* control = nullptr) {
104 if (control == nullptr) control = start();
105 Node* loop = graph()->NewNode(common()->Loop(2), control, control);
106 Node* branch = graph()->NewNode(common()->Branch(), cond, loop);
107 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
108 Node* exit = graph()->NewNode(common()->IfFalse(), branch);
109 loop->ReplaceInput(1, if_true);
110 return {loop, branch, if_true, exit};
111 }
112
113 void Chain(While* a, Node* control) { a->loop->ReplaceInput(0, control); }
114 void Nest(While* a, While* b) {
115 b->loop->ReplaceInput(1, a->exit);
116 a->loop->ReplaceInput(0, b->if_true);
117 }
118 Node* NewPhi(While* w, Node* a, Node* b) {
119 return graph()->NewNode(common()->Phi(kMachAnyTagged, 2), a, b, w->loop);
120 }
121
122 Branch NewBranch(Node* cond, Node* control = nullptr) {
123 if (control == nullptr) control = start();
124 Node* branch = graph()->NewNode(common()->Branch(), cond, control);
125 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
126 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
127 return {branch, if_true, if_false};
128 }
129
130 Counter NewCounter(While* w, int32_t b, int32_t k) {
131 Node* base = Int32Constant(b);
132 Node* inc = Int32Constant(k);
133 Node* phi =
134 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), base, base, w->loop);
135 Node* add = graph()->NewNode(machine()->Int32Add(), phi, inc);
136 phi->ReplaceInput(1, add);
137 return {base, inc, phi, add};
138 }
139 };
140
141
142 TEST_F(LoopPeelingTest, SimpleLoop) {
143 Node* p0 = Parameter(0);
144 While w = NewWhile(p0);
145 Node* r = InsertReturn(p0, start(), w.exit);
146
147 PeeledIteration* peeled = PeelOne();
148
149 Node* br1 = ExpectPeeled(w.branch, peeled);
150 Node* if_true1 = ExpectPeeled(w.if_true, peeled);
151 Node* if_false1 = ExpectPeeled(w.exit, peeled);
152
153 EXPECT_THAT(br1, IsBranch(p0, start()));
154 EXPECT_THAT(if_true1, IsIfTrue(br1));
155 EXPECT_THAT(if_false1, IsIfFalse(br1));
156
157 EXPECT_THAT(w.loop, IsLoop(if_true1, w.if_true));
158 EXPECT_THAT(r, IsReturn(p0, start(), IsMerge(w.exit, if_false1)));
159 }
160
161
162 TEST_F(LoopPeelingTest, SimpleLoopWithCounter) {
163 Node* p0 = Parameter(0);
164 While w = NewWhile(p0);
165 Counter c = NewCounter(&w, 0, 1);
166 Node* r = InsertReturn(c.phi, start(), w.exit);
167
168 PeeledIteration* peeled = PeelOne();
169
170 Node* br1 = ExpectPeeled(w.branch, peeled);
171 Node* if_true1 = ExpectPeeled(w.if_true, peeled);
172 Node* if_false1 = ExpectPeeled(w.exit, peeled);
173
174 EXPECT_THAT(br1, IsBranch(p0, start()));
175 EXPECT_THAT(if_true1, IsIfTrue(br1));
176 EXPECT_THAT(if_false1, IsIfFalse(br1));
177 EXPECT_THAT(w.loop, IsLoop(if_true1, w.if_true));
178
179 EXPECT_THAT(peeled->map(c.add), IsInt32Add(c.base, c.inc));
180
181 Capture<Node*> merge;
182 EXPECT_THAT(
183 r, IsReturn(IsPhi(kMachAnyTagged, c.phi, c.base,
184 AllOf(CaptureEq(&merge), IsMerge(w.exit, if_false1))),
185 start(), CaptureEq(&merge)));
186 }
187
188
189 TEST_F(LoopPeelingTest, SimpleNestedLoopWithCounter_peel_outer) {
190 Node* p0 = Parameter(0);
191 While outer = NewWhile(p0);
192 While inner = NewWhile(p0);
193 Nest(&inner, &outer);
194
195 Counter c = NewCounter(&outer, 0, 1);
196 Node* r = InsertReturn(c.phi, start(), outer.exit);
197
198 PeeledIteration* peeled = PeelOne();
199
200 Node* bro = ExpectPeeled(outer.branch, peeled);
201 Node* if_trueo = ExpectPeeled(outer.if_true, peeled);
202 Node* if_falseo = ExpectPeeled(outer.exit, peeled);
203
204 EXPECT_THAT(bro, IsBranch(p0, start()));
205 EXPECT_THAT(if_trueo, IsIfTrue(bro));
206 EXPECT_THAT(if_falseo, IsIfFalse(bro));
207
208 Node* bri = ExpectPeeled(inner.branch, peeled);
209 Node* if_truei = ExpectPeeled(inner.if_true, peeled);
210 Node* if_falsei = ExpectPeeled(inner.exit, peeled);
211
212 EXPECT_THAT(bri, IsBranch(p0, ExpectPeeled(inner.loop, peeled)));
213 EXPECT_THAT(if_truei, IsIfTrue(bri));
214 EXPECT_THAT(if_falsei, IsIfFalse(bri));
215
216 EXPECT_THAT(outer.loop, IsLoop(if_falsei, inner.exit));
217 EXPECT_THAT(peeled->map(c.add), IsInt32Add(c.base, c.inc));
218
219 Capture<Node*> merge;
220 EXPECT_THAT(
221 r,
222 IsReturn(IsPhi(kMachAnyTagged, c.phi, c.base,
223 AllOf(CaptureEq(&merge), IsMerge(outer.exit, if_falseo))),
224 start(), CaptureEq(&merge)));
225 }
226
227
228 TEST_F(LoopPeelingTest, SimpleNestedLoopWithCounter_peel_inner) {
229 Node* p0 = Parameter(0);
230 While outer = NewWhile(p0);
231 While inner = NewWhile(p0);
232 Nest(&inner, &outer);
233
234 Counter c = NewCounter(&outer, 0, 1);
235 Node* r = InsertReturn(c.phi, start(), outer.exit);
236
237 LoopTree* loop_tree = GetLoopTree();
238 LoopTree::Loop* loop = loop_tree->ContainingLoop(inner.loop);
239 EXPECT_NE(nullptr, loop);
240 EXPECT_EQ(1u, loop->depth());
241
242 PeeledIteration* peeled = Peel(loop_tree, loop);
243
244 ExpectNotPeeled(outer.loop, peeled);
245 ExpectNotPeeled(outer.branch, peeled);
246 ExpectNotPeeled(outer.if_true, peeled);
247 ExpectNotPeeled(outer.exit, peeled);
248
249 Node* bri = ExpectPeeled(inner.branch, peeled);
250 Node* if_truei = ExpectPeeled(inner.if_true, peeled);
251 Node* if_falsei = ExpectPeeled(inner.exit, peeled);
252
253 EXPECT_THAT(bri, IsBranch(p0, ExpectPeeled(inner.loop, peeled)));
254 EXPECT_THAT(if_truei, IsIfTrue(bri));
255 EXPECT_THAT(if_falsei, IsIfFalse(bri));
256
257 EXPECT_THAT(outer.loop, IsLoop(start(), IsMerge(inner.exit, if_falsei)));
258 ExpectNotPeeled(c.add, peeled);
259
260 EXPECT_THAT(r, IsReturn(c.phi, start(), outer.exit));
261 }
262
263
264 TEST_F(LoopPeelingTest, SimpleInnerCounter_peel_inner) {
265 Node* p0 = Parameter(0);
266 While outer = NewWhile(p0);
267 While inner = NewWhile(p0);
268 Nest(&inner, &outer);
269 Counter c = NewCounter(&inner, 0, 1);
270 Node* phi = NewPhi(&outer, Int32Constant(11), c.phi);
271
272 Node* r = InsertReturn(phi, start(), outer.exit);
273
274 LoopTree* loop_tree = GetLoopTree();
275 LoopTree::Loop* loop = loop_tree->ContainingLoop(inner.loop);
276 EXPECT_NE(nullptr, loop);
277 EXPECT_EQ(1u, loop->depth());
278
279 PeeledIteration* peeled = Peel(loop_tree, loop);
280
281 ExpectNotPeeled(outer.loop, peeled);
282 ExpectNotPeeled(outer.branch, peeled);
283 ExpectNotPeeled(outer.if_true, peeled);
284 ExpectNotPeeled(outer.exit, peeled);
285
286 Node* bri = ExpectPeeled(inner.branch, peeled);
287 Node* if_truei = ExpectPeeled(inner.if_true, peeled);
288 Node* if_falsei = ExpectPeeled(inner.exit, peeled);
289
290 EXPECT_THAT(bri, IsBranch(p0, ExpectPeeled(inner.loop, peeled)));
291 EXPECT_THAT(if_truei, IsIfTrue(bri));
292 EXPECT_THAT(if_falsei, IsIfFalse(bri));
293
294 EXPECT_THAT(outer.loop, IsLoop(start(), IsMerge(inner.exit, if_falsei)));
295 EXPECT_THAT(peeled->map(c.add), IsInt32Add(c.base, c.inc));
296
297 Node* back = phi->InputAt(1);
298 EXPECT_THAT(back, IsPhi(kMachAnyTagged, c.phi, c.base,
299 IsMerge(inner.exit, if_falsei)));
300
301 EXPECT_THAT(phi,
302 IsPhi(kMachAnyTagged, IsInt32Constant(11), back, outer.loop));
303
304 EXPECT_THAT(r, IsReturn(phi, start(), outer.exit));
305 }
306
307
308 TEST_F(LoopPeelingTest, TwoBackedgeLoop) {
309 Node* p0 = Parameter(0);
310 Node* loop = graph()->NewNode(common()->Loop(3), start(), start(), start());
311 Branch b1 = NewBranch(p0, loop);
312 Branch b2 = NewBranch(p0, b1.if_true);
313
314 loop->ReplaceInput(1, b2.if_true);
315 loop->ReplaceInput(2, b2.if_false);
316
317 Node* r = InsertReturn(p0, start(), b1.if_false);
318
319 PeeledIteration* peeled = PeelOne();
320
321 Node* b1b = ExpectPeeled(b1.branch, peeled);
322 Node* b1t = ExpectPeeled(b1.if_true, peeled);
323 Node* b1f = ExpectPeeled(b1.if_false, peeled);
324
325 EXPECT_THAT(b1b, IsBranch(p0, start()));
326 EXPECT_THAT(ExpectPeeled(b1.if_true, peeled), IsIfTrue(b1b));
327 EXPECT_THAT(b1f, IsIfFalse(b1b));
328
329 Node* b2b = ExpectPeeled(b2.branch, peeled);
330 Node* b2t = ExpectPeeled(b2.if_true, peeled);
331 Node* b2f = ExpectPeeled(b2.if_false, peeled);
332
333 EXPECT_THAT(b2b, IsBranch(p0, b1t));
334 EXPECT_THAT(b2t, IsIfTrue(b2b));
335 EXPECT_THAT(b2f, IsIfFalse(b2b));
336
337 EXPECT_THAT(loop, IsLoop(IsMerge(b2t, b2f), b2.if_true, b2.if_false));
338 EXPECT_THAT(r, IsReturn(p0, start(), IsMerge(b1.if_false, b1f)));
339 }
340
341
342 TEST_F(LoopPeelingTest, TwoBackedgeLoopWithPhi) {
343 Node* p0 = Parameter(0);
344 Node* loop = graph()->NewNode(common()->Loop(3), start(), start(), start());
345 Branch b1 = NewBranch(p0, loop);
346 Branch b2 = NewBranch(p0, b1.if_true);
347 Node* phi =
348 graph()->NewNode(common()->Phi(kMachAnyTagged, 3), Int32Constant(0),
349 Int32Constant(1), Int32Constant(2), loop);
350
351 loop->ReplaceInput(1, b2.if_true);
352 loop->ReplaceInput(2, b2.if_false);
353
354 Node* r = InsertReturn(phi, start(), b1.if_false);
355
356 PeeledIteration* peeled = PeelOne();
357
358 Node* b1b = ExpectPeeled(b1.branch, peeled);
359 Node* b1t = ExpectPeeled(b1.if_true, peeled);
360 Node* b1f = ExpectPeeled(b1.if_false, peeled);
361
362 EXPECT_THAT(b1b, IsBranch(p0, start()));
363 EXPECT_THAT(ExpectPeeled(b1.if_true, peeled), IsIfTrue(b1b));
364 EXPECT_THAT(b1f, IsIfFalse(b1b));
365
366 Node* b2b = ExpectPeeled(b2.branch, peeled);
367 Node* b2t = ExpectPeeled(b2.if_true, peeled);
368 Node* b2f = ExpectPeeled(b2.if_false, peeled);
369
370 EXPECT_THAT(b2b, IsBranch(p0, b1t));
371 EXPECT_THAT(b2t, IsIfTrue(b2b));
372 EXPECT_THAT(b2f, IsIfFalse(b2b));
373
374 EXPECT_THAT(loop, IsLoop(IsMerge(b2t, b2f), b2.if_true, b2.if_false));
375
376 EXPECT_THAT(
377 phi, IsPhi(kMachAnyTagged, IsPhi(kMachAnyTagged, IsInt32Constant(1),
378 IsInt32Constant(2), IsMerge(b2t, b2f)),
379 IsInt32Constant(1), IsInt32Constant(2), loop));
380
381 Capture<Node*> merge;
382 EXPECT_THAT(
383 r, IsReturn(IsPhi(kMachAnyTagged, phi, IsInt32Constant(0),
384 AllOf(CaptureEq(&merge), IsMerge(b1.if_false, b1f))),
385 start(), CaptureEq(&merge)));
386 }
387
388
389 TEST_F(LoopPeelingTest, TwoBackedgeLoopWithCounter) {
390 Node* p0 = Parameter(0);
391 Node* loop = graph()->NewNode(common()->Loop(3), start(), start(), start());
392 Branch b1 = NewBranch(p0, loop);
393 Branch b2 = NewBranch(p0, b1.if_true);
394 Node* phi =
395 graph()->NewNode(common()->Phi(kMachAnyTagged, 3), Int32Constant(0),
396 Int32Constant(1), Int32Constant(2), loop);
397
398 phi->ReplaceInput(
399 1, graph()->NewNode(machine()->Int32Add(), phi, Int32Constant(1)));
400 phi->ReplaceInput(
401 2, graph()->NewNode(machine()->Int32Add(), phi, Int32Constant(2)));
402
403 loop->ReplaceInput(1, b2.if_true);
404 loop->ReplaceInput(2, b2.if_false);
405
406 Node* r = InsertReturn(phi, start(), b1.if_false);
407
408 PeeledIteration* peeled = PeelOne();
409
410 Node* b1b = ExpectPeeled(b1.branch, peeled);
411 Node* b1t = ExpectPeeled(b1.if_true, peeled);
412 Node* b1f = ExpectPeeled(b1.if_false, peeled);
413
414 EXPECT_THAT(b1b, IsBranch(p0, start()));
415 EXPECT_THAT(ExpectPeeled(b1.if_true, peeled), IsIfTrue(b1b));
416 EXPECT_THAT(b1f, IsIfFalse(b1b));
417
418 Node* b2b = ExpectPeeled(b2.branch, peeled);
419 Node* b2t = ExpectPeeled(b2.if_true, peeled);
420 Node* b2f = ExpectPeeled(b2.if_false, peeled);
421
422 EXPECT_THAT(b2b, IsBranch(p0, b1t));
423 EXPECT_THAT(b2t, IsIfTrue(b2b));
424 EXPECT_THAT(b2f, IsIfFalse(b2b));
425
426 Capture<Node*> entry;
427 EXPECT_THAT(loop, IsLoop(AllOf(CaptureEq(&entry), IsMerge(b2t, b2f)),
428 b2.if_true, b2.if_false));
429
430 Node* eval = phi->InputAt(0);
431
432 EXPECT_THAT(eval, IsPhi(kMachAnyTagged,
433 IsInt32Add(IsInt32Constant(0), IsInt32Constant(1)),
434 IsInt32Add(IsInt32Constant(0), IsInt32Constant(2)),
435 CaptureEq(&entry)));
436
437 EXPECT_THAT(phi,
438 IsPhi(kMachAnyTagged, eval, IsInt32Add(phi, IsInt32Constant(1)),
439 IsInt32Add(phi, IsInt32Constant(2)), loop));
440
441 Capture<Node*> merge;
442 EXPECT_THAT(
443 r, IsReturn(IsPhi(kMachAnyTagged, phi, IsInt32Constant(0),
444 AllOf(CaptureEq(&merge), IsMerge(b1.if_false, b1f))),
445 start(), CaptureEq(&merge)));
446 }
447
448
449 } // namespace compiler
450 } // namespace internal
451 } // namespace v8
OLDNEW
« no previous file with comments | « test/unittests/compiler/graph-unittest.h ('k') | test/unittests/compiler/node-test-utils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698