xref: /llvm-project/llvm/test/Transforms/LICM/guards.ll (revision e390c229a438ed1eb3396df8fbeeda89c49474e6)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; REQUIRES: asserts
3; RUN: opt -passes=licm -ipt-expensive-asserts=true < %s -S | FileCheck %s
4; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<target-ir>,require<scalar-evolution>,require<opt-remark-emit>,loop-mssa(licm)' -ipt-expensive-asserts=true < %s -S | FileCheck %s
5
6; Hoist guard and load.
7define void @test1(i1 %cond, ptr %ptr) {
8; CHECK-LABEL: @test1(
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND:%.*]]) [ "deopt"(i32 0) ]
11; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[PTR:%.*]], align 4
12; CHECK-NEXT:    br label [[LOOP:%.*]]
13; CHECK:       loop:
14; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[X_INC:%.*]], [[LOOP]] ]
15; CHECK-NEXT:    [[X_INC]] = add i32 [[X]], [[VAL]]
16; CHECK-NEXT:    br label [[LOOP]]
17;
18
19entry:
20  br label %loop
21
22loop:
23  %x = phi i32 [ 0, %entry ], [ %x.inc, %loop ]
24  call void (i1, ...) @llvm.experimental.guard(i1 %cond) ["deopt" (i32 0)]
25  %val = load i32, ptr %ptr
26  %x.inc = add i32 %x, %val
27  br label %loop
28}
29
30; Can't hoist over a side effect, but can still promote and fold the load.
31define void @test2(i1 %cond, ptr %ptr) {
32; CHECK-LABEL: @test2(
33; CHECK-NEXT:  entry:
34; CHECK-NEXT:    br label [[LOOP:%.*]]
35; CHECK:       loop:
36; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[X_INC:%.*]], [[LOOP]] ]
37; CHECK-NEXT:    store i32 0, ptr [[PTR:%.*]], align 4
38; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND:%.*]]) [ "deopt"(i32 0) ]
39; CHECK-NEXT:    [[X_INC]] = add i32 [[X]], 0
40; CHECK-NEXT:    br label [[LOOP]]
41;
42
43entry:
44  br label %loop
45
46loop:
47  %x = phi i32 [ 0, %entry ], [ %x.inc, %loop ]
48  store i32 0, ptr %ptr
49  call void (i1, ...) @llvm.experimental.guard(i1 %cond) ["deopt" (i32 0)]
50  %val = load i32, ptr %ptr
51  %x.inc = add i32 %x, %val
52  br label %loop
53}
54
55; Can't hoist over a side effect
56define void @test2b(i1 %cond, ptr %ptr) {
57; CHECK-LABEL: @test2b(
58; CHECK-NEXT:  entry:
59; CHECK-NEXT:    [[P2:%.*]] = getelementptr i32, ptr [[PTR:%.*]], i32 1
60; CHECK-NEXT:    br label [[LOOP:%.*]]
61; CHECK:       loop:
62; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[X_INC:%.*]], [[LOOP]] ]
63; CHECK-NEXT:    store i32 [[X]], ptr [[P2]], align 4
64; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND:%.*]]) [ "deopt"(i32 0) ]
65; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[PTR]], align 4
66; CHECK-NEXT:    [[X_INC]] = add i32 [[X]], [[VAL]]
67; CHECK-NEXT:    br label [[LOOP]]
68;
69
70entry:
71  br label %loop
72
73loop:
74  %x = phi i32 [ 0, %entry ], [ %x.inc, %loop ]
75  %p2 = getelementptr i32, ptr %ptr, i32 1
76  store i32 %x, ptr %p2
77  call void (i1, ...) @llvm.experimental.guard(i1 %cond) ["deopt" (i32 0)]
78  %val = load i32, ptr %ptr
79  %x.inc = add i32 %x, %val
80  br label %loop
81}
82
83; But can hoist if the side effect is hoisted with MSSA
84define void @test2b_prime(i1 %cond, ptr noalias %ptr) {
85; CHECK-LABEL: @test2b_prime(
86; CHECK-NEXT:  entry:
87; CHECK-NEXT:    [[P2:%.*]] = getelementptr i32, ptr [[PTR:%.*]], i32 1
88; CHECK-NEXT:    store i32 0, ptr [[P2]], align 4
89; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND:%.*]]) [ "deopt"(i32 0) ]
90; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[PTR]], align 4
91; CHECK-NEXT:    br label [[LOOP:%.*]]
92; CHECK:       loop:
93; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[X_INC:%.*]], [[LOOP]] ]
94; CHECK-NEXT:    [[X_INC]] = add i32 [[X]], [[VAL]]
95; CHECK-NEXT:    br label [[LOOP]]
96;
97
98entry:
99  br label %loop
100
101loop:
102  %x = phi i32 [ 0, %entry ], [ %x.inc, %loop ]
103  %p2 = getelementptr i32, ptr %ptr, i32 1
104  store i32 0, ptr %p2
105  call void (i1, ...) @llvm.experimental.guard(i1 %cond) ["deopt" (i32 0)]
106  %val = load i32, ptr %ptr
107  %x.inc = add i32 %x, %val
108  br label %loop
109}
110
111; Hoist guard. Cannot hoist load because of aliasing, but can promote.
112define void @test3(i1 %cond, ptr %ptr) {
113; CHECK-LABEL: @test3(
114; CHECK-NEXT:  entry:
115; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND:%.*]]) [ "deopt"(i32 0) ]
116; CHECK-NEXT:    [[PTR_PROMOTED:%.*]] = load i32, ptr [[PTR:%.*]], align 4
117; CHECK-NEXT:    br label [[LOOP:%.*]]
118; CHECK:       loop:
119; CHECK-NEXT:    [[TMP0:%.*]] = phi i32 [ [[PTR_PROMOTED]], [[ENTRY:%.*]] ], [ 0, [[LOOP]] ]
120; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[X_INC:%.*]], [[LOOP]] ]
121; CHECK-NEXT:    store i32 0, ptr [[PTR]], align 4
122; CHECK-NEXT:    [[X_INC]] = add i32 [[X]], [[TMP0]]
123; CHECK-NEXT:    br label [[LOOP]]
124;
125
126entry:
127  br label %loop
128
129loop:
130  %x = phi i32 [ 0, %entry ], [ %x.inc, %loop ]
131  call void (i1, ...) @llvm.experimental.guard(i1 %cond) ["deopt" (i32 0)]
132  %val = load i32, ptr %ptr
133  store i32 0, ptr %ptr
134  %x.inc = add i32 %x, %val
135  br label %loop
136}
137
138; Hoist load and guard.
139define void @test4(i1 %c, ptr %p) {
140; CHECK-LABEL: @test4(
141; CHECK-NEXT:  entry:
142; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
143; CHECK-NEXT:    [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
144; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
145; CHECK-NEXT:    br label [[LOOP:%.*]]
146; CHECK:       loop:
147; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
148; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
149; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
150; CHECK:       if.true:
151; CHECK-NEXT:    br label [[BACKEDGE]]
152; CHECK:       if.false:
153; CHECK-NEXT:    br label [[BACKEDGE]]
154; CHECK:       backedge:
155; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
156; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
157; CHECK:       exit:
158; CHECK-NEXT:    ret void
159;
160
161entry:
162  br label %loop
163
164loop:
165  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
166  %iv.next = add i32 %iv, 1
167  br i1 %c, label %if.true, label %if.false
168
169if.true:
170  br label %backedge
171
172if.false:
173  br label %backedge
174
175backedge:
176  %a = load i32, ptr %p
177  %invariant_cond = icmp ne i32 %a, 100
178  call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
179  %loop_cond = icmp slt i32 %iv.next, 1000
180  br i1 %loop_cond, label %loop, label %exit
181
182exit:
183  ret void
184}
185
186; Do not hoist across a conditionally executed side effect.
187define void @test4a(i1 %c, ptr %p, ptr %q) {
188; CHECK-LABEL: @test4a(
189; CHECK-NEXT:  entry:
190; CHECK-NEXT:    br label [[LOOP:%.*]]
191; CHECK:       loop:
192; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
193; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
194; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
195; CHECK:       if.true:
196; CHECK-NEXT:    store i32 123, ptr [[Q:%.*]], align 4
197; CHECK-NEXT:    br label [[BACKEDGE]]
198; CHECK:       if.false:
199; CHECK-NEXT:    br label [[BACKEDGE]]
200; CHECK:       backedge:
201; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
202; CHECK-NEXT:    [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
203; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
204; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
205; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
206; CHECK:       exit:
207; CHECK-NEXT:    ret void
208;
209
210entry:
211  br label %loop
212
213loop:
214  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
215  %iv.next = add i32 %iv, 1
216  br i1 %c, label %if.true, label %if.false
217
218if.true:
219  store i32 123, ptr %q
220  br label %backedge
221
222if.false:
223  br label %backedge
224
225backedge:
226  %a = load i32, ptr %p
227  %invariant_cond = icmp ne i32 %a, 100
228  call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
229  %loop_cond = icmp slt i32 %iv.next, 1000
230  br i1 %loop_cond, label %loop, label %exit
231
232exit:
233  ret void
234}
235
236; Do not hoist a conditionally executed guard.
237define void @test4b(i1 %c, ptr %p, ptr %q) {
238; CHECK-LABEL: @test4b(
239; CHECK-NEXT:  entry:
240; CHECK-NEXT:    br label [[LOOP:%.*]]
241; CHECK:       loop:
242; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
243; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
244; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
245; CHECK:       if.true:
246; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
247; CHECK-NEXT:    [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
248; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
249; CHECK-NEXT:    br label [[BACKEDGE]]
250; CHECK:       if.false:
251; CHECK-NEXT:    br label [[BACKEDGE]]
252; CHECK:       backedge:
253; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
254; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
255; CHECK:       exit:
256; CHECK-NEXT:    ret void
257;
258
259entry:
260  br label %loop
261
262loop:
263  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
264  %iv.next = add i32 %iv, 1
265  br i1 %c, label %if.true, label %if.false
266
267if.true:
268  %a = load i32, ptr %p
269  %invariant_cond = icmp ne i32 %a, 100
270  call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
271  br label %backedge
272
273if.false:
274  br label %backedge
275
276backedge:
277  %loop_cond = icmp slt i32 %iv.next, 1000
278  br i1 %loop_cond, label %loop, label %exit
279
280exit:
281  ret void
282}
283
284; Hoist store, load and guard.
285define void @test4c(i1 %c, ptr %p, ptr noalias %s) {
286; CHECK-LABEL: @test4c(
287; CHECK-NEXT:  entry:
288; CHECK-NEXT:    store i8 0, ptr [[S:%.*]], align 1
289; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
290; CHECK-NEXT:    [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
291; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
292; CHECK-NEXT:    br label [[LOOP:%.*]]
293; CHECK:       loop:
294; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
295; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
296; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
297; CHECK:       if.true:
298; CHECK-NEXT:    br label [[BACKEDGE]]
299; CHECK:       if.false:
300; CHECK-NEXT:    br label [[BACKEDGE]]
301; CHECK:       backedge:
302; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
303; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
304; CHECK:       exit:
305; CHECK-NEXT:    ret void
306;
307
308entry:
309  br label %loop
310
311loop:
312  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
313  %iv.next = add i32 %iv, 1
314  store i8 0, ptr %s
315  br i1 %c, label %if.true, label %if.false
316
317if.true:
318  br label %backedge
319
320if.false:
321  br label %backedge
322
323backedge:
324  %a = load i32, ptr %p
325  %invariant_cond = icmp ne i32 %a, 100
326  call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
327  %loop_cond = icmp slt i32 %iv.next, 1000
328  br i1 %loop_cond, label %loop, label %exit
329
330exit:
331  ret void
332}
333
334; Check that we don't hoist across a store in a conditionally executed block.
335define void @test4d(i1 %c, ptr %p, ptr noalias %s) {
336; CHECK-LABEL: @test4d(
337; CHECK-NEXT:  entry:
338; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
339; CHECK-NEXT:    [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
340; CHECK-NEXT:    br label [[LOOP:%.*]]
341; CHECK:       loop:
342; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
343; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
344; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
345; CHECK:       if.true:
346; CHECK-NEXT:    store i8 0, ptr [[S:%.*]], align 1
347; CHECK-NEXT:    br label [[BACKEDGE]]
348; CHECK:       if.false:
349; CHECK-NEXT:    br label [[BACKEDGE]]
350; CHECK:       backedge:
351; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
352; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
353; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
354; CHECK:       exit:
355; CHECK-NEXT:    ret void
356;
357
358entry:
359  br label %loop
360
361loop:
362  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
363  %iv.next = add i32 %iv, 1
364  br i1 %c, label %if.true, label %if.false
365
366if.true:
367  store i8 0, ptr %s
368  br label %backedge
369
370if.false:
371  br label %backedge
372
373backedge:
374  %a = load i32, ptr %p
375  %invariant_cond = icmp ne i32 %a, 100
376  call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
377  %loop_cond = icmp slt i32 %iv.next, 1000
378  br i1 %loop_cond, label %loop, label %exit
379
380exit:
381  ret void
382}
383
384; Check that we don't hoist across a store before the guard in the backedge.
385define void @test4e(i1 %c, ptr %p, ptr noalias %s) {
386; CHECK-LABEL: @test4e(
387; CHECK-NEXT:  entry:
388; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
389; CHECK-NEXT:    [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
390; CHECK-NEXT:    store i8 0, ptr [[S:%.*]], align 1
391; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
392; CHECK-NEXT:    br label [[LOOP:%.*]]
393; CHECK:       loop:
394; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
395; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
396; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
397; CHECK:       if.true:
398; CHECK-NEXT:    br label [[BACKEDGE]]
399; CHECK:       if.false:
400; CHECK-NEXT:    br label [[BACKEDGE]]
401; CHECK:       backedge:
402; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
403; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
404; CHECK:       exit:
405; CHECK-NEXT:    ret void
406;
407
408entry:
409  br label %loop
410
411loop:
412  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
413  %iv.next = add i32 %iv, 1
414  br i1 %c, label %if.true, label %if.false
415
416if.true:
417  br label %backedge
418
419if.false:
420  br label %backedge
421
422backedge:
423  %a = load i32, ptr %p
424  %invariant_cond = icmp ne i32 %a, 100
425  store i8 0, ptr %s
426  call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
427  %loop_cond = icmp slt i32 %iv.next, 1000
428  br i1 %loop_cond, label %loop, label %exit
429
430exit:
431  ret void
432}
433
434; Check that we can hoist the guard in spite of store which happens after.
435define void @test4f(i1 %c, ptr %p, ptr noalias %s) {
436; CHECK-LABEL: @test4f(
437; CHECK-NEXT:  entry:
438; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
439; CHECK-NEXT:    [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
440; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
441; CHECK-NEXT:    store i8 0, ptr [[S:%.*]], align 1
442; CHECK-NEXT:    br label [[LOOP:%.*]]
443; CHECK:       loop:
444; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
445; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
446; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
447; CHECK:       if.true:
448; CHECK-NEXT:    br label [[BACKEDGE]]
449; CHECK:       if.false:
450; CHECK-NEXT:    br label [[BACKEDGE]]
451; CHECK:       backedge:
452; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
453; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
454; CHECK:       exit:
455; CHECK-NEXT:    ret void
456;
457
458entry:
459  br label %loop
460
461loop:
462  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
463  %iv.next = add i32 %iv, 1
464  br i1 %c, label %if.true, label %if.false
465
466if.true:
467  br label %backedge
468
469if.false:
470  br label %backedge
471
472backedge:
473  %a = load i32, ptr %p
474  %invariant_cond = icmp ne i32 %a, 100
475  call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
476  store i8 0, ptr %s
477  %loop_cond = icmp slt i32 %iv.next, 1000
478  br i1 %loop_cond, label %loop, label %exit
479
480exit:
481  ret void
482}
483
484; Do not hoist an invariant guard across a variant guard.
485define void @test5(i1 %c, ptr %p, ptr %q) {
486; CHECK-LABEL: @test5(
487; CHECK-NEXT:  entry:
488; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
489; CHECK-NEXT:    [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
490; CHECK-NEXT:    br label [[LOOP:%.*]]
491; CHECK:       loop:
492; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
493; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
494; CHECK-NEXT:    [[VARIANT_COND:%.*]] = icmp ne i32 [[A]], [[IV]]
495; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[VARIANT_COND]]) [ "deopt"() ]
496; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
497; CHECK-NEXT:    br label [[BACKEDGE]]
498; CHECK:       backedge:
499; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
500; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
501; CHECK:       exit:
502; CHECK-NEXT:    ret void
503;
504
505entry:
506  br label %loop
507
508loop:
509  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
510  %iv.next = add i32 %iv, 1
511  %a = load i32, ptr %p
512  %invariant_cond = icmp ne i32 %a, 100
513  %variant_cond = icmp ne i32 %a, %iv
514  call void (i1, ...) @llvm.experimental.guard(i1 %variant_cond) [ "deopt"() ]
515  call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
516  br label %backedge
517
518backedge:
519  %loop_cond = icmp slt i32 %iv.next, 1000
520  br i1 %loop_cond, label %loop, label %exit
521
522exit:
523  ret void
524}
525
526; Hoist an invariant guard, leave the following variant guard in the loop.
527define void @test5a(i1 %c, ptr %p, ptr %q) {
528; CHECK-LABEL: @test5a(
529; CHECK-NEXT:  entry:
530; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
531; CHECK-NEXT:    [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
532; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
533; CHECK-NEXT:    br label [[LOOP:%.*]]
534; CHECK:       loop:
535; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
536; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
537; CHECK-NEXT:    [[VARIANT_COND:%.*]] = icmp ne i32 [[A]], [[IV]]
538; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[VARIANT_COND]]) [ "deopt"() ]
539; CHECK-NEXT:    br label [[BACKEDGE]]
540; CHECK:       backedge:
541; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
542; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
543; CHECK:       exit:
544; CHECK-NEXT:    ret void
545;
546
547entry:
548  br label %loop
549
550loop:
551  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
552  %iv.next = add i32 %iv, 1
553  %a = load i32, ptr %p
554  %invariant_cond = icmp ne i32 %a, 100
555  %variant_cond = icmp ne i32 %a, %iv
556  call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
557  call void (i1, ...) @llvm.experimental.guard(i1 %variant_cond) [ "deopt"() ]
558  br label %backedge
559
560backedge:
561  %loop_cond = icmp slt i32 %iv.next, 1000
562  br i1 %loop_cond, label %loop, label %exit
563
564exit:
565  ret void
566}
567
568declare void @llvm.experimental.guard(i1, ...)
569