xref: /llvm-project/llvm/test/Transforms/GuardWidening/basic.ll (revision 88ad44ec43bdaba5185a0227ec81eb15bd0f7c5a)
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
4
5declare void @llvm.experimental.guard(i1,...)
6
7; Basic test case: we wide the first check to check both the
8; conditions.
9define 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
16;
17entry:
18
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
22}
23
24; Same as @f_0, but with using a more general notion of postdominance.
25define void @f_1(i1 %cond_0, i1 %cond_1, i1 %arg) {
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 %arg, 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
38;
39entry:
40
41  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
42  br i1 %arg, label %left, label %right
43
44left:
45  br label %merge
46
47right:
48  br label %merge
49
50merge:
51  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
52  ret void
53}
54
55; Like @f_1, but we have some code we need to hoist before we can
56; widen a dominanting check.
57define void @f_2(i32 %a, i32 %b, i1 %arg) {
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 %arg, 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
72;
73entry:
74
75  %cond_0 = icmp ult i32 %a, 10
76  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
77  br i1 %arg, label %left, label %right
78
79left:
80  br label %merge
81
82right:
83  br label %merge
84
85merge:
86  %cond_1 = icmp ult i32 %b, 10
87  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
88  ret void
89}
90
91; Negative test: don't hoist stuff out of control flow
92; indiscriminately, since that can make us do more work than needed.
93define void @f_3(i32 %a, i32 %b, i1 %arg) {
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 %arg, 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
105;
106entry:
107
108  %cond_0 = icmp ult i32 %a, 10
109  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
110  br i1 %arg, label %left, label %right
111
112left:
113
114  %cond_1 = icmp ult i32 %b, 10
115  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
116  ret void
117
118right:
119  ret void
120}
121
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.
125define void @f_4(i32 %a, i32 %b, i1 %arg) {
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 %arg, label [[LOOP:%.*]], label [[LEAVE:%.*]]
134; CHECK:       loop:
135; CHECK-NEXT:    br i1 %arg, label [[LOOP]], label [[LEAVE]]
136; CHECK:       leave:
137; CHECK-NEXT:    ret void
138;
139entry:
140
141  %cond_0 = icmp ult i32 %a, 10
142  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
143  br i1 %arg, label %loop, label %leave
144
145loop:
146  %cond_1 = icmp ult i32 %b, 10
147  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
148  br i1 %arg, label %loop, label %leave
149
150leave:
151  ret void
152}
153
154; Hoisting out of control flow is also fine if we can widen the
155; dominating check without doing any extra work.
156define void @f_5(i32 %a, i1 %arg) {
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 %arg, 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
168;
169entry:
170
171  %cond_0 = icmp ugt i32 %a, 7
172  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
173  br i1 %arg, label %left, label %right
174
175left:
176  %cond_1 = icmp ugt i32 %a, 10
177  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
178  ret void
179
180right:
181  ret void
182}
183
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.
187define 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
196;
197entry:
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
204}
205
206; All else equal, we try to widen the earliest guard we can.  This
207; heuristic can use some tuning.
208define void @f_7(i32 %a, ptr %cond_buf, i1 %arg) {
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 %arg, label [[LEFT:%.*]], label [[RIGHT:%.*]]
219; CHECK:       left:
220; CHECK-NEXT:    br label [[LEFT]]
221; CHECK:       right:
222; CHECK-NEXT:    ret void
223;
224entry:
225
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 %arg, label %left, label %right
231
232left:
233  %cond_3 = icmp ult i32 %a, 7
234  call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ]
235  br label %left
236
237right:
238  ret void
239}
240
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.
244define void @f_8(i32 %a, i1 %cond_1, i1 %cond_2, i1 %arg) {
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 %arg, 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 %arg, label [[LOOP2:%.*]], label [[LEAVE2:%.*]]
257; CHECK:       loop2:
258; CHECK-NEXT:    br label [[LOOP2]]
259; CHECK:       leave2:
260; CHECK-NEXT:    ret void
261;
262entry:
263  br label %loop
264
265loop:
266  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
267  br i1 %arg, label %loop, label %leave
268
269leave:
270
271  call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ]
272  br i1 %arg, label %loop2, label %leave2
273
274loop2:
275  %cond_3 = icmp ult i32 %a, 7
276  call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ]
277  br label %loop2
278
279leave2:
280  ret void
281}
282
283; In cases like these where there isn't any "obviously profitable"
284; widening sites, we refuse to do anything.
285define void @f_9(i32 %a, i1 %cond_0, i1 %cond_1, i1 %arg) {
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 %arg, 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]]
295;
296entry:
297  br label %first_loop
298
299first_loop:
300
301  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
302  br i1 %arg, label %first_loop, label %second_loop
303
304second_loop:
305
306  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
307  br label %second_loop
308}
309
310; Same situation as in @f_9: no "obviously profitable" widening sites,
311; so we refuse to do anything.
312define void @f_10(i32 %a, i1 %cond_0, i1 %cond_1, i1 %arg) {
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 %arg, 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
322;
323entry:
324  br label %loop
325
326loop:
327
328  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
329  br i1 %arg, label %loop, label %no_loop
330
331no_loop:
332  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
333  ret void
334}
335
336; With guards in loops, we're okay hoisting out the guard into the
337; containing loop.
338define void @f_11(i32 %a, i1 %cond_0, i1 %cond_1, i1 %arg) {
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 %arg, label [[INNER]], label [[OUTER:%.*]]
347; CHECK:       outer:
348; CHECK-NEXT:    br label [[INNER]]
349;
350entry:
351  br label %inner
352
353inner:
354
355  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
356  br i1 %arg, label %inner, label %outer
357
358outer:
359  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
360  br label %inner
361}
362
363; Checks that we are adequately guarded against exponential-time
364; behavior when hoisting code.
365define 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
403;
404
405; Eliding the earlier 29 multiplications for brevity
406
407entry:
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
442}
443
444define void @f_13(i32 %a, i1 %arg) {
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 %arg, 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
456;
457entry:
458
459  %cond_0 = icmp ult i32 %a, 14
460  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
461  br i1 %arg, label %left, label %right
462
463left:
464  %cond_1 = icmp slt i32 %a, 10
465  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
466  ret void
467
468right:
469  ret void
470}
471
472define void @f_14(i32 %a, i1 %arg) {
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 %arg, 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
484;
485entry:
486
487  %cond_0 = icmp ult i32 %a, 14
488  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
489  br i1 %arg, label %left, label %right
490
491left:
492
493  %cond_1 = icmp sgt i32 %a, 10
494  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
495  ret void
496
497right:
498  ret void
499}
500
501; Make sure we do not widen guard by trivial true conditions into something.
502define 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
508;
509entry:
510
511  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
512  call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
513  ret void
514}
515
516; Make sure we do not widen guard by trivial false conditions into something.
517define 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
523;
524entry:
525
526  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
527  call void(i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ]
528  ret void
529}
530