OLD | NEW |
---|---|
(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 | |
OLD | NEW |