Follow up to d0858bffa11, add missing REQUIRES x86
[llvm-project.git] / llvm / test / Transforms / GuardWidening / basic.ll
blob096ea9057915c61b43b50bbd79cbef8fbb237382
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -passes=guard-widening < %s        | FileCheck %s
3 ; RUN: opt -S -passes=guard-widening < %s | FileCheck %s
5 declare void @llvm.experimental.guard(i1,...)
7 ; Basic test case: we wide the first check to check both the
8 ; conditions.
9 define void @f_0(i1 %cond_0, i1 %cond_1) {
10 ; CHECK-LABEL: @f_0(
11 ; CHECK-NEXT:  entry:
12 ; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
13 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
14 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
15 ; CHECK-NEXT:    ret void
17 entry:
19   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
20   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
21   ret void
24 ; Same as @f_0, but with using a more general notion of postdominance.
25 define void @f_1(i1 %cond_0, i1 %cond_1) {
26 ; CHECK-LABEL: @f_1(
27 ; CHECK-NEXT:  entry:
28 ; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
29 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
30 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
31 ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
32 ; CHECK:       left:
33 ; CHECK-NEXT:    br label [[MERGE:%.*]]
34 ; CHECK:       right:
35 ; CHECK-NEXT:    br label [[MERGE]]
36 ; CHECK:       merge:
37 ; CHECK-NEXT:    ret void
39 entry:
41   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
42   br i1 undef, label %left, label %right
44 left:
45   br label %merge
47 right:
48   br label %merge
50 merge:
51   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
52   ret void
55 ; Like @f_1, but we have some code we need to hoist before we can
56 ; widen a dominanting check.
57 define void @f_2(i32 %a, i32 %b) {
58 ; CHECK-LABEL: @f_2(
59 ; CHECK-NEXT:  entry:
60 ; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
61 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
62 ; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10
63 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]]
64 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
65 ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
66 ; CHECK:       left:
67 ; CHECK-NEXT:    br label [[MERGE:%.*]]
68 ; CHECK:       right:
69 ; CHECK-NEXT:    br label [[MERGE]]
70 ; CHECK:       merge:
71 ; CHECK-NEXT:    ret void
73 entry:
75   %cond_0 = icmp ult i32 %a, 10
76   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
77   br i1 undef, label %left, label %right
79 left:
80   br label %merge
82 right:
83   br label %merge
85 merge:
86   %cond_1 = icmp ult i32 %b, 10
87   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
88   ret void
91 ; Negative test: don't hoist stuff out of control flow
92 ; indiscriminately, since that can make us do more work than needed.
93 define void @f_3(i32 %a, i32 %b) {
94 ; CHECK-LABEL: @f_3(
95 ; CHECK-NEXT:  entry:
96 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
97 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ]
98 ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
99 ; CHECK:       left:
100 ; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
101 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ]
102 ; CHECK-NEXT:    ret void
103 ; CHECK:       right:
104 ; CHECK-NEXT:    ret void
106 entry:
108   %cond_0 = icmp ult i32 %a, 10
109   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
110   br i1 undef, label %left, label %right
112 left:
114   %cond_1 = icmp ult i32 %b, 10
115   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
116   ret void
118 right:
119   ret void
122 ; But hoisting out of control flow is fine if it makes a loop computed
123 ; condition loop invariant.  This behavior may require some tuning in
124 ; the future.
125 define void @f_4(i32 %a, i32 %b) {
126 ; CHECK-LABEL: @f_4(
127 ; CHECK-NEXT:  entry:
128 ; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
129 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
130 ; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10
131 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]]
132 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
133 ; CHECK-NEXT:    br i1 undef, label [[LOOP:%.*]], label [[LEAVE:%.*]]
134 ; CHECK:       loop:
135 ; CHECK-NEXT:    br i1 undef, label [[LOOP]], label [[LEAVE]]
136 ; CHECK:       leave:
137 ; CHECK-NEXT:    ret void
139 entry:
141   %cond_0 = icmp ult i32 %a, 10
142   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
143   br i1 undef, label %loop, label %leave
145 loop:
146   %cond_1 = icmp ult i32 %b, 10
147   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
148   br i1 undef, label %loop, label %leave
150 leave:
151   ret void
154 ; Hoisting out of control flow is also fine if we can widen the
155 ; dominating check without doing any extra work.
156 define void @f_5(i32 %a) {
157 ; CHECK-LABEL: @f_5(
158 ; CHECK-NEXT:  entry:
159 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ugt i32 [[A:%.*]], 7
160 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = icmp uge i32 [[A]], 11
161 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
162 ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
163 ; CHECK:       left:
164 ; CHECK-NEXT:    [[COND_1:%.*]] = icmp ugt i32 [[A]], 10
165 ; CHECK-NEXT:    ret void
166 ; CHECK:       right:
167 ; CHECK-NEXT:    ret void
169 entry:
171   %cond_0 = icmp ugt i32 %a, 7
172   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
173   br i1 undef, label %left, label %right
175 left:
176   %cond_1 = icmp ugt i32 %a, 10
177   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
178   ret void
180 right:
181   ret void
184 ; Negative test: the load from %a can be safely speculated to before
185 ; the first guard, but there is no guarantee that it will produce the
186 ; same value.
187 define void @f_6(ptr dereferenceable(32) %a, ptr %b, i1 %unknown) {
188 ; CHECK-LABEL: @f_6(
189 ; CHECK-NEXT:  entry:
190 ; CHECK-NEXT:    [[COND_0:%.*]] = load i1, ptr [[A:%.*]], align 1
191 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ]
192 ; CHECK-NEXT:    store i1 [[UNKNOWN:%.*]], ptr [[B:%.*]], align 1
193 ; CHECK-NEXT:    [[COND_1:%.*]] = load i1, ptr [[A]], align 1
194 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ]
195 ; CHECK-NEXT:    ret void
197 entry:
198   %cond_0 = load i1, ptr %a
199   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
200   store i1 %unknown, ptr %b
201   %cond_1 = load i1, ptr %a
202   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
203   ret void
206 ; All else equal, we try to widen the earliest guard we can.  This
207 ; heuristic can use some tuning.
208 define void @f_7(i32 %a, ptr %cond_buf) {
209 ; CHECK-LABEL: @f_7(
210 ; CHECK-NEXT:  entry:
211 ; CHECK-NEXT:    [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
212 ; CHECK-NEXT:    [[COND_1:%.*]] = load volatile i1, ptr [[COND_BUF:%.*]], align 1
213 ; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 7
214 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_3]]
215 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
216 ; CHECK-NEXT:    [[COND_2:%.*]] = load volatile i1, ptr [[COND_BUF]], align 1
217 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2]]) [ "deopt"() ]
218 ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
219 ; CHECK:       left:
220 ; CHECK-NEXT:    br label [[LEFT]]
221 ; CHECK:       right:
222 ; CHECK-NEXT:    ret void
224 entry:
226   %cond_1 = load volatile i1, ptr %cond_buf
227   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
228   %cond_2 = load volatile i1, ptr %cond_buf
229   call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ]
230   br i1 undef, label %left, label %right
232 left:
233   %cond_3 = icmp ult i32 %a, 7
234   call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ]
235   br label %left
237 right:
238   ret void
241 ; In this case the earliest dominating guard is in a loop, and we
242 ; don't want to put extra work in there.  This heuristic can use some
243 ; tuning.
244 define void @f_8(i32 %a, i1 %cond_1, i1 %cond_2) {
245 ; CHECK-LABEL: @f_8(
246 ; CHECK-NEXT:  entry:
247 ; CHECK-NEXT:    [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
248 ; CHECK-NEXT:    br label [[LOOP:%.*]]
249 ; CHECK:       loop:
250 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ]
251 ; CHECK-NEXT:    br i1 undef, label [[LOOP]], label [[LEAVE:%.*]]
252 ; CHECK:       leave:
253 ; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 7
254 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[COND_3]]
255 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
256 ; CHECK-NEXT:    br i1 undef, label [[LOOP2:%.*]], label [[LEAVE2:%.*]]
257 ; CHECK:       loop2:
258 ; CHECK-NEXT:    br label [[LOOP2]]
259 ; CHECK:       leave2:
260 ; CHECK-NEXT:    ret void
262 entry:
263   br label %loop
265 loop:
266   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
267   br i1 undef, label %loop, label %leave
269 leave:
271   call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ]
272   br i1 undef, label %loop2, label %leave2
274 loop2:
275   %cond_3 = icmp ult i32 %a, 7
276   call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ]
277   br label %loop2
279 leave2:
280   ret void
283 ; In cases like these where there isn't any "obviously profitable"
284 ; widening sites, we refuse to do anything.
285 define void @f_9(i32 %a, i1 %cond_0, i1 %cond_1) {
286 ; CHECK-LABEL: @f_9(
287 ; CHECK-NEXT:  entry:
288 ; CHECK-NEXT:    br label [[FIRST_LOOP:%.*]]
289 ; CHECK:       first_loop:
290 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
291 ; CHECK-NEXT:    br i1 undef, label [[FIRST_LOOP]], label [[SECOND_LOOP:%.*]]
292 ; CHECK:       second_loop:
293 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ]
294 ; CHECK-NEXT:    br label [[SECOND_LOOP]]
296 entry:
297   br label %first_loop
299 first_loop:
301   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
302   br i1 undef, label %first_loop, label %second_loop
304 second_loop:
306   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
307   br label %second_loop
310 ; Same situation as in @f_9: no "obviously profitable" widening sites,
311 ; so we refuse to do anything.
312 define void @f_10(i32 %a, i1 %cond_0, i1 %cond_1) {
313 ; CHECK-LABEL: @f_10(
314 ; CHECK-NEXT:  entry:
315 ; CHECK-NEXT:    br label [[LOOP:%.*]]
316 ; CHECK:       loop:
317 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
318 ; CHECK-NEXT:    br i1 undef, label [[LOOP]], label [[NO_LOOP:%.*]]
319 ; CHECK:       no_loop:
320 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ]
321 ; CHECK-NEXT:    ret void
323 entry:
324   br label %loop
326 loop:
328   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
329   br i1 undef, label %loop, label %no_loop
331 no_loop:
332   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
333   ret void
336 ; With guards in loops, we're okay hoisting out the guard into the
337 ; containing loop.
338 define void @f_11(i32 %a, i1 %cond_0, i1 %cond_1) {
339 ; CHECK-LABEL: @f_11(
340 ; CHECK-NEXT:  entry:
341 ; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
342 ; CHECK-NEXT:    br label [[INNER:%.*]]
343 ; CHECK:       inner:
344 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
345 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
346 ; CHECK-NEXT:    br i1 undef, label [[INNER]], label [[OUTER:%.*]]
347 ; CHECK:       outer:
348 ; CHECK-NEXT:    br label [[INNER]]
350 entry:
351   br label %inner
353 inner:
355   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
356   br i1 undef, label %inner, label %outer
358 outer:
359   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
360   br label %inner
363 ; Checks that we are adequately guarded against exponential-time
364 ; behavior when hoisting code.
365 define void @f_12(i32 %a0) {
366 ; CHECK-LABEL: @f_12(
367 ; CHECK-NEXT:  entry:
368 ; CHECK-NEXT:    [[A0_GW_FR:%.*]] = freeze i32 [[A0:%.*]]
369 ; CHECK-NEXT:    [[A1:%.*]] = mul i32 [[A0_GW_FR]], [[A0_GW_FR]]
370 ; CHECK-NEXT:    [[A2:%.*]] = mul i32 [[A1]], [[A1]]
371 ; CHECK-NEXT:    [[A3:%.*]] = mul i32 [[A2]], [[A2]]
372 ; CHECK-NEXT:    [[A4:%.*]] = mul i32 [[A3]], [[A3]]
373 ; CHECK-NEXT:    [[A5:%.*]] = mul i32 [[A4]], [[A4]]
374 ; CHECK-NEXT:    [[A6:%.*]] = mul i32 [[A5]], [[A5]]
375 ; CHECK-NEXT:    [[A7:%.*]] = mul i32 [[A6]], [[A6]]
376 ; CHECK-NEXT:    [[A8:%.*]] = mul i32 [[A7]], [[A7]]
377 ; CHECK-NEXT:    [[A9:%.*]] = mul i32 [[A8]], [[A8]]
378 ; CHECK-NEXT:    [[A10:%.*]] = mul i32 [[A9]], [[A9]]
379 ; CHECK-NEXT:    [[A11:%.*]] = mul i32 [[A10]], [[A10]]
380 ; CHECK-NEXT:    [[A12:%.*]] = mul i32 [[A11]], [[A11]]
381 ; CHECK-NEXT:    [[A13:%.*]] = mul i32 [[A12]], [[A12]]
382 ; CHECK-NEXT:    [[A14:%.*]] = mul i32 [[A13]], [[A13]]
383 ; CHECK-NEXT:    [[A15:%.*]] = mul i32 [[A14]], [[A14]]
384 ; CHECK-NEXT:    [[A16:%.*]] = mul i32 [[A15]], [[A15]]
385 ; CHECK-NEXT:    [[A17:%.*]] = mul i32 [[A16]], [[A16]]
386 ; CHECK-NEXT:    [[A18:%.*]] = mul i32 [[A17]], [[A17]]
387 ; CHECK-NEXT:    [[A19:%.*]] = mul i32 [[A18]], [[A18]]
388 ; CHECK-NEXT:    [[A20:%.*]] = mul i32 [[A19]], [[A19]]
389 ; CHECK-NEXT:    [[A21:%.*]] = mul i32 [[A20]], [[A20]]
390 ; CHECK-NEXT:    [[A22:%.*]] = mul i32 [[A21]], [[A21]]
391 ; CHECK-NEXT:    [[A23:%.*]] = mul i32 [[A22]], [[A22]]
392 ; CHECK-NEXT:    [[A24:%.*]] = mul i32 [[A23]], [[A23]]
393 ; CHECK-NEXT:    [[A25:%.*]] = mul i32 [[A24]], [[A24]]
394 ; CHECK-NEXT:    [[A26:%.*]] = mul i32 [[A25]], [[A25]]
395 ; CHECK-NEXT:    [[A27:%.*]] = mul i32 [[A26]], [[A26]]
396 ; CHECK-NEXT:    [[A28:%.*]] = mul i32 [[A27]], [[A27]]
397 ; CHECK-NEXT:    [[A29:%.*]] = mul i32 [[A28]], [[A28]]
398 ; CHECK-NEXT:    [[A30:%.*]] = mul i32 [[A29]], [[A29]]
399 ; CHECK-NEXT:    [[COND:%.*]] = trunc i32 [[A30]] to i1
400 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 true, [[COND]]
401 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
402 ; CHECK-NEXT:    ret void
405 ; Eliding the earlier 29 multiplications for brevity
407 entry:
408   call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
409   %a1 = mul i32 %a0, %a0
410   %a2 = mul i32 %a1, %a1
411   %a3 = mul i32 %a2, %a2
412   %a4 = mul i32 %a3, %a3
413   %a5 = mul i32 %a4, %a4
414   %a6 = mul i32 %a5, %a5
415   %a7 = mul i32 %a6, %a6
416   %a8 = mul i32 %a7, %a7
417   %a9 = mul i32 %a8, %a8
418   %a10 = mul i32 %a9, %a9
419   %a11 = mul i32 %a10, %a10
420   %a12 = mul i32 %a11, %a11
421   %a13 = mul i32 %a12, %a12
422   %a14 = mul i32 %a13, %a13
423   %a15 = mul i32 %a14, %a14
424   %a16 = mul i32 %a15, %a15
425   %a17 = mul i32 %a16, %a16
426   %a18 = mul i32 %a17, %a17
427   %a19 = mul i32 %a18, %a18
428   %a20 = mul i32 %a19, %a19
429   %a21 = mul i32 %a20, %a20
430   %a22 = mul i32 %a21, %a21
431   %a23 = mul i32 %a22, %a22
432   %a24 = mul i32 %a23, %a23
433   %a25 = mul i32 %a24, %a24
434   %a26 = mul i32 %a25, %a25
435   %a27 = mul i32 %a26, %a26
436   %a28 = mul i32 %a27, %a27
437   %a29 = mul i32 %a28, %a28
438   %a30 = mul i32 %a29, %a29
439   %cond = trunc i32 %a30 to i1
440   call void(i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]
441   ret void
444 define void @f_13(i32 %a) {
445 ; CHECK-LABEL: @f_13(
446 ; CHECK-NEXT:  entry:
447 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14
448 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = icmp ult i32 [[A]], 10
449 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
450 ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
451 ; CHECK:       left:
452 ; CHECK-NEXT:    [[COND_1:%.*]] = icmp slt i32 [[A]], 10
453 ; CHECK-NEXT:    ret void
454 ; CHECK:       right:
455 ; CHECK-NEXT:    ret void
457 entry:
459   %cond_0 = icmp ult i32 %a, 14
460   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
461   br i1 undef, label %left, label %right
463 left:
464   %cond_1 = icmp slt i32 %a, 10
465   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
466   ret void
468 right:
469   ret void
472 define void @f_14(i32 %a) {
473 ; CHECK-LABEL: @f_14(
474 ; CHECK-NEXT:  entry:
475 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14
476 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ]
477 ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
478 ; CHECK:       left:
479 ; CHECK-NEXT:    [[COND_1:%.*]] = icmp sgt i32 [[A]], 10
480 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ]
481 ; CHECK-NEXT:    ret void
482 ; CHECK:       right:
483 ; CHECK-NEXT:    ret void
485 entry:
487   %cond_0 = icmp ult i32 %a, 14
488   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
489   br i1 undef, label %left, label %right
491 left:
493   %cond_1 = icmp sgt i32 %a, 10
494   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
495   ret void
497 right:
498   ret void
501 ; Make sure we do not widen guard by trivial true conditions into something.
502 define void @f_15(i1 %cond_0, i1 %cond_1) {
503 ; CHECK-LABEL: @f_15(
504 ; CHECK-NEXT:  entry:
505 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
506 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
507 ; CHECK-NEXT:    ret void
509 entry:
511   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
512   call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
513   ret void
516 ; Make sure we do not widen guard by trivial false conditions into something.
517 define void @f_16(i1 %cond_0, i1 %cond_1) {
518 ; CHECK-LABEL: @f_16(
519 ; CHECK-NEXT:  entry:
520 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
521 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ]
522 ; CHECK-NEXT:    ret void
524 entry:
526   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
527   call void(i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ]
528   ret void