Line data Source code
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.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* if_false;
32 : Node* exit;
33 : };
34 :
35 :
36 : // A helper for building branches.
37 : struct Branch {
38 : Node* branch;
39 : Node* if_true;
40 : Node* if_false;
41 : };
42 :
43 :
44 : // A helper for building counters attached to loops.
45 : struct Counter {
46 : Node* base;
47 : Node* inc;
48 : Node* phi;
49 : Node* add;
50 : Node* exit_marker;
51 : };
52 :
53 :
54 : class LoopPeelingTest : public GraphTest {
55 : public:
56 20 : LoopPeelingTest() : GraphTest(1), machine_(zone()) {}
57 10 : ~LoopPeelingTest() override = default;
58 :
59 : protected:
60 : MachineOperatorBuilder machine_;
61 :
62 5 : MachineOperatorBuilder* machine() { return &machine_; }
63 :
64 10 : LoopTree* GetLoopTree() {
65 10 : if (FLAG_trace_turbo_graph) {
66 0 : StdoutStream{} << AsRPO(*graph());
67 : }
68 20 : Zone zone(isolate()->allocator(), ZONE_NAME);
69 20 : return LoopFinder::BuildLoopTree(graph(), &zone);
70 : }
71 :
72 :
73 7 : PeeledIteration* PeelOne() {
74 7 : LoopTree* loop_tree = GetLoopTree();
75 7 : LoopTree::Loop* loop = loop_tree->outer_loops()[0];
76 : LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions(),
77 : node_origins());
78 14 : EXPECT_TRUE(peeler.CanPeel(loop));
79 7 : return Peel(peeler, loop);
80 : }
81 :
82 9 : PeeledIteration* Peel(LoopPeeler peeler, LoopTree::Loop* loop) {
83 18 : EXPECT_TRUE(peeler.CanPeel(loop));
84 9 : PeeledIteration* peeled = peeler.Peel(loop);
85 9 : if (FLAG_trace_turbo_graph) {
86 0 : StdoutStream{} << AsRPO(*graph());
87 : }
88 9 : return peeled;
89 : }
90 :
91 10 : Node* InsertReturn(Node* val, Node* effect, Node* control) {
92 10 : Node* zero = graph()->NewNode(common()->Int32Constant(0));
93 10 : Node* r = graph()->NewNode(common()->Return(), zero, val, effect, control);
94 : graph()->SetEnd(r);
95 10 : return r;
96 : }
97 :
98 49 : Node* ExpectPeeled(Node* node, PeeledIteration* iter) {
99 49 : Node* p = iter->map(node);
100 49 : EXPECT_NE(node, p);
101 49 : return p;
102 : }
103 :
104 11 : void ExpectNotPeeled(Node* node, PeeledIteration* iter) {
105 22 : EXPECT_EQ(node, iter->map(node));
106 11 : }
107 :
108 8 : While NewWhile(Node* cond, Node* control = nullptr) {
109 8 : if (control == nullptr) control = start();
110 : While w;
111 16 : w.loop = graph()->NewNode(common()->Loop(2), control, control);
112 16 : w.branch = graph()->NewNode(common()->Branch(), cond, w.loop);
113 16 : w.if_true = graph()->NewNode(common()->IfTrue(), w.branch);
114 16 : w.if_false = graph()->NewNode(common()->IfFalse(), w.branch);
115 16 : w.exit = graph()->NewNode(common()->LoopExit(), w.if_false, w.loop);
116 8 : w.loop->ReplaceInput(1, w.if_true);
117 8 : return w;
118 : }
119 :
120 : void Chain(While* a, Node* control) { a->loop->ReplaceInput(0, control); }
121 : void Nest(While* a, While* b) {
122 3 : b->loop->ReplaceInput(1, a->exit);
123 3 : a->loop->ReplaceInput(0, b->if_true);
124 : }
125 1 : Node* NewPhi(While* w, Node* a, Node* b) {
126 2 : return graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), a,
127 1 : b, w->loop);
128 : }
129 :
130 9 : Branch NewBranch(Node* cond, Node* control = nullptr) {
131 : Branch b;
132 9 : if (control == nullptr) control = start();
133 18 : b.branch = graph()->NewNode(common()->Branch(), cond, control);
134 18 : b.if_true = graph()->NewNode(common()->IfTrue(), b.branch);
135 18 : b.if_false = graph()->NewNode(common()->IfFalse(), b.branch);
136 9 : return b;
137 : }
138 :
139 4 : Counter NewCounter(While* w, int32_t b, int32_t k) {
140 : Counter c;
141 4 : c.base = Int32Constant(b);
142 4 : c.inc = Int32Constant(k);
143 8 : c.phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
144 4 : c.base, c.base, w->loop);
145 8 : c.add = graph()->NewNode(machine()->Int32Add(), c.phi, c.inc);
146 4 : c.phi->ReplaceInput(1, c.add);
147 8 : c.exit_marker = graph()->NewNode(common()->LoopExitValue(), c.phi, w->exit);
148 4 : return c;
149 : }
150 : };
151 :
152 :
153 15419 : TEST_F(LoopPeelingTest, SimpleLoop) {
154 1 : Node* p0 = Parameter(0);
155 1 : While w = NewWhile(p0);
156 1 : Node* r = InsertReturn(p0, start(), w.exit);
157 :
158 1 : PeeledIteration* peeled = PeelOne();
159 :
160 1 : Node* br1 = ExpectPeeled(w.branch, peeled);
161 1 : Node* if_true1 = ExpectPeeled(w.if_true, peeled);
162 1 : Node* if_false1 = ExpectPeeled(w.if_false, peeled);
163 :
164 6 : EXPECT_THAT(br1, IsBranch(p0, start()));
165 5 : EXPECT_THAT(if_true1, IsIfTrue(br1));
166 5 : EXPECT_THAT(if_false1, IsIfFalse(br1));
167 :
168 6 : EXPECT_THAT(w.loop, IsLoop(if_true1, w.if_true));
169 9 : EXPECT_THAT(r, IsReturn(p0, start(), IsMerge(w.if_false, if_false1)));
170 1 : }
171 :
172 :
173 15419 : TEST_F(LoopPeelingTest, SimpleLoopWithCounter) {
174 1 : Node* p0 = Parameter(0);
175 1 : While w = NewWhile(p0);
176 1 : Counter c = NewCounter(&w, 0, 1);
177 1 : Node* r = InsertReturn(c.exit_marker, start(), w.exit);
178 :
179 1 : PeeledIteration* peeled = PeelOne();
180 :
181 1 : Node* br1 = ExpectPeeled(w.branch, peeled);
182 1 : Node* if_true1 = ExpectPeeled(w.if_true, peeled);
183 1 : Node* if_false1 = ExpectPeeled(w.if_false, peeled);
184 :
185 6 : EXPECT_THAT(br1, IsBranch(p0, start()));
186 5 : EXPECT_THAT(if_true1, IsIfTrue(br1));
187 5 : EXPECT_THAT(if_false1, IsIfFalse(br1));
188 6 : EXPECT_THAT(w.loop, IsLoop(if_true1, w.if_true));
189 :
190 6 : EXPECT_THAT(peeled->map(c.add), IsInt32Add(c.base, c.inc));
191 :
192 6 : EXPECT_THAT(w.exit, IsMerge(w.if_false, if_false1));
193 11 : EXPECT_THAT(
194 : r, IsReturn(IsPhi(MachineRepresentation::kTagged, c.phi, c.base, w.exit),
195 0 : start(), w.exit));
196 1 : }
197 :
198 :
199 15419 : TEST_F(LoopPeelingTest, SimpleNestedLoopWithCounter_peel_outer) {
200 1 : Node* p0 = Parameter(0);
201 1 : While outer = NewWhile(p0);
202 1 : While inner = NewWhile(p0);
203 : Nest(&inner, &outer);
204 :
205 1 : Counter c = NewCounter(&outer, 0, 1);
206 1 : Node* r = InsertReturn(c.exit_marker, start(), outer.exit);
207 :
208 1 : PeeledIteration* peeled = PeelOne();
209 :
210 1 : Node* bro = ExpectPeeled(outer.branch, peeled);
211 1 : Node* if_trueo = ExpectPeeled(outer.if_true, peeled);
212 1 : Node* if_falseo = ExpectPeeled(outer.if_false, peeled);
213 :
214 6 : EXPECT_THAT(bro, IsBranch(p0, start()));
215 5 : EXPECT_THAT(if_trueo, IsIfTrue(bro));
216 5 : EXPECT_THAT(if_falseo, IsIfFalse(bro));
217 :
218 1 : Node* bri = ExpectPeeled(inner.branch, peeled);
219 1 : Node* if_truei = ExpectPeeled(inner.if_true, peeled);
220 1 : Node* if_falsei = ExpectPeeled(inner.if_false, peeled);
221 1 : Node* exiti = ExpectPeeled(inner.exit, peeled);
222 :
223 6 : EXPECT_THAT(bri, IsBranch(p0, ExpectPeeled(inner.loop, peeled)));
224 5 : EXPECT_THAT(if_truei, IsIfTrue(bri));
225 5 : EXPECT_THAT(if_falsei, IsIfFalse(bri));
226 :
227 6 : EXPECT_THAT(outer.loop, IsLoop(exiti, inner.exit));
228 6 : EXPECT_THAT(peeled->map(c.add), IsInt32Add(c.base, c.inc));
229 :
230 : Capture<Node*> merge;
231 6 : EXPECT_THAT(outer.exit, IsMerge(outer.if_false, if_falseo));
232 11 : EXPECT_THAT(r, IsReturn(IsPhi(MachineRepresentation::kTagged, c.phi, c.base,
233 : outer.exit),
234 0 : start(), outer.exit));
235 1 : }
236 :
237 :
238 15419 : TEST_F(LoopPeelingTest, SimpleNestedLoopWithCounter_peel_inner) {
239 1 : Node* p0 = Parameter(0);
240 1 : While outer = NewWhile(p0);
241 1 : While inner = NewWhile(p0);
242 : Nest(&inner, &outer);
243 :
244 1 : Counter c = NewCounter(&outer, 0, 1);
245 1 : Node* r = InsertReturn(c.exit_marker, start(), outer.exit);
246 :
247 1 : LoopTree* loop_tree = GetLoopTree();
248 2 : LoopTree::Loop* loop = loop_tree->ContainingLoop(inner.loop);
249 1 : EXPECT_NE(nullptr, loop);
250 3 : EXPECT_EQ(1u, loop->depth());
251 :
252 : LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions(),
253 : node_origins());
254 1 : PeeledIteration* peeled = Peel(peeler, loop);
255 :
256 1 : ExpectNotPeeled(outer.loop, peeled);
257 1 : ExpectNotPeeled(outer.branch, peeled);
258 1 : ExpectNotPeeled(outer.if_true, peeled);
259 1 : ExpectNotPeeled(outer.if_false, peeled);
260 1 : ExpectNotPeeled(outer.exit, peeled);
261 :
262 1 : Node* bri = ExpectPeeled(inner.branch, peeled);
263 1 : Node* if_truei = ExpectPeeled(inner.if_true, peeled);
264 1 : Node* if_falsei = ExpectPeeled(inner.if_false, peeled);
265 :
266 6 : EXPECT_THAT(bri, IsBranch(p0, ExpectPeeled(inner.loop, peeled)));
267 5 : EXPECT_THAT(if_truei, IsIfTrue(bri));
268 5 : EXPECT_THAT(if_falsei, IsIfFalse(bri));
269 :
270 6 : EXPECT_THAT(inner.exit, IsMerge(inner.if_false, if_falsei));
271 6 : EXPECT_THAT(outer.loop, IsLoop(start(), inner.exit));
272 1 : ExpectNotPeeled(c.add, peeled);
273 :
274 7 : EXPECT_THAT(r, IsReturn(c.exit_marker, start(), outer.exit));
275 : }
276 :
277 :
278 15419 : TEST_F(LoopPeelingTest, SimpleInnerCounter_peel_inner) {
279 1 : Node* p0 = Parameter(0);
280 1 : While outer = NewWhile(p0);
281 1 : While inner = NewWhile(p0);
282 : Nest(&inner, &outer);
283 1 : Counter c = NewCounter(&inner, 0, 1);
284 1 : Node* phi = NewPhi(&outer, Int32Constant(11), c.exit_marker);
285 :
286 1 : Node* r = InsertReturn(phi, start(), outer.exit);
287 :
288 1 : LoopTree* loop_tree = GetLoopTree();
289 2 : LoopTree::Loop* loop = loop_tree->ContainingLoop(inner.loop);
290 1 : EXPECT_NE(nullptr, loop);
291 3 : EXPECT_EQ(1u, loop->depth());
292 :
293 : LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions(),
294 : node_origins());
295 1 : PeeledIteration* peeled = Peel(peeler, loop);
296 :
297 1 : ExpectNotPeeled(outer.loop, peeled);
298 1 : ExpectNotPeeled(outer.branch, peeled);
299 1 : ExpectNotPeeled(outer.if_true, peeled);
300 1 : ExpectNotPeeled(outer.if_false, peeled);
301 1 : ExpectNotPeeled(outer.exit, peeled);
302 :
303 1 : Node* bri = ExpectPeeled(inner.branch, peeled);
304 1 : Node* if_truei = ExpectPeeled(inner.if_true, peeled);
305 1 : Node* if_falsei = ExpectPeeled(inner.if_false, peeled);
306 :
307 6 : EXPECT_THAT(bri, IsBranch(p0, ExpectPeeled(inner.loop, peeled)));
308 5 : EXPECT_THAT(if_truei, IsIfTrue(bri));
309 5 : EXPECT_THAT(if_falsei, IsIfFalse(bri));
310 :
311 6 : EXPECT_THAT(inner.exit, IsMerge(inner.if_false, if_falsei));
312 6 : EXPECT_THAT(outer.loop, IsLoop(start(), inner.exit));
313 6 : EXPECT_THAT(peeled->map(c.add), IsInt32Add(c.base, c.inc));
314 :
315 8 : EXPECT_THAT(c.exit_marker,
316 0 : IsPhi(MachineRepresentation::kTagged, c.phi, c.base, inner.exit));
317 :
318 9 : EXPECT_THAT(phi, IsPhi(MachineRepresentation::kTagged, IsInt32Constant(11),
319 0 : c.exit_marker, outer.loop));
320 :
321 7 : EXPECT_THAT(r, IsReturn(phi, start(), outer.exit));
322 1 : }
323 :
324 :
325 15419 : TEST_F(LoopPeelingTest, TwoBackedgeLoop) {
326 1 : Node* p0 = Parameter(0);
327 2 : Node* loop = graph()->NewNode(common()->Loop(3), start(), start(), start());
328 1 : Branch b1 = NewBranch(p0, loop);
329 1 : Branch b2 = NewBranch(p0, b1.if_true);
330 :
331 1 : loop->ReplaceInput(1, b2.if_true);
332 1 : loop->ReplaceInput(2, b2.if_false);
333 :
334 2 : Node* exit = graph()->NewNode(common()->LoopExit(), b1.if_false, loop);
335 :
336 1 : Node* r = InsertReturn(p0, start(), exit);
337 :
338 1 : PeeledIteration* peeled = PeelOne();
339 :
340 1 : Node* b1b = ExpectPeeled(b1.branch, peeled);
341 1 : Node* b1t = ExpectPeeled(b1.if_true, peeled);
342 1 : Node* b1f = ExpectPeeled(b1.if_false, peeled);
343 :
344 6 : EXPECT_THAT(b1b, IsBranch(p0, start()));
345 5 : EXPECT_THAT(ExpectPeeled(b1.if_true, peeled), IsIfTrue(b1b));
346 5 : EXPECT_THAT(b1f, IsIfFalse(b1b));
347 :
348 1 : Node* b2b = ExpectPeeled(b2.branch, peeled);
349 1 : Node* b2t = ExpectPeeled(b2.if_true, peeled);
350 1 : Node* b2f = ExpectPeeled(b2.if_false, peeled);
351 :
352 6 : EXPECT_THAT(b2b, IsBranch(p0, b1t));
353 5 : EXPECT_THAT(b2t, IsIfTrue(b2b));
354 5 : EXPECT_THAT(b2f, IsIfFalse(b2b));
355 :
356 9 : EXPECT_THAT(loop, IsLoop(IsMerge(b2t, b2f), b2.if_true, b2.if_false));
357 6 : EXPECT_THAT(exit, IsMerge(b1.if_false, b1f));
358 7 : EXPECT_THAT(r, IsReturn(p0, start(), exit));
359 1 : }
360 :
361 :
362 15419 : TEST_F(LoopPeelingTest, TwoBackedgeLoopWithPhi) {
363 1 : Node* p0 = Parameter(0);
364 2 : Node* loop = graph()->NewNode(common()->Loop(3), start(), start(), start());
365 1 : Branch b1 = NewBranch(p0, loop);
366 1 : Branch b2 = NewBranch(p0, b1.if_true);
367 1 : Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 3),
368 : Int32Constant(0), Int32Constant(1),
369 1 : Int32Constant(2), loop);
370 :
371 1 : loop->ReplaceInput(1, b2.if_true);
372 1 : loop->ReplaceInput(2, b2.if_false);
373 :
374 2 : Node* exit = graph()->NewNode(common()->LoopExit(), b1.if_false, loop);
375 2 : Node* exit_marker = graph()->NewNode(common()->LoopExitValue(), phi, exit);
376 1 : Node* r = InsertReturn(exit_marker, start(), exit);
377 :
378 1 : PeeledIteration* peeled = PeelOne();
379 :
380 1 : Node* b1b = ExpectPeeled(b1.branch, peeled);
381 1 : Node* b1t = ExpectPeeled(b1.if_true, peeled);
382 1 : Node* b1f = ExpectPeeled(b1.if_false, peeled);
383 :
384 6 : EXPECT_THAT(b1b, IsBranch(p0, start()));
385 5 : EXPECT_THAT(ExpectPeeled(b1.if_true, peeled), IsIfTrue(b1b));
386 5 : EXPECT_THAT(b1f, IsIfFalse(b1b));
387 :
388 1 : Node* b2b = ExpectPeeled(b2.branch, peeled);
389 1 : Node* b2t = ExpectPeeled(b2.if_true, peeled);
390 1 : Node* b2f = ExpectPeeled(b2.if_false, peeled);
391 :
392 6 : EXPECT_THAT(b2b, IsBranch(p0, b1t));
393 5 : EXPECT_THAT(b2t, IsIfTrue(b2b));
394 5 : EXPECT_THAT(b2f, IsIfFalse(b2b));
395 :
396 9 : EXPECT_THAT(loop, IsLoop(IsMerge(b2t, b2f), b2.if_true, b2.if_false));
397 :
398 19 : EXPECT_THAT(phi,
399 : IsPhi(MachineRepresentation::kTagged,
400 : IsPhi(MachineRepresentation::kTagged, IsInt32Constant(1),
401 : IsInt32Constant(2), IsMerge(b2t, b2f)),
402 0 : IsInt32Constant(1), IsInt32Constant(2), loop));
403 :
404 6 : EXPECT_THAT(exit, IsMerge(b1.if_false, b1f));
405 9 : EXPECT_THAT(exit_marker, IsPhi(MachineRepresentation::kTagged, phi,
406 0 : IsInt32Constant(0), exit));
407 7 : EXPECT_THAT(r, IsReturn(exit_marker, start(), exit));
408 1 : }
409 :
410 :
411 15419 : TEST_F(LoopPeelingTest, TwoBackedgeLoopWithCounter) {
412 1 : Node* p0 = Parameter(0);
413 2 : Node* loop = graph()->NewNode(common()->Loop(3), start(), start(), start());
414 1 : Branch b1 = NewBranch(p0, loop);
415 1 : Branch b2 = NewBranch(p0, b1.if_true);
416 1 : Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 3),
417 : Int32Constant(0), Int32Constant(1),
418 1 : Int32Constant(2), loop);
419 :
420 3 : phi->ReplaceInput(
421 1 : 1, graph()->NewNode(machine()->Int32Add(), phi, Int32Constant(1)));
422 2 : phi->ReplaceInput(
423 1 : 2, graph()->NewNode(machine()->Int32Add(), phi, Int32Constant(2)));
424 :
425 1 : loop->ReplaceInput(1, b2.if_true);
426 1 : loop->ReplaceInput(2, b2.if_false);
427 :
428 2 : Node* exit = graph()->NewNode(common()->LoopExit(), b1.if_false, loop);
429 2 : Node* exit_marker = graph()->NewNode(common()->LoopExitValue(), phi, exit);
430 1 : Node* r = InsertReturn(exit_marker, start(), exit);
431 :
432 1 : PeeledIteration* peeled = PeelOne();
433 :
434 1 : Node* b1b = ExpectPeeled(b1.branch, peeled);
435 1 : Node* b1t = ExpectPeeled(b1.if_true, peeled);
436 1 : Node* b1f = ExpectPeeled(b1.if_false, peeled);
437 :
438 6 : EXPECT_THAT(b1b, IsBranch(p0, start()));
439 5 : EXPECT_THAT(ExpectPeeled(b1.if_true, peeled), IsIfTrue(b1b));
440 5 : EXPECT_THAT(b1f, IsIfFalse(b1b));
441 :
442 1 : Node* b2b = ExpectPeeled(b2.branch, peeled);
443 1 : Node* b2t = ExpectPeeled(b2.if_true, peeled);
444 1 : Node* b2f = ExpectPeeled(b2.if_false, peeled);
445 :
446 6 : EXPECT_THAT(b2b, IsBranch(p0, b1t));
447 5 : EXPECT_THAT(b2t, IsIfTrue(b2b));
448 5 : EXPECT_THAT(b2f, IsIfFalse(b2b));
449 :
450 : Capture<Node*> entry;
451 13 : EXPECT_THAT(loop, IsLoop(AllOf(CaptureEq(&entry), IsMerge(b2t, b2f)),
452 0 : b2.if_true, b2.if_false));
453 :
454 2 : Node* eval = phi->InputAt(0);
455 :
456 16 : EXPECT_THAT(eval, IsPhi(MachineRepresentation::kTagged,
457 : IsInt32Add(IsInt32Constant(0), IsInt32Constant(1)),
458 : IsInt32Add(IsInt32Constant(0), IsInt32Constant(2)),
459 0 : CaptureEq(&entry)));
460 :
461 15 : EXPECT_THAT(phi, IsPhi(MachineRepresentation::kTagged, eval,
462 : IsInt32Add(phi, IsInt32Constant(1)),
463 0 : IsInt32Add(phi, IsInt32Constant(2)), loop));
464 :
465 6 : EXPECT_THAT(exit, IsMerge(b1.if_false, b1f));
466 9 : EXPECT_THAT(exit_marker, IsPhi(MachineRepresentation::kTagged, phi,
467 0 : IsInt32Constant(0), exit));
468 7 : EXPECT_THAT(r, IsReturn(exit_marker, start(), exit));
469 1 : }
470 :
471 15419 : TEST_F(LoopPeelingTest, TwoExitLoop) {
472 1 : Node* p0 = Parameter(0);
473 2 : Node* loop = graph()->NewNode(common()->Loop(2), start(), start());
474 1 : Branch b1 = NewBranch(p0, loop);
475 1 : Branch b2 = NewBranch(p0, b1.if_true);
476 :
477 1 : loop->ReplaceInput(1, b2.if_true);
478 :
479 2 : Node* exit1 = graph()->NewNode(common()->LoopExit(), b1.if_false, loop);
480 2 : Node* exit2 = graph()->NewNode(common()->LoopExit(), b2.if_false, loop);
481 :
482 2 : Node* merge = graph()->NewNode(common()->Merge(2), exit1, exit2);
483 1 : Node* r = InsertReturn(p0, start(), merge);
484 :
485 1 : PeeledIteration* peeled = PeelOne();
486 :
487 1 : Node* b1p = ExpectPeeled(b1.branch, peeled);
488 1 : Node* if_true1p = ExpectPeeled(b1.if_true, peeled);
489 1 : Node* if_false1p = ExpectPeeled(b1.if_false, peeled);
490 :
491 1 : Node* b2p = ExpectPeeled(b2.branch, peeled);
492 1 : Node* if_true2p = ExpectPeeled(b2.if_true, peeled);
493 1 : Node* if_false2p = ExpectPeeled(b2.if_false, peeled);
494 :
495 6 : EXPECT_THAT(b1p, IsBranch(p0, start()));
496 5 : EXPECT_THAT(if_true1p, IsIfTrue(b1p));
497 5 : EXPECT_THAT(if_false1p, IsIfFalse(b1p));
498 :
499 6 : EXPECT_THAT(b2p, IsBranch(p0, if_true1p));
500 5 : EXPECT_THAT(if_true2p, IsIfTrue(b2p));
501 5 : EXPECT_THAT(if_false2p, IsIfFalse(b2p));
502 :
503 6 : EXPECT_THAT(exit1, IsMerge(b1.if_false, if_false1p));
504 6 : EXPECT_THAT(exit2, IsMerge(b2.if_false, if_false2p));
505 :
506 6 : EXPECT_THAT(loop, IsLoop(if_true2p, b2.if_true));
507 :
508 6 : EXPECT_THAT(merge, IsMerge(exit1, exit2));
509 7 : EXPECT_THAT(r, IsReturn(p0, start(), merge));
510 1 : }
511 :
512 15419 : TEST_F(LoopPeelingTest, SimpleLoopWithUnmarkedExit) {
513 1 : Node* p0 = Parameter(0);
514 1 : Node* loop = graph()->NewNode(common()->Loop(2), start(), start());
515 1 : Branch b = NewBranch(p0, loop);
516 1 : loop->ReplaceInput(1, b.if_true);
517 :
518 1 : InsertReturn(p0, start(), b.if_false);
519 :
520 : {
521 1 : LoopTree* loop_tree = GetLoopTree();
522 1 : LoopTree::Loop* loop = loop_tree->outer_loops()[0];
523 : LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions(),
524 : node_origins());
525 2 : EXPECT_FALSE(peeler.CanPeel(loop));
526 : }
527 1 : }
528 :
529 :
530 : } // namespace compiler
531 : } // namespace internal
532 9249 : } // namespace v8
|