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

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

Powered by Google App Engine
This is Rietveld 408576698