xref: /llvm-project/llvm/test/Transforms/IndVarSimplify/lftr-multi-exit.ll (revision 864bb84a427de367528d15270790dd152871daf2)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=indvars -S | FileCheck %s
3; This is a collection of tests specifically for LFTR of multiple exit loops.
4; The actual LFTR performed is trivial so as to focus on the loop structure
5; aspects.
6
7; Provide legal integer types.
8target datalayout = "n8:16:32:64"
9
10@A = external global i32
11
12define void @analyzeable_early_exit(i32 %n) {
13; CHECK-LABEL: @analyzeable_early_exit(
14; CHECK-NEXT:  entry:
15; CHECK-NEXT:    br label [[LOOP:%.*]]
16; CHECK:       loop:
17; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
18; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
19; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
20; CHECK:       latch:
21; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
22; CHECK-NEXT:    store i32 [[IV]], ptr @A, align 4
23; CHECK-NEXT:    [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
24; CHECK-NEXT:    br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
25; CHECK:       exit:
26; CHECK-NEXT:    ret void
27;
28entry:
29  br label %loop
30
31loop:
32  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
33  %earlycnd = icmp ult i32 %iv, %n
34  br i1 %earlycnd, label %latch, label %exit
35
36latch:
37  %iv.next = add i32 %iv, 1
38  store i32 %iv, ptr @A
39  %c = icmp ult i32 %iv.next, 1000
40  br i1 %c, label %loop, label %exit
41
42exit:
43  ret void
44}
45
46define void @unanalyzeable_early_exit() {
47; CHECK-LABEL: @unanalyzeable_early_exit(
48; CHECK-NEXT:  entry:
49; CHECK-NEXT:    br label [[LOOP:%.*]]
50; CHECK:       loop:
51; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
52; CHECK-NEXT:    [[VOL:%.*]] = load volatile i32, ptr @A, align 4
53; CHECK-NEXT:    [[EARLYCND:%.*]] = icmp ne i32 [[VOL]], 0
54; CHECK-NEXT:    br i1 [[EARLYCND]], label [[LATCH]], label [[EXIT:%.*]]
55; CHECK:       latch:
56; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
57; CHECK-NEXT:    store i32 [[IV]], ptr @A, align 4
58; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
59; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT]]
60; CHECK:       exit:
61; CHECK-NEXT:    ret void
62;
63entry:
64  br label %loop
65
66loop:
67  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
68  %vol = load volatile i32, ptr @A
69  %earlycnd = icmp ne i32 %vol, 0
70  br i1 %earlycnd, label %latch, label %exit
71
72latch:
73  %iv.next = add i32 %iv, 1
74  store i32 %iv, ptr @A
75  %c = icmp ult i32 %iv.next, 1000
76  br i1 %c, label %loop, label %exit
77
78exit:
79  ret void
80}
81
82
83define void @multiple_early_exits(i32 %n, i32 %m) {
84; CHECK-LABEL: @multiple_early_exits(
85; CHECK-NEXT:  entry:
86; CHECK-NEXT:    br label [[LOOP:%.*]]
87; CHECK:       loop:
88; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
89; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
90; CHECK-NEXT:    br i1 [[EXITCOND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]]
91; CHECK:       continue:
92; CHECK-NEXT:    store volatile i32 [[IV]], ptr @A, align 4
93; CHECK-NEXT:    [[EXITCOND1:%.*]] = icmp ne i32 [[IV]], [[M:%.*]]
94; CHECK-NEXT:    br i1 [[EXITCOND1]], label [[LATCH]], label [[EXIT]]
95; CHECK:       latch:
96; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
97; CHECK-NEXT:    store volatile i32 [[IV]], ptr @A, align 4
98; CHECK-NEXT:    [[EXITCOND2:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
99; CHECK-NEXT:    br i1 [[EXITCOND2]], label [[LOOP]], label [[EXIT]]
100; CHECK:       exit:
101; CHECK-NEXT:    ret void
102;
103entry:
104  br label %loop
105
106loop:
107  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
108  %earlycnd = icmp ult i32 %iv, %n
109  br i1 %earlycnd, label %continue, label %exit
110
111continue:
112  store volatile i32 %iv, ptr @A
113  %earlycnd2 = icmp ult i32 %iv, %m
114  br i1 %earlycnd2, label %latch, label %exit
115
116latch:
117  %iv.next = add i32 %iv, 1
118  store volatile i32 %iv, ptr @A
119  %c = icmp ult i32 %iv.next, 1000
120  br i1 %c, label %loop, label %exit
121
122exit:
123  ret void
124}
125
126; Note: This slightly odd form is what indvars itself produces for multiple
127; exits without a side effect between them.
128define void @compound_early_exit(i32 %n, i32 %m) {
129; CHECK-LABEL: @compound_early_exit(
130; CHECK-NEXT:  entry:
131; CHECK-NEXT:    [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[M:%.*]], i32 [[N:%.*]])
132; CHECK-NEXT:    br label [[LOOP:%.*]]
133; CHECK:       loop:
134; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
135; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[UMIN]]
136; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
137; CHECK:       latch:
138; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
139; CHECK-NEXT:    store volatile i32 [[IV]], ptr @A, align 4
140; CHECK-NEXT:    [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
141; CHECK-NEXT:    br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
142; CHECK:       exit:
143; CHECK-NEXT:    ret void
144;
145entry:
146  br label %loop
147
148loop:
149  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
150  %earlycnd = icmp ult i32 %iv, %n
151  %earlycnd2 = icmp ult i32 %iv, %m
152  %and = and i1 %earlycnd, %earlycnd2
153  br i1 %and, label %latch, label %exit
154
155latch:
156  %iv.next = add i32 %iv, 1
157  store volatile i32 %iv, ptr @A
158  %c = icmp ult i32 %iv.next, 1000
159  br i1 %c, label %loop, label %exit
160
161exit:
162  ret void
163}
164
165
166define void @unanalyzeable_latch(i32 %n) {
167; CHECK-LABEL: @unanalyzeable_latch(
168; CHECK-NEXT:  entry:
169; CHECK-NEXT:    br label [[LOOP:%.*]]
170; CHECK:       loop:
171; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
172; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
173; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
174; CHECK:       latch:
175; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
176; CHECK-NEXT:    store i32 [[IV]], ptr @A, align 4
177; CHECK-NEXT:    [[VOL:%.*]] = load volatile i32, ptr @A, align 4
178; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[VOL]], 1000
179; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT]]
180; CHECK:       exit:
181; CHECK-NEXT:    ret void
182;
183entry:
184  br label %loop
185
186loop:
187  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
188  %earlycnd = icmp ult i32 %iv, %n
189  br i1 %earlycnd, label %latch, label %exit
190
191latch:
192  %iv.next = add i32 %iv, 1
193  store i32 %iv, ptr @A
194  %vol = load volatile i32, ptr @A
195  %c = icmp ult i32 %vol, 1000
196  br i1 %c, label %loop, label %exit
197
198exit:
199  ret void
200}
201
202define void @single_exit_no_latch(i32 %n) {
203; CHECK-LABEL: @single_exit_no_latch(
204; CHECK-NEXT:  entry:
205; CHECK-NEXT:    br label [[LOOP:%.*]]
206; CHECK:       loop:
207; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
208; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
209; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
210; CHECK:       latch:
211; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
212; CHECK-NEXT:    store i32 [[IV]], ptr @A, align 4
213; CHECK-NEXT:    br label [[LOOP]]
214; CHECK:       exit:
215; CHECK-NEXT:    ret void
216;
217entry:
218  br label %loop
219
220loop:
221  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
222  %earlycnd = icmp ult i32 %iv, %n
223  br i1 %earlycnd, label %latch, label %exit
224
225latch:
226  %iv.next = add i32 %iv, 1
227  store i32 %iv, ptr @A
228  br label %loop
229
230exit:
231  ret void
232}
233
234; Multiple exits which could be LFTRed, but the latch itself is not an
235; exiting block.
236define void @no_latch_exit(i32 %n, i32 %m) {
237; CHECK-LABEL: @no_latch_exit(
238; CHECK-NEXT:  entry:
239; CHECK-NEXT:    br label [[LOOP:%.*]]
240; CHECK:       loop:
241; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
242; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
243; CHECK-NEXT:    br i1 [[EXITCOND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]]
244; CHECK:       continue:
245; CHECK-NEXT:    store volatile i32 [[IV]], ptr @A, align 4
246; CHECK-NEXT:    [[EXITCOND1:%.*]] = icmp ne i32 [[IV]], [[M:%.*]]
247; CHECK-NEXT:    br i1 [[EXITCOND1]], label [[LATCH]], label [[EXIT]]
248; CHECK:       latch:
249; CHECK-NEXT:    store volatile i32 [[IV]], ptr @A, align 4
250; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
251; CHECK-NEXT:    br label [[LOOP]]
252; CHECK:       exit:
253; CHECK-NEXT:    ret void
254;
255entry:
256  br label %loop
257
258loop:
259  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
260  %earlycnd = icmp ult i32 %iv, %n
261  br i1 %earlycnd, label %continue, label %exit
262
263continue:
264  store volatile i32 %iv, ptr @A
265  %earlycnd2 = icmp ult i32 %iv, %m
266  br i1 %earlycnd2, label %latch, label %exit
267
268latch:
269  store volatile i32 %iv, ptr @A
270  %iv.next = add i32 %iv, 1
271  br label %loop
272
273exit:
274  ret void
275}
276
277;; Show the value of multiple exit LFTR (being able to eliminate all but
278;; one IV when exit tests involve multiple IVs).
279define void @combine_ivs(i32 %n) {
280; CHECK-LABEL: @combine_ivs(
281; CHECK-NEXT:  entry:
282; CHECK-NEXT:    br label [[LOOP:%.*]]
283; CHECK:       loop:
284; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
285; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
286; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
287; CHECK:       latch:
288; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
289; CHECK-NEXT:    store volatile i32 [[IV]], ptr @A, align 4
290; CHECK-NEXT:    [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 999
291; CHECK-NEXT:    br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
292; CHECK:       exit:
293; CHECK-NEXT:    ret void
294;
295entry:
296  br label %loop
297
298loop:
299  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
300  %iv2 = phi i32 [ 1, %entry], [ %iv2.next, %latch]
301  %earlycnd = icmp ult i32 %iv, %n
302  br i1 %earlycnd, label %latch, label %exit
303
304latch:
305  %iv.next = add i32 %iv, 1
306  %iv2.next = add i32 %iv2, 1
307  store volatile i32 %iv, ptr @A
308  %c = icmp ult i32 %iv2.next, 1000
309  br i1 %c, label %loop, label %exit
310
311exit:
312  ret void
313}
314
315; We can remove the decrementing IV entirely
316define void @combine_ivs2(i32 %n) {
317; CHECK-LABEL: @combine_ivs2(
318; CHECK-NEXT:  entry:
319; CHECK-NEXT:    br label [[LOOP:%.*]]
320; CHECK:       loop:
321; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
322; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
323; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
324; CHECK:       latch:
325; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
326; CHECK-NEXT:    store volatile i32 [[IV]], ptr @A, align 4
327; CHECK-NEXT:    [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
328; CHECK-NEXT:    br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
329; CHECK:       exit:
330; CHECK-NEXT:    ret void
331;
332entry:
333  br label %loop
334
335loop:
336  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
337  %iv2 = phi i32 [ 1000, %entry], [ %iv2.next, %latch]
338  %earlycnd = icmp ult i32 %iv, %n
339  br i1 %earlycnd, label %latch, label %exit
340
341latch:
342  %iv.next = add i32 %iv, 1
343  %iv2.next = sub i32 %iv2, 1
344  store volatile i32 %iv, ptr @A
345  %c = icmp ugt i32 %iv2.next, 0
346  br i1 %c, label %loop, label %exit
347
348exit:
349  ret void
350}
351
352; An example where we can eliminate an f(i) computation entirely
353; from a multiple exit loop with LFTR.
354define void @simplify_exit_test(i32 %n) {
355; CHECK-LABEL: @simplify_exit_test(
356; CHECK-NEXT:  entry:
357; CHECK-NEXT:    br label [[LOOP:%.*]]
358; CHECK:       loop:
359; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
360; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
361; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
362; CHECK:       latch:
363; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
364; CHECK-NEXT:    store volatile i32 [[IV]], ptr @A, align 4
365; CHECK-NEXT:    [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 65
366; CHECK-NEXT:    br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
367; CHECK:       exit:
368; CHECK-NEXT:    ret void
369;
370entry:
371  br label %loop
372
373loop:
374  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
375  %earlycnd = icmp ult i32 %iv, %n
376  br i1 %earlycnd, label %latch, label %exit
377
378latch:
379  %iv.next = add i32 %iv, 1
380  %fx = shl i32 %iv, 4
381  store volatile i32 %iv, ptr @A
382  %c = icmp ult i32 %fx, 1024
383  br i1 %c, label %loop, label %exit
384
385exit:
386  ret void
387}
388
389
390; Another example where we can remove an f(i) type computation, but this
391; time in a loop w/o a statically computable exit count.
392define void @simplify_exit_test2(i32 %n) {
393; CHECK-LABEL: @simplify_exit_test2(
394; CHECK-NEXT:  entry:
395; CHECK-NEXT:    br label [[LOOP:%.*]]
396; CHECK:       loop:
397; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
398; CHECK-NEXT:    [[VOL:%.*]] = load volatile i32, ptr @A, align 4
399; CHECK-NEXT:    [[EARLYCND:%.*]] = icmp ne i32 [[VOL]], 0
400; CHECK-NEXT:    br i1 [[EARLYCND]], label [[LATCH]], label [[EXIT:%.*]]
401; CHECK:       latch:
402; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
403; CHECK-NEXT:    [[FX:%.*]] = udiv i32 [[IV]], 4
404; CHECK-NEXT:    store volatile i32 [[IV]], ptr @A, align 4
405; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[FX]], 1024
406; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT]]
407; CHECK:       exit:
408; CHECK-NEXT:    ret void
409;
410entry:
411  br label %loop
412
413loop:
414  %iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
415  %vol = load volatile i32, ptr @A
416  %earlycnd = icmp ne i32 %vol, 0
417  br i1 %earlycnd, label %latch, label %exit
418
419latch:
420  %iv.next = add i32 %iv, 1
421  %fx = udiv i32 %iv, 4
422  store volatile i32 %iv, ptr @A
423  %c = icmp ult i32 %fx, 1024
424  br i1 %c, label %loop, label %exit
425
426exit:
427  ret void
428}
429
430; Demonstrate a case where two nested loops share a single exiting block.
431; The key point is that the exit count is *different* for the two loops, and
432; thus we can't rewrite the exit for the outer one.  There are three sub-cases
433; which can happen here: a) the outer loop has a backedge taken count of zero
434; (for the case where we know the inner exit is known taken), b) the exit is
435; known never taken (but may have an exit count outside the range of the IV)
436; or c) the outer loop has an unanalyzable exit count (where we can't tell).
437define void @nested(i32 %n) {
438; CHECK-LABEL: @nested(
439; CHECK-NEXT:  entry:
440; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[N:%.*]], 1
441; CHECK-NEXT:    br label [[OUTER:%.*]]
442; CHECK:       outer:
443; CHECK-NEXT:    [[IV1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV1_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
444; CHECK-NEXT:    store volatile i32 [[IV1]], ptr @A, align 4
445; CHECK-NEXT:    [[IV1_NEXT]] = add nuw nsw i32 [[IV1]], 1
446; CHECK-NEXT:    br label [[INNER:%.*]]
447; CHECK:       inner:
448; CHECK-NEXT:    [[IV2:%.*]] = phi i32 [ 0, [[OUTER]] ], [ [[IV2_NEXT:%.*]], [[INNER_LATCH:%.*]] ]
449; CHECK-NEXT:    store volatile i32 [[IV2]], ptr @A, align 4
450; CHECK-NEXT:    [[IV2_NEXT]] = add nuw nsw i32 [[IV2]], 1
451; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV2]], 20
452; CHECK-NEXT:    br i1 [[EXITCOND]], label [[INNER_LATCH]], label [[EXIT_LOOPEXIT:%.*]]
453; CHECK:       inner_latch:
454; CHECK-NEXT:    [[EXITCOND2:%.*]] = icmp ne i32 [[IV2_NEXT]], [[TMP0]]
455; CHECK-NEXT:    br i1 [[EXITCOND2]], label [[INNER]], label [[OUTER_LATCH]]
456; CHECK:       outer_latch:
457; CHECK-NEXT:    [[EXITCOND3:%.*]] = icmp ne i32 [[IV1_NEXT]], 21
458; CHECK-NEXT:    br i1 [[EXITCOND3]], label [[OUTER]], label [[EXIT_LOOPEXIT1:%.*]]
459; CHECK:       exit.loopexit:
460; CHECK-NEXT:    br label [[EXIT:%.*]]
461; CHECK:       exit.loopexit1:
462; CHECK-NEXT:    br label [[EXIT]]
463; CHECK:       exit:
464; CHECK-NEXT:    ret void
465;
466entry:
467  br label %outer
468
469outer:
470  %iv1 = phi i32 [ 0, %entry ], [ %iv1.next, %outer_latch ]
471  store volatile i32 %iv1, ptr @A
472  %iv1.next = add i32 %iv1, 1
473  br label %inner
474
475inner:
476  %iv2 = phi i32 [ 0, %outer ], [ %iv2.next, %inner_latch ]
477  store volatile i32 %iv2, ptr @A
478  %iv2.next = add i32 %iv2, 1
479  %innertest = icmp ult i32 %iv2, 20
480  br i1 %innertest, label %inner_latch, label %exit
481
482inner_latch:
483  %innertestb = icmp ult i32 %iv2, %n
484  br i1 %innertestb, label %inner, label %outer_latch
485
486outer_latch:
487  %outertest = icmp ult i32 %iv1, 20
488  br i1 %outertest, label %outer, label %exit
489
490exit:
491  ret void
492}
493