xref: /llvm-project/llvm/test/Transforms/LoopPredication/constant-ranges.ll (revision a580d2e4304053f7e0fc93ee26c911e689695fca)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes='loop-mssa(loop-predication)' -loop-predication-insert-assumes-of-predicated-guards-conditions=false < %s 2>&1 | FileCheck %s
3
4define i32 @test_ult(ptr noundef %p, i32 noundef %n, ptr noundef %arr, ptr noundef %len_p, i32 noundef %c) {
5; CHECK-LABEL: @test_ult(
6; CHECK-NEXT:  entry:
7; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0:![0-9]+]], !noundef !1
8; CHECK-NEXT:    br label [[LOOP:%.*]]
9; CHECK:       loop:
10; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
11; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
12; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
13; CHECK-NEXT:    [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], 128
14; CHECK-NEXT:    br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]]
15; CHECK:       do_range_check:
16; CHECK-NEXT:    call void @llvm.assume(i1 [[BOUND_CHECK]])
17; CHECK-NEXT:    [[RANGE_CHECK_ULT:%.*]] = icmp ult i32 [[EL]], [[LEN]]
18; CHECK-NEXT:    [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
19; CHECK-NEXT:    [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_ULT]], [[WC]]
20; CHECK-NEXT:    br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]]
21; CHECK:       backedge:
22; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
23; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4
24; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
25; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
26; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
27; CHECK:       deopt:
28; CHECK-NEXT:    [[DEOPT_RES:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
29; CHECK-NEXT:    ret i32 [[DEOPT_RES]]
30; CHECK:       exit:
31; CHECK-NEXT:    ret i32 0
32; CHECK:       bound_check_failed:
33; CHECK-NEXT:    ret i32 -1
34;
35entry:
36  %len = load i32, ptr %len_p, align 4, !noundef !0, !range !1
37  br label %loop
38
39loop:
40  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
41  %el.ptr = getelementptr i32, ptr %p, i32 %iv
42  %el = load i32, ptr %el.ptr, align 4
43  %bound_check = icmp ult i32 %el, 128
44  br i1 %bound_check, label %do_range_check, label %bound_check_failed
45
46do_range_check:
47  call void @llvm.assume(i1 %bound_check)
48  %range_check.ult = icmp ult i32 %el, %len
49  %wc = call i1 @llvm.experimental.widenable.condition()
50  %explicit_guard_cond = and i1 %range_check.ult, %wc
51  br i1 %explicit_guard_cond, label %backedge, label %deopt
52
53backedge:
54  %arr.ptr = getelementptr i32, ptr %arr, i32 %el
55  store i32 %iv, ptr %arr.ptr, align 4
56  %iv.next = add i32 %iv, 1
57  %loop_cond = icmp slt i32 %iv.next, %n
58  br i1 %loop_cond, label %loop, label %exit
59
60deopt:
61  %deopt_res = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
62  ret i32 %deopt_res
63
64exit:
65  ret i32 0
66
67bound_check_failed:
68  ret i32 -1
69}
70
71define i32 @test_slt(ptr noundef %p, i32 noundef %n, ptr noundef %arr, ptr noundef %len_p, i32 noundef %c) {
72; CHECK-LABEL: @test_slt(
73; CHECK-NEXT:  entry:
74; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1
75; CHECK-NEXT:    br label [[LOOP:%.*]]
76; CHECK:       loop:
77; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
78; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
79; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
80; CHECK-NEXT:    [[BOUND_CHECK:%.*]] = icmp slt i32 [[EL]], 128
81; CHECK-NEXT:    br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]]
82; CHECK:       do_range_check:
83; CHECK-NEXT:    call void @llvm.assume(i1 [[BOUND_CHECK]])
84; CHECK-NEXT:    [[RANGE_CHECK_SLT:%.*]] = icmp slt i32 [[EL]], [[LEN]]
85; CHECK-NEXT:    [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
86; CHECK-NEXT:    [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLT]], [[WC]]
87; CHECK-NEXT:    br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]]
88; CHECK:       backedge:
89; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
90; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4
91; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
92; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[N:%.*]]
93; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
94; CHECK:       deopt:
95; CHECK-NEXT:    [[DEOPT_RES:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
96; CHECK-NEXT:    ret i32 [[DEOPT_RES]]
97; CHECK:       exit:
98; CHECK-NEXT:    ret i32 0
99; CHECK:       bound_check_failed:
100; CHECK-NEXT:    ret i32 -1
101;
102entry:
103  %len = load i32, ptr %len_p, align 4, !noundef !0, !range !1
104  br label %loop
105
106loop:
107  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
108  %el.ptr = getelementptr i32, ptr %p, i32 %iv
109  %el = load i32, ptr %el.ptr, align 4
110  %bound_check = icmp slt i32 %el, 128
111  br i1 %bound_check, label %do_range_check, label %bound_check_failed
112
113do_range_check:
114  call void @llvm.assume(i1 %bound_check)
115  %range_check.slt = icmp slt i32 %el, %len
116  %wc = call i1 @llvm.experimental.widenable.condition()
117  %explicit_guard_cond = and i1 %range_check.slt, %wc
118  br i1 %explicit_guard_cond, label %backedge, label %deopt
119
120backedge:
121  %arr.ptr = getelementptr i32, ptr %arr, i32 %el
122  store i32 %iv, ptr %arr.ptr, align 4
123  %iv.next = add i32 %iv, 1
124  %loop_cond = icmp ult i32 %iv.next, %n
125  br i1 %loop_cond, label %loop, label %exit
126
127deopt:
128  %deopt_res = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
129  ret i32 %deopt_res
130
131exit:
132  ret i32 0
133
134bound_check_failed:
135  ret i32 -1
136}
137
138define i32 @test_ule(ptr noundef %p, i32 noundef %n, ptr noundef %arr, ptr noundef %len_p, i32 noundef %c) {
139; CHECK-LABEL: @test_ule(
140; CHECK-NEXT:  entry:
141; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1
142; CHECK-NEXT:    br label [[LOOP:%.*]]
143; CHECK:       loop:
144; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
145; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
146; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
147; CHECK-NEXT:    [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], 128
148; CHECK-NEXT:    br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]]
149; CHECK:       do_range_check:
150; CHECK-NEXT:    call void @llvm.assume(i1 [[BOUND_CHECK]])
151; CHECK-NEXT:    [[RANGE_CHECK_ULE:%.*]] = icmp ule i32 [[EL]], [[LEN]]
152; CHECK-NEXT:    [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
153; CHECK-NEXT:    [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_ULE]], [[WC]]
154; CHECK-NEXT:    br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]]
155; CHECK:       backedge:
156; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
157; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4
158; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
159; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[N:%.*]]
160; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
161; CHECK:       deopt:
162; CHECK-NEXT:    [[DEOPT_RES:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
163; CHECK-NEXT:    ret i32 [[DEOPT_RES]]
164; CHECK:       exit:
165; CHECK-NEXT:    ret i32 0
166; CHECK:       bound_check_failed:
167; CHECK-NEXT:    ret i32 -1
168;
169entry:
170  %len = load i32, ptr %len_p, align 4, !noundef !0, !range !1
171  br label %loop
172
173loop:
174  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
175  %el.ptr = getelementptr i32, ptr %p, i32 %iv
176  %el = load i32, ptr %el.ptr, align 4
177  %bound_check = icmp ult i32 %el, 128
178  br i1 %bound_check, label %do_range_check, label %bound_check_failed
179
180do_range_check:
181  call void @llvm.assume(i1 %bound_check)
182  %range_check.ule = icmp ule i32 %el, %len
183  %wc = call i1 @llvm.experimental.widenable.condition()
184  %explicit_guard_cond = and i1 %range_check.ule, %wc
185  br i1 %explicit_guard_cond, label %backedge, label %deopt
186
187backedge:
188  %arr.ptr = getelementptr i32, ptr %arr, i32 %el
189  store i32 %iv, ptr %arr.ptr, align 4
190  %iv.next = add i32 %iv, 1
191  %loop_cond = icmp ult i32 %iv.next, %n
192  br i1 %loop_cond, label %loop, label %exit
193
194deopt:
195  %deopt_res = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
196  ret i32 %deopt_res
197
198exit:
199  ret i32 0
200
201bound_check_failed:
202  ret i32 -1
203}
204
205define i32 @test_sle(ptr noundef %p, i32 noundef %n, ptr noundef %arr, ptr noundef %len_p, i32 noundef %c) {
206; CHECK-LABEL: @test_sle(
207; CHECK-NEXT:  entry:
208; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1
209; CHECK-NEXT:    br label [[LOOP:%.*]]
210; CHECK:       loop:
211; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
212; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
213; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
214; CHECK-NEXT:    [[BOUND_CHECK:%.*]] = icmp slt i32 [[EL]], 128
215; CHECK-NEXT:    br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]]
216; CHECK:       do_range_check:
217; CHECK-NEXT:    call void @llvm.assume(i1 [[BOUND_CHECK]])
218; CHECK-NEXT:    [[RANGE_CHECK_SLE:%.*]] = icmp sle i32 [[EL]], [[LEN]]
219; CHECK-NEXT:    [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
220; CHECK-NEXT:    [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]]
221; CHECK-NEXT:    br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]]
222; CHECK:       backedge:
223; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
224; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4
225; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
226; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[N:%.*]]
227; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
228; CHECK:       deopt:
229; CHECK-NEXT:    [[DEOPT_RES:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
230; CHECK-NEXT:    ret i32 [[DEOPT_RES]]
231; CHECK:       exit:
232; CHECK-NEXT:    ret i32 0
233; CHECK:       bound_check_failed:
234; CHECK-NEXT:    ret i32 -1
235;
236entry:
237  %len = load i32, ptr %len_p, align 4, !noundef !0, !range !1
238  br label %loop
239
240loop:
241  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
242  %el.ptr = getelementptr i32, ptr %p, i32 %iv
243  %el = load i32, ptr %el.ptr, align 4
244  %bound_check = icmp slt i32 %el, 128
245  br i1 %bound_check, label %do_range_check, label %bound_check_failed
246
247do_range_check:
248  call void @llvm.assume(i1 %bound_check)
249  %range_check.sle = icmp sle i32 %el, %len
250  %wc = call i1 @llvm.experimental.widenable.condition()
251  %explicit_guard_cond = and i1 %range_check.sle, %wc
252  br i1 %explicit_guard_cond, label %backedge, label %deopt
253
254backedge:
255  %arr.ptr = getelementptr i32, ptr %arr, i32 %el
256  store i32 %iv, ptr %arr.ptr, align 4
257  %iv.next = add i32 %iv, 1
258  %loop_cond = icmp ult i32 %iv.next, %n
259  br i1 %loop_cond, label %loop, label %exit
260
261deopt:
262  %deopt_res = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
263  ret i32 %deopt_res
264
265exit:
266  ret i32 0
267
268bound_check_failed:
269  ret i32 -1
270}
271
272define i32 @test_ugt(ptr noundef %p, i32 noundef %n, ptr noundef %arr, ptr noundef %len_p, i32 noundef %c) {
273; CHECK-LABEL: @test_ugt(
274; CHECK-NEXT:  entry:
275; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1
276; CHECK-NEXT:    br label [[LOOP:%.*]]
277; CHECK:       loop:
278; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
279; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
280; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
281; CHECK-NEXT:    [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], 128
282; CHECK-NEXT:    br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]]
283; CHECK:       do_range_check:
284; CHECK-NEXT:    call void @llvm.assume(i1 [[BOUND_CHECK]])
285; CHECK-NEXT:    [[RANGE_CHECK_SLE:%.*]] = icmp ugt i32 [[LEN]], [[EL]]
286; CHECK-NEXT:    [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
287; CHECK-NEXT:    [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]]
288; CHECK-NEXT:    br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]]
289; CHECK:       backedge:
290; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
291; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4
292; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
293; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[N:%.*]]
294; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
295; CHECK:       deopt:
296; CHECK-NEXT:    [[DEOPT_RES:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
297; CHECK-NEXT:    ret i32 [[DEOPT_RES]]
298; CHECK:       exit:
299; CHECK-NEXT:    ret i32 0
300; CHECK:       bound_check_failed:
301; CHECK-NEXT:    ret i32 -1
302;
303entry:
304  %len = load i32, ptr %len_p, align 4, !noundef !0, !range !1
305  br label %loop
306
307loop:
308  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
309  %el.ptr = getelementptr i32, ptr %p, i32 %iv
310  %el = load i32, ptr %el.ptr, align 4
311  %bound_check = icmp ult i32 %el, 128
312  br i1 %bound_check, label %do_range_check, label %bound_check_failed
313
314do_range_check:
315  call void @llvm.assume(i1 %bound_check)
316  %range_check.sle = icmp ugt i32 %len, %el
317  %wc = call i1 @llvm.experimental.widenable.condition()
318  %explicit_guard_cond = and i1 %range_check.sle, %wc
319  br i1 %explicit_guard_cond, label %backedge, label %deopt
320
321backedge:
322  %arr.ptr = getelementptr i32, ptr %arr, i32 %el
323  store i32 %iv, ptr %arr.ptr, align 4
324  %iv.next = add i32 %iv, 1
325  %loop_cond = icmp ult i32 %iv.next, %n
326  br i1 %loop_cond, label %loop, label %exit
327
328deopt:
329  %deopt_res = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
330  ret i32 %deopt_res
331
332exit:
333  ret i32 0
334
335bound_check_failed:
336  ret i32 -1
337}
338
339define i32 @test_uge(ptr noundef %p, i32 noundef %n, ptr noundef %arr, ptr noundef %len_p, i32 noundef %c) {
340; CHECK-LABEL: @test_uge(
341; CHECK-NEXT:  entry:
342; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1
343; CHECK-NEXT:    br label [[LOOP:%.*]]
344; CHECK:       loop:
345; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
346; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
347; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
348; CHECK-NEXT:    [[BOUND_CHECK:%.*]] = icmp ult i32 [[EL]], 128
349; CHECK-NEXT:    br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]]
350; CHECK:       do_range_check:
351; CHECK-NEXT:    call void @llvm.assume(i1 [[BOUND_CHECK]])
352; CHECK-NEXT:    [[RANGE_CHECK_SLE:%.*]] = icmp uge i32 [[LEN]], [[EL]]
353; CHECK-NEXT:    [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
354; CHECK-NEXT:    [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]]
355; CHECK-NEXT:    br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]]
356; CHECK:       backedge:
357; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
358; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4
359; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
360; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[N:%.*]]
361; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
362; CHECK:       deopt:
363; CHECK-NEXT:    [[DEOPT_RES:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
364; CHECK-NEXT:    ret i32 [[DEOPT_RES]]
365; CHECK:       exit:
366; CHECK-NEXT:    ret i32 0
367; CHECK:       bound_check_failed:
368; CHECK-NEXT:    ret i32 -1
369;
370entry:
371  %len = load i32, ptr %len_p, align 4, !noundef !0, !range !1
372  br label %loop
373
374loop:
375  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
376  %el.ptr = getelementptr i32, ptr %p, i32 %iv
377  %el = load i32, ptr %el.ptr, align 4
378  %bound_check = icmp ult i32 %el, 128
379  br i1 %bound_check, label %do_range_check, label %bound_check_failed
380
381do_range_check:
382  call void @llvm.assume(i1 %bound_check)
383  %range_check.sle = icmp uge i32 %len, %el
384  %wc = call i1 @llvm.experimental.widenable.condition()
385  %explicit_guard_cond = and i1 %range_check.sle, %wc
386  br i1 %explicit_guard_cond, label %backedge, label %deopt
387
388backedge:
389  %arr.ptr = getelementptr i32, ptr %arr, i32 %el
390  store i32 %iv, ptr %arr.ptr, align 4
391  %iv.next = add i32 %iv, 1
392  %loop_cond = icmp ult i32 %iv.next, %n
393  br i1 %loop_cond, label %loop, label %exit
394
395deopt:
396  %deopt_res = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
397  ret i32 %deopt_res
398
399exit:
400  ret i32 0
401
402bound_check_failed:
403  ret i32 -1
404}
405
406define i32 @test_sgt(ptr noundef %p, i32 noundef %n, ptr noundef %arr, ptr noundef %len_p, i32 noundef %c) {
407; CHECK-LABEL: @test_sgt(
408; CHECK-NEXT:  entry:
409; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1
410; CHECK-NEXT:    br label [[LOOP:%.*]]
411; CHECK:       loop:
412; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
413; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
414; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
415; CHECK-NEXT:    [[BOUND_CHECK:%.*]] = icmp slt i32 [[EL]], 128
416; CHECK-NEXT:    br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]]
417; CHECK:       do_range_check:
418; CHECK-NEXT:    call void @llvm.assume(i1 [[BOUND_CHECK]])
419; CHECK-NEXT:    [[RANGE_CHECK_SLE:%.*]] = icmp sgt i32 [[LEN]], [[EL]]
420; CHECK-NEXT:    [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
421; CHECK-NEXT:    [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]]
422; CHECK-NEXT:    br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]]
423; CHECK:       backedge:
424; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
425; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4
426; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
427; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[N:%.*]]
428; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
429; CHECK:       deopt:
430; CHECK-NEXT:    [[DEOPT_RES:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
431; CHECK-NEXT:    ret i32 [[DEOPT_RES]]
432; CHECK:       exit:
433; CHECK-NEXT:    ret i32 0
434; CHECK:       bound_check_failed:
435; CHECK-NEXT:    ret i32 -1
436;
437entry:
438  %len = load i32, ptr %len_p, align 4, !noundef !0, !range !1
439  br label %loop
440
441loop:
442  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
443  %el.ptr = getelementptr i32, ptr %p, i32 %iv
444  %el = load i32, ptr %el.ptr, align 4
445  %bound_check = icmp slt i32 %el, 128
446  br i1 %bound_check, label %do_range_check, label %bound_check_failed
447
448do_range_check:
449  call void @llvm.assume(i1 %bound_check)
450  %range_check.sle = icmp sgt i32 %len, %el
451  %wc = call i1 @llvm.experimental.widenable.condition()
452  %explicit_guard_cond = and i1 %range_check.sle, %wc
453  br i1 %explicit_guard_cond, label %backedge, label %deopt
454
455backedge:
456  %arr.ptr = getelementptr i32, ptr %arr, i32 %el
457  store i32 %iv, ptr %arr.ptr, align 4
458  %iv.next = add i32 %iv, 1
459  %loop_cond = icmp ult i32 %iv.next, %n
460  br i1 %loop_cond, label %loop, label %exit
461
462deopt:
463  %deopt_res = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
464  ret i32 %deopt_res
465
466exit:
467  ret i32 0
468
469bound_check_failed:
470  ret i32 -1
471}
472
473define i32 @test_sge(ptr noundef %p, i32 noundef %n, ptr noundef %arr, ptr noundef %len_p, i32 noundef %c) {
474; CHECK-LABEL: @test_sge(
475; CHECK-NEXT:  entry:
476; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1
477; CHECK-NEXT:    br label [[LOOP:%.*]]
478; CHECK:       loop:
479; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
480; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
481; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
482; CHECK-NEXT:    [[BOUND_CHECK:%.*]] = icmp slt i32 [[EL]], 128
483; CHECK-NEXT:    br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]]
484; CHECK:       do_range_check:
485; CHECK-NEXT:    call void @llvm.assume(i1 [[BOUND_CHECK]])
486; CHECK-NEXT:    [[RANGE_CHECK_SLE:%.*]] = icmp sge i32 [[LEN]], [[EL]]
487; CHECK-NEXT:    [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
488; CHECK-NEXT:    [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]]
489; CHECK-NEXT:    br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]]
490; CHECK:       backedge:
491; CHECK-NEXT:    [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]]
492; CHECK-NEXT:    store i32 [[IV]], ptr [[ARR_PTR]], align 4
493; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
494; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[N:%.*]]
495; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
496; CHECK:       deopt:
497; CHECK-NEXT:    [[DEOPT_RES:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
498; CHECK-NEXT:    ret i32 [[DEOPT_RES]]
499; CHECK:       exit:
500; CHECK-NEXT:    ret i32 0
501; CHECK:       bound_check_failed:
502; CHECK-NEXT:    ret i32 -1
503;
504entry:
505  %len = load i32, ptr %len_p, align 4, !noundef !0, !range !1
506  br label %loop
507
508loop:
509  %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
510  %el.ptr = getelementptr i32, ptr %p, i32 %iv
511  %el = load i32, ptr %el.ptr, align 4
512  %bound_check = icmp slt i32 %el, 128
513  br i1 %bound_check, label %do_range_check, label %bound_check_failed
514
515do_range_check:
516  call void @llvm.assume(i1 %bound_check)
517  %range_check.sle = icmp sge i32 %len, %el
518  %wc = call i1 @llvm.experimental.widenable.condition()
519  %explicit_guard_cond = and i1 %range_check.sle, %wc
520  br i1 %explicit_guard_cond, label %backedge, label %deopt
521
522backedge:
523  %arr.ptr = getelementptr i32, ptr %arr, i32 %el
524  store i32 %iv, ptr %arr.ptr, align 4
525  %iv.next = add i32 %iv, 1
526  %loop_cond = icmp ult i32 %iv.next, %n
527  br i1 %loop_cond, label %loop, label %exit
528
529deopt:
530  %deopt_res = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
531  ret i32 %deopt_res
532
533exit:
534  ret i32 0
535
536bound_check_failed:
537  ret i32 -1
538}
539
540; Function Attrs: inaccessiblememonly nocallback nofree nosync nounwind speculatable willreturn
541declare i1 @llvm.experimental.widenable.condition() #1
542
543declare i32 @llvm.experimental.deoptimize.i32(...)
544
545declare void @llvm.assume(i1)
546
547attributes #1 = { inaccessiblememonly nocallback nofree nosync nounwind speculatable willreturn }
548
549!0 = !{}
550!1 = !{i32 0, i32 2147483646}
551