blob: 30a648d764f11be0a124cbda66316cf3a60f17e6 [file] [log] [blame]
Nicolas Geoffray15bd2282016-01-05 15:55:41 +00001# Copyright (C) 2015 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15.class public LIrreducibleLoop;
16
17.super Ljava/lang/Object;
18
19# Back-edges in the ascii-art graphs are represented with dash '-'.
20
21# Test that we support a simple irreducible loop.
22#
23# entry
24# / \
25# / \
26# loop_entry \
27# / \- \
28# exit \- \
29# other_loop_entry
30#
31## CHECK-START: int IrreducibleLoop.simpleLoop(int) dead_code_elimination (before)
32## CHECK: irreducible:true
33.method public static simpleLoop(I)I
34 .registers 2
35 const/16 v0, 42
36 if-eq v1, v0, :other_loop_entry
37 :loop_entry
38 if-ne v1, v0, :exit
39 add-int v0, v0, v0
40 :other_loop_entry
41 add-int v0, v0, v0
42 goto :loop_entry
43 :exit
44 return v0
45.end method
46
47# Test that lse does not wrongly optimize loads in irreducible loops. At the
48# SSA level, since we create redundant phis for irreducible loop headers, lse
49# does not see the relation between the dex register and the phi.
50#
51# entry
52# p1
53# / \
54# / \
55# / \
56# / \
57# loop_pre_entry \
58# set 42 in p1:myField \
59# / \
60# loop_entry \
61# get p1.myField \
62# / \- \
63# exit \- \
64# \- \
65# other_loop_entry
66# set 30 in p1:myField
67#
68## CHECK-START: int IrreducibleLoop.lse(int, Main) dead_code_elimination (after)
69## CHECK: irreducible:true
70#
71## CHECK-START: int IrreducibleLoop.lse(int, Main) load_store_elimination (after)
72## CHECK: InstanceFieldGet
73.method public static lse(ILMain;)I
74 .registers 4
75 const/16 v0, 42
76 const/16 v1, 30
77 if-eq p0, v0, :other_loop_pre_entry
78 goto: loop_pre_entry
79 :loop_pre_entry
80 iput v0, p1, LMain;->myField:I
81 :loop_entry
82 if-ne v1, v0, :exit
83 :other_loop_entry
84 iget v0, p1, LMain;->myField:I
85 if-eq v1, v0, :exit
86 goto :loop_entry
87 :exit
88 return v0
89 :other_loop_pre_entry
90 iput v1, p1, LMain;->myField:I
91 goto :other_loop_entry
92.end method
93
94# Check that if a irreducible loop entry is dead, the loop can become
95# natural.
96# We start with:
97#
98# entry
99# / \
100# / \
101# loop_entry \
102# / \- \
103# exit \- \
104# other_loop_entry
105#
106## CHECK-START: int IrreducibleLoop.dce(int) dead_code_elimination (before)
107## CHECK: irreducible:true
108
109# And end with:
110#
111# entry
112# /
113# /
114# loop_entry
115# / \-
116# exit \-
117# other_loop_entry
118
119## CHECK-START: int IrreducibleLoop.dce(int) dead_code_elimination (after)
120## CHECK-NOT: irreducible:true
121.method public static dce(I)I
122 .registers 3
123 const/16 v0, 42
124 const/16 v1, 168
125 if-ne v0, v0, :other_loop_pre_entry
126 :loop_entry
127 if-ne v0, v0, :exit
128 add-int v0, v0, v0
129 :other_loop_entry
130 add-int v0, v0, v0
131 if-eq v0, v1, :exit
132 goto :loop_entry
133 :exit
134 return v0
135 :other_loop_pre_entry
136 add-int v0, v0, v0
137 goto :other_loop_entry
138.end method
139
140# Check that a dex register only used in the loop header remains live thanks
141# to the (redundant) Phi created at the loop header for it.
142#
143# entry
144# p0
145# / \
146# / \
147# / \
148# loop_entry \
149# i0 = phi(p0,i1) \
150# / \- \
151# exit \- \
152# other_loop_entry
153# i1 = phi(p0, i0)
154#
155## CHECK-START: int IrreducibleLoop.liveness(int) liveness (after)
156## CHECK-DAG: <<Arg:i\d+>> ParameterValue liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopPhiUse:\d+>>)}
157## CHECK-DAG: <<LoopPhi:i\d+>> Phi [<<Arg>>,<<PhiInLoop:i\d+>>] liveness:<<ArgLoopPhiUse>> ranges:{[<<ArgLoopPhiUse>>,<<PhiInLoopUse:\d+>>)}
158## CHECK-DAG: <<PhiInLoop>> Phi [<<Arg>>,<<LoopPhi>>] liveness:<<PhiInLoopUse>> ranges:{[<<PhiInLoopUse>>,<<BackEdgeLifetimeEnd:\d+>>)}
159## CHECK: Return liveness:<<ReturnLiveness:\d+>>
160## CHECK-EVAL: <<ReturnLiveness>> == <<BackEdgeLifetimeEnd>> + 2
161.method public static liveness(I)I
162 .registers 2
163 const/16 v0, 42
164 if-eq p0, v0, :other_loop_entry
165 :loop_entry
166 add-int v0, v0, p0
167 if-ne v1, v0, :exit
168 :other_loop_entry
169 add-int v0, v0, v0
170 goto :loop_entry
171 :exit
172 return v0
173.end method
174
175# Check that we don't GVN across irreducible loops:
176# "const-class 1" in loop_entry should not be GVN with
177# "const-class 1" in entry.
178#
179# entry
180# const-class 1
181# / \
182# / \
183# loop_entry \
184# const-class 1 \
185# / \- \
186# exit \- \
187# other_loop_entry
188# const-class 2
189#
190## CHECK-START: java.lang.Class IrreducibleLoop.gvn() GVN (before)
191## CHECK: LoadClass
192## CHECK: LoadClass
193## CHECK: LoadClass
194## CHECK-NOT: LoadClass
195
196## CHECK-START: java.lang.Class IrreducibleLoop.gvn() GVN (after)
197## CHECK: LoadClass
198## CHECK: LoadClass
199## CHECK: LoadClass
200## CHECK-NOT: LoadClass
201
202.method public static gvn()Ljava/lang/Class;
203 .registers 3
204 const/4 v2, 0
205 const-class v0, LMain;
206 if-ne v0, v2, :other_loop_entry
207 :loop_entry
208 const-class v0, LMain;
209 if-ne v0, v2, :exit
210 :other_loop_entry
211 const-class v1, LIrreducibleLoop;
212 goto :loop_entry
213 :exit
214 return-object v0
215.end method
216
217# Check that we don't LICM across irreducible loops:
218# "add" in loop_entry should not be LICMed.
219#
220# entry
221# / \
222# / \
223# loop_entry \
224# add \
225# / \- \
226# exit \- \
227# other_loop_entry
228#
229## CHECK-START: int IrreducibleLoop.licm1(int) licm (after)
230## CHECK: Add irreducible:true
231.method public static licm1(I)I
232 .registers 3
233 const/4 v0, 0
234 if-ne p0, v0, :other_loop_entry
235 :loop_entry
236 add-int v0, p0, p0
237 if-ne v0, p0, :exit
238 :other_loop_entry
239 sub-int v1, p0, p0
240 goto :loop_entry
241 :exit
242 sub-int v0, v0, p0
243 return v0
244.end method
245
246# Check that we don't LICM across irreducible loops:
247# "const-class" in loop_entry should not be LICMed.
248#
249# entry
250# / \
251# / \
252# loop_entry \
253# const-class \
254# / \- \
255# exit \- \
256# other_loop_entry
257#
258## CHECK-START: int IrreducibleLoop.licm2(int) licm (after)
259## CHECK: LoadClass irreducible:true
260.method public static licm2(I)I
261 .registers 3
262 const/4 v0, 0
263 if-ne p0, v0, :other_loop_entry
264 :loop_entry
265 const-class v1, LIrreducibleLoop;
266 if-ne v0, p0, :exit
267 :other_loop_entry
268 sub-int v1, p0, p0
269 goto :loop_entry
270 :exit
271 sub-int v0, v0, p0
272 return v0
273.end method
274
275# Check that we don't LICM in a natural loop that contains an irreducible loop:
276# "const-class" should not be LICMed.
277#
278# entry
279# |
280# loop_entry
281# const-class -------------------
282# / \ -
283# / \ -
284# exit loop_body -
285# / \ -
286# / \ -
287# irreducible_loop_entry \ -
288# - \ \ -
289# - \ \ -
290# - irreducible_loop_other_entry
291# - |
292# - |
293# ------ irreducible_loop_back_edge
294#
295## CHECK-START: int IrreducibleLoop.licm3(int, int, int) licm (after)
296## CHECK: LoadClass loop:<<OuterLoop:B\d+>> irreducible:false
297## CHECK: Goto outer_loop:<<OuterLoop>> irreducible:true
298.method public static licm3(III)I
299 .registers 4
300 :loop_entry
301 const-class v0, LIrreducibleLoop;
302 if-ne p1, p2, :exit
303 goto :loop_body
304
305 :loop_body
306 if-eq p0, p1, :irreducible_loop_entry
307 goto :irreducible_loop_other_entry
308
309 :irreducible_loop_entry
310 goto :irreducible_loop_other_entry
311
312 :irreducible_loop_other_entry
313 if-eq p0, p2, :loop_entry
314 goto :irreducible_loop_back_edge
315
316 :irreducible_loop_back_edge
317 goto :irreducible_loop_entry
318 :exit
319 return p0
320.end method
321
322# Check a loop within an irreducible loop
323#
324# entry
325# / \
326# / \
327# irreducible_loop_entry \
328# / - \ irreducible_loop_pre_other_entry
329# exit - \ /
330# - irreducible_loop_body
331# - |
332# - |
333# - loop_within_header
334# - / \-
335# - / \-
336# irreducible_loop_back_edge loop_within_back_edge
337#
338## CHECK-START: void IrreducibleLoop.analyze1(int) ssa_builder (after)
339## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true
340## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:false
341.method public static analyze1(I)V
342 .registers 1
343 if-eq p0, p0, :irreducible_loop_entry
344 goto :irreducible_loop_pre_other_entry
345
346 :irreducible_loop_entry
347 if-eq p0, p0, :exit
348 goto :irreducible_loop_body
349
350 :irreducible_loop_body
351 :loop_within_header
352 if-eq p0, p0, :irreducible_loop_back_edge
353 goto :loop_within_back_edge
354
355 :loop_within_back_edge
356 goto :loop_within_header
357
358 :irreducible_loop_back_edge
359 goto :irreducible_loop_entry
360
361 :irreducible_loop_pre_other_entry
362 goto :irreducible_loop_body
363
364 :exit
365 return-void
366.end method
367
368# Check than a loop before an irreducible loop is not part of the
369# irreducible loop.
370#
371# entry
372# |
373# |
374# loop_header
375# / \-
376# / \-
377# irreducible_loop_pre_entry loop_body
378# / \
379# / \
380# irreducible_loop_entry \
381# / \- irreducible_loop_other_pre_entry
382# / \- /
383# exit \- /
384# irreducible_loop_body
385#
386## CHECK-START: void IrreducibleLoop.analyze2(int) ssa_builder (after)
387## CHECK-DAG: Goto outer_loop:none irreducible:false
388## CHECK-DAG: Goto outer_loop:none irreducible:true
389.method public static analyze2(I)V
390 .registers 1
391 :loop_header
392 if-eq p0, p0, :irreducible_loop_pre_entry
393 goto :loop_body
394 :loop_body
395 goto :loop_header
396
397 :irreducible_loop_pre_entry
398 if-eq p0, p0, :irreducible_loop_other_pre_entry
399 goto :irreducible_loop_entry
400
401 :irreducible_loop_entry
402 if-eq p0, p0, :exit
403 goto :irreducible_loop_body
404
405 :irreducible_loop_body
406 goto :irreducible_loop_entry
407
408 :irreducible_loop_other_pre_entry
409 goto :irreducible_loop_body
410
411 :exit
412 return-void
413.end method
414
415# Check two irreducible loops, one within another.
416#
417# entry
418# / \
419# / \
420# loop1_header loop2_header
421# - | / -
422# - | / -
423# - | / -
424# - | / -
425# - loop2_body -
426# - / \ -
427# - / \ -
428# loop1_body loop2_back_edge
429# |
430# |
431# exit
432#
433## CHECK-START: void IrreducibleLoop.analyze3(int) ssa_builder (after)
434## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true
435## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:true
436.method public static analyze3(I)V
437 .registers 1
438 if-eq p0, p0, :loop2_header
439 goto :loop1_header
440
441 :loop1_header
442 goto :loop2_body
443
444 :loop2_header
445 goto :loop2_body
446
447 :loop2_body
448 if-eq p0, p0, :loop2_back_edge
449 goto :loop1_body
450
451 :loop2_back_edge
452 goto :loop2_header
453
454 :loop1_body
455 if-eq p0, p0, :exit
456 goto :loop1_header
457
458 :exit
459 return-void
460.end method
461
462# Check two irreducible loops, one within another. Almost identical
463# to analyze3 except the branches of the first 'if' are swapped, to
464# ensure the order at which we find the back edges does not matter.
465#
466# entry
467# / \
468# / \
469# loop1_header loop2_header
470# - | / -
471# - | / -
472# - | / -
473# - | / -
474# - loop2_body -
475# - / \ -
476# - / \ -
477# loop1_body loop2_back_edge
478# |
479# |
480# exit
481#
482## CHECK-START: void IrreducibleLoop.analyze4(int) ssa_builder (after)
483## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true
484## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:true
485.method public static analyze4(I)V
486 .registers 1
487 if-eq p0, p0, :loop1_header
488 goto :loop2_header
489
490 :loop1_header
491 goto :loop2_body
492
493 :loop2_header
494 goto :loop2_body
495
496 :loop2_body
497 if-eq p0, p0, :loop2_back_edge
498 goto :loop1_body
499
500 :loop2_back_edge
501 goto :loop2_header
502
503 :loop1_body
504 if-eq p0, p0, :exit
505 goto :loop1_header
506
507 :exit
508 return-void
509.end method
510
511# Check two irreducible loops, one within another. Almost identical
512# to analyze3 and analyze4, except that the inner loop exits from the
513# back edge, and not the body.
514#
515# entry
516# / \
517# / \
518# loop1_header loop2_header
519# - \ / -
520# - \ / -
521# - \ / -
522# - \ / -
523# - loop2_body -
524# - | -
525# - | -
526# - loop2_back_edge ------
527# - |
528# - |
529# ----- loop1_body
530# |
531# |
532# exit
533#
534## CHECK-START: void IrreducibleLoop.analyze5(int) ssa_builder (after)
535## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true
536## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:true
537.method public static analyze5(I)V
538 .registers 1
539 if-eq p0, p0, :loop1_header
540 goto :loop2_header
541
542 :loop1_header
543 goto :loop2_body
544
545 :loop2_header
546 goto :loop2_body
547
548 :loop2_body
549 goto :loop2_back_edge
550
551 :loop2_back_edge
552 if-eq p0, p0, :loop2_header
553 goto :loop1_body
554
555 :loop1_body
556 if-eq p0, p0, :exit
557 goto :loop1_header
558
559 :exit
560 return-void
561.end method