xref: /llvm-project/llvm/test/Transforms/IndVarSimplify/predicated_ranges.ll (revision ab07cbe4377a1c5aca3693fd01c347eea7ac6988)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes=indvars -S < %s | FileCheck %s
3
4; Check that we are able to remove the range check basing on the following facts:
5; 0 <= len <= MAX_INT [1];
6; iv starts from len and goes down stopping at zero and [1], therefore
7;   0 <= iv <= len [2];
8; 3. In range_check_block, iv != 0 and [2], therefore
9;   1 <= iv <= len [3];
10; 4. iv.next = iv - 1 and [3], therefore
11;   0 <= iv.next < len.
12define void @test_predicated_simple_unsigned(ptr %p, ptr %arr) {
13; CHECK-LABEL: @test_predicated_simple_unsigned(
14; CHECK-NEXT:  preheader:
15; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4, !range [[RNG0:![0-9]+]]
16; CHECK-NEXT:    br label [[LOOP:%.*]]
17; CHECK:       loop:
18; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
19; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
20; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
21; CHECK:       range_check_block:
22; CHECK-NEXT:    [[IV_NEXT]] = sub nuw nsw i32 [[IV]], 1
23; CHECK-NEXT:    br i1 true, label [[BACKEDGE]], label [[FAIL:%.*]]
24; CHECK:       backedge:
25; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
26; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
27; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
28; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
29; CHECK:       exit:
30; CHECK-NEXT:    ret void
31; CHECK:       fail:
32; CHECK-NEXT:    unreachable
33;
34preheader:
35  %len = load i32, ptr %p, !range !0
36  br label %loop
37
38loop:
39  %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
40  %zero_cond = icmp eq i32 %iv, 0
41  br i1 %zero_cond, label %exit, label %range_check_block
42
43range_check_block:
44  %iv.next = sub i32 %iv, 1
45  %range_check = icmp ult i32 %iv.next, %len
46  br i1 %range_check, label %backedge, label %fail
47
48backedge:
49  %el.ptr = getelementptr i32, ptr %p, i32 %iv
50  %el = load i32, ptr %el.ptr
51  %loop.cond = icmp eq i32 %el, 0
52  br i1 %loop.cond, label %loop, label %exit
53
54exit:
55  ret void
56
57fail:
58  unreachable
59}
60
61define void @test_predicated_simple_signed(ptr %p, ptr %arr) {
62; CHECK-LABEL: @test_predicated_simple_signed(
63; CHECK-NEXT:  preheader:
64; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4, !range [[RNG0]]
65; CHECK-NEXT:    br label [[LOOP:%.*]]
66; CHECK:       loop:
67; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
68; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
69; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
70; CHECK:       range_check_block:
71; CHECK-NEXT:    [[IV_NEXT]] = sub nuw nsw i32 [[IV]], 1
72; CHECK-NEXT:    br i1 true, label [[BACKEDGE]], label [[FAIL:%.*]]
73; CHECK:       backedge:
74; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
75; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
76; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
77; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
78; CHECK:       exit:
79; CHECK-NEXT:    ret void
80; CHECK:       fail:
81; CHECK-NEXT:    unreachable
82;
83preheader:
84  %len = load i32, ptr %p, !range !0
85  br label %loop
86
87loop:
88  %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
89  %zero_cond = icmp eq i32 %iv, 0
90  br i1 %zero_cond, label %exit, label %range_check_block
91
92range_check_block:
93  %iv.next = sub i32 %iv, 1
94  %range_check = icmp slt i32 %iv.next, %len
95  br i1 %range_check, label %backedge, label %fail
96
97backedge:
98  %el.ptr = getelementptr i32, ptr %p, i32 %iv
99  %el = load i32, ptr %el.ptr
100  %loop.cond = icmp eq i32 %el, 0
101  br i1 %loop.cond, label %loop, label %exit
102
103exit:
104  ret void
105
106fail:
107  unreachable
108}
109
110; Cannot remove checks because the range check fails on the last iteration.
111define void @predicated_outside_loop_signed_neg(i32 %arg) nounwind #0 {
112; CHECK-LABEL: @predicated_outside_loop_signed_neg(
113; CHECK-NEXT:  entry:
114; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
115; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
116; CHECK-NEXT:    br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
117; CHECK:       outer.preheader:
118; CHECK-NEXT:    br label [[OUTER:%.*]]
119; CHECK:       outer:
120; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
121; CHECK-NEXT:    [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
122; CHECK-NEXT:    [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
123; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
124; CHECK-NEXT:    br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
125; CHECK:       inner.ph:
126; CHECK-NEXT:    br label [[INNER:%.*]]
127; CHECK:       inner:
128; CHECK-NEXT:    br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
129; CHECK:       outer.inc.loopexit:
130; CHECK-NEXT:    br label [[OUTER_INC]]
131; CHECK:       outer.inc:
132; CHECK-NEXT:    [[I_INC]] = add nuw nsw i32 [[I]], 1
133; CHECK-NEXT:    br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
134; CHECK:       exit.loopexit:
135; CHECK-NEXT:    br label [[EXIT]]
136; CHECK:       exit:
137; CHECK-NEXT:    ret void
138;
139entry:
140  %sub1 = sub nsw i32 %arg, 1
141  %cmp1 = icmp slt i32 0, %sub1
142  br i1 %cmp1, label %outer, label %exit
143
144outer:
145  %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
146  %sub2 = sub nsw i32 %arg, %i
147  %sub3 = sub nsw i32 %sub2, 1
148  %cmp2 = icmp slt i32 0, %sub3
149  br i1 %cmp2, label %inner.ph, label %outer.inc
150
151inner.ph:
152  br label %inner
153
154inner:
155  %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
156  %j.inc = add nsw i32 %j, 1
157  %cmp3 = icmp slt i32 %j.inc, %sub3
158  br i1 %cmp3, label %inner, label %outer.inc
159
160outer.inc:
161  %i.inc = add nsw i32 %i, 1
162  %cmp4 = icmp slt i32 %i.inc, %arg
163  br i1 %cmp4, label %outer, label %exit
164
165exit:
166  ret void
167}
168
169; Range check can be removed.
170define void @predicated_outside_loop_signed_pos(i32 %arg) nounwind #0 {
171; CHECK-LABEL: @predicated_outside_loop_signed_pos(
172; CHECK-NEXT:  entry:
173; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
174; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
175; CHECK-NEXT:    br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
176; CHECK:       outer.preheader:
177; CHECK-NEXT:    br label [[OUTER:%.*]]
178; CHECK:       outer:
179; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
180; CHECK-NEXT:    [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
181; CHECK-NEXT:    [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
182; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
183; CHECK-NEXT:    br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
184; CHECK:       inner.ph:
185; CHECK-NEXT:    br label [[INNER:%.*]]
186; CHECK:       inner:
187; CHECK-NEXT:    br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
188; CHECK:       outer.inc.loopexit:
189; CHECK-NEXT:    br label [[OUTER_INC]]
190; CHECK:       outer.inc:
191; CHECK-NEXT:    [[I_INC]] = add nuw nsw i32 [[I]], 1
192; CHECK-NEXT:    br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
193; CHECK:       exit.loopexit:
194; CHECK-NEXT:    br label [[EXIT]]
195; CHECK:       exit:
196; CHECK-NEXT:    ret void
197;
198entry:
199  %sub1 = sub nsw i32 %arg, 1
200  %cmp1 = icmp slt i32 0, %sub1
201  br i1 %cmp1, label %outer, label %exit
202
203outer:
204  %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
205  %sub2 = sub nsw i32 %arg, %i
206  %sub3 = sub nsw i32 %sub2, 1
207  %cmp2 = icmp slt i32 0, %sub3
208  br i1 %cmp2, label %inner.ph, label %outer.inc
209
210inner.ph:
211  br label %inner
212
213inner:
214  %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
215  %j.inc = add nsw i32 %j, 1
216  %cmp3 = icmp slt i32 %j.inc, %sub3
217  br i1 %cmp3, label %inner, label %outer.inc
218
219outer.inc:
220  %i.inc = add nsw i32 %i, 1
221  %cmp4 = icmp slt i32 %i.inc, %sub1
222  br i1 %cmp4, label %outer, label %exit
223
224exit:
225  ret void
226}
227
228define void @predicated_outside_loop_unsigned(i32 %arg) nounwind #0 {
229; CHECK-LABEL: @predicated_outside_loop_unsigned(
230; CHECK-NEXT:  entry:
231; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
232; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
233; CHECK-NEXT:    br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
234; CHECK:       outer.preheader:
235; CHECK-NEXT:    br label [[OUTER:%.*]]
236; CHECK:       outer:
237; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
238; CHECK-NEXT:    [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
239; CHECK-NEXT:    [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
240; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 0, [[SUB3]]
241; CHECK-NEXT:    br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
242; CHECK:       inner.ph:
243; CHECK-NEXT:    br label [[INNER:%.*]]
244; CHECK:       inner:
245; CHECK-NEXT:    br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
246; CHECK:       outer.inc.loopexit:
247; CHECK-NEXT:    br label [[OUTER_INC]]
248; CHECK:       outer.inc:
249; CHECK-NEXT:    [[I_INC]] = add nuw nsw i32 [[I]], 1
250; CHECK-NEXT:    br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
251; CHECK:       exit.loopexit:
252; CHECK-NEXT:    br label [[EXIT]]
253; CHECK:       exit:
254; CHECK-NEXT:    ret void
255;
256entry:
257  %sub1 = sub nsw i32 %arg, 1
258  %cmp1 = icmp slt i32 0, %sub1
259  br i1 %cmp1, label %outer, label %exit
260
261outer:
262  %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
263  %sub2 = sub nsw i32 %arg, %i
264  %sub3 = sub nsw i32 %sub2, 1
265  %cmp2 = icmp ult i32 0, %sub3
266  br i1 %cmp2, label %inner.ph, label %outer.inc
267
268inner.ph:
269  br label %inner
270
271inner:
272  %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
273  %j.inc = add nsw i32 %j, 1
274  %cmp3 = icmp slt i32 %j.inc, %sub3
275  br i1 %cmp3, label %inner, label %outer.inc
276
277outer.inc:
278  %i.inc = add nsw i32 %i, 1
279  %cmp4 = icmp slt i32 %i.inc, %arg
280  br i1 %cmp4, label %outer, label %exit
281
282exit:
283  ret void
284}
285
286; Cannot remove checks because the range check fails on the last iteration.
287define void @predicated_inside_loop_signed_neg(i32 %arg) nounwind #0 {
288; CHECK-LABEL: @predicated_inside_loop_signed_neg(
289; CHECK-NEXT:  entry:
290; CHECK-NEXT:    br label [[OUTER:%.*]]
291; CHECK:       outer:
292; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ]
293; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
294; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
295; CHECK-NEXT:    br i1 [[CMP1]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
296; CHECK:       guarded:
297; CHECK-NEXT:    [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
298; CHECK-NEXT:    [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
299; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
300; CHECK-NEXT:    br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
301; CHECK:       inner.ph:
302; CHECK-NEXT:    br label [[INNER:%.*]]
303; CHECK:       inner:
304; CHECK-NEXT:    br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
305; CHECK:       outer.inc.loopexit:
306; CHECK-NEXT:    br label [[OUTER_INC]]
307; CHECK:       outer.inc:
308; CHECK-NEXT:    [[I_INC]] = add nuw nsw i32 [[I]], 1
309; CHECK-NEXT:    [[CMP4:%.*]] = icmp slt i32 [[I_INC]], [[ARG]]
310; CHECK-NEXT:    br i1 [[CMP4]], label [[OUTER]], label [[EXIT]]
311; CHECK:       exit:
312; CHECK-NEXT:    ret void
313;
314entry:
315  br label %outer
316
317outer:
318  %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
319  %sub1 = sub nsw i32 %arg, 1
320  %cmp1 = icmp slt i32 0, %sub1
321  br i1 %cmp1, label %guarded, label %exit
322
323guarded:
324  %sub2 = sub nsw i32 %arg, %i
325  %sub3 = sub nsw i32 %sub2, 1
326  %cmp2 = icmp slt i32 0, %sub3
327  br i1 %cmp2, label %inner.ph, label %outer.inc
328
329inner.ph:
330  br label %inner
331
332inner:
333  %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
334  %j.inc = add nsw i32 %j, 1
335  %cmp3 = icmp slt i32 %j.inc, %sub3
336  br i1 %cmp3, label %inner, label %outer.inc
337
338outer.inc:
339  %i.inc = add nsw i32 %i, 1
340  %cmp4 = icmp slt i32 %i.inc, %arg
341  br i1 %cmp4, label %outer, label %exit
342
343exit:
344  ret void
345}
346
347; Range check can be trivially removed.
348define void @predicated_inside_loop_signed_pos(i32 %arg) nounwind #0 {
349; CHECK-LABEL: @predicated_inside_loop_signed_pos(
350; CHECK-NEXT:  entry:
351; CHECK-NEXT:    br label [[OUTER:%.*]]
352; CHECK:       outer:
353; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ]
354; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
355; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
356; CHECK-NEXT:    br i1 [[CMP1]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
357; CHECK:       guarded:
358; CHECK-NEXT:    [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
359; CHECK-NEXT:    [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
360; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
361; CHECK-NEXT:    br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
362; CHECK:       inner.ph:
363; CHECK-NEXT:    br label [[INNER:%.*]]
364; CHECK:       inner:
365; CHECK-NEXT:    br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
366; CHECK:       outer.inc.loopexit:
367; CHECK-NEXT:    br label [[OUTER_INC]]
368; CHECK:       outer.inc:
369; CHECK-NEXT:    [[I_INC]] = add nuw nsw i32 [[I]], 1
370; CHECK-NEXT:    [[CMP4:%.*]] = icmp slt i32 [[I_INC]], [[SUB1]]
371; CHECK-NEXT:    br i1 [[CMP4]], label [[OUTER]], label [[EXIT]]
372; CHECK:       exit:
373; CHECK-NEXT:    ret void
374;
375entry:
376  br label %outer
377
378outer:
379  %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
380  %sub1 = sub nsw i32 %arg, 1
381  %cmp1 = icmp slt i32 0, %sub1
382  br i1 %cmp1, label %guarded, label %exit
383
384guarded:
385  %sub2 = sub nsw i32 %arg, %i
386  %sub3 = sub nsw i32 %sub2, 1
387  %cmp2 = icmp slt i32 0, %sub3
388  br i1 %cmp2, label %inner.ph, label %outer.inc
389
390inner.ph:
391  br label %inner
392
393inner:
394  %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
395  %j.inc = add nsw i32 %j, 1
396  %cmp3 = icmp slt i32 %j.inc, %sub3
397  br i1 %cmp3, label %inner, label %outer.inc
398
399outer.inc:
400  %i.inc = add nsw i32 %i, 1
401  %cmp4 = icmp slt i32 %i.inc, %sub1
402  br i1 %cmp4, label %outer, label %exit
403
404exit:
405  ret void
406}
407
408define void @predicated_inside_loop_unsigned(i32 %arg) nounwind #0 {
409; CHECK-LABEL: @predicated_inside_loop_unsigned(
410; CHECK-NEXT:  entry:
411; CHECK-NEXT:    br label [[OUTER:%.*]]
412; CHECK:       outer:
413; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ]
414; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
415; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
416; CHECK-NEXT:    br i1 [[CMP1]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
417; CHECK:       guarded:
418; CHECK-NEXT:    [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
419; CHECK-NEXT:    [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
420; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 0, [[SUB3]]
421; CHECK-NEXT:    br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
422; CHECK:       inner.ph:
423; CHECK-NEXT:    br label [[INNER:%.*]]
424; CHECK:       inner:
425; CHECK-NEXT:    br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
426; CHECK:       outer.inc.loopexit:
427; CHECK-NEXT:    br label [[OUTER_INC]]
428; CHECK:       outer.inc:
429; CHECK-NEXT:    [[I_INC]] = add nuw nsw i32 [[I]], 1
430; CHECK-NEXT:    [[CMP4:%.*]] = icmp slt i32 [[I_INC]], [[ARG]]
431; CHECK-NEXT:    br i1 [[CMP4]], label [[OUTER]], label [[EXIT]]
432; CHECK:       exit:
433; CHECK-NEXT:    ret void
434;
435entry:
436  br label %outer
437
438outer:
439  %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
440  %sub1 = sub nsw i32 %arg, 1
441  %cmp1 = icmp slt i32 0, %sub1
442  br i1 %cmp1, label %guarded, label %exit
443
444guarded:
445  %sub2 = sub nsw i32 %arg, %i
446  %sub3 = sub nsw i32 %sub2, 1
447  %cmp2 = icmp ult i32 0, %sub3
448  br i1 %cmp2, label %inner.ph, label %outer.inc
449
450inner.ph:
451  br label %inner
452
453inner:
454  %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
455  %j.inc = add nsw i32 %j, 1
456  %cmp3 = icmp slt i32 %j.inc, %sub3
457  br i1 %cmp3, label %inner, label %outer.inc
458
459outer.inc:
460  %i.inc = add nsw i32 %i, 1
461  %cmp4 = icmp slt i32 %i.inc, %arg
462  br i1 %cmp4, label %outer, label %exit
463
464exit:
465  ret void
466}
467
468define void @test_can_predicate_simple_unsigned(ptr %p, ptr %arr) {
469; CHECK-LABEL: @test_can_predicate_simple_unsigned(
470; CHECK-NEXT:  preheader:
471; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
472; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[LEN]], -1
473; CHECK-NEXT:    [[RANGE_CHECK_FIRST_ITER:%.*]] = icmp ult i32 [[TMP0]], [[LEN]]
474; CHECK-NEXT:    br label [[LOOP:%.*]]
475; CHECK:       loop:
476; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
477; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
478; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
479; CHECK:       range_check_block:
480; CHECK-NEXT:    [[IV_NEXT]] = sub nuw i32 [[IV]], 1
481; CHECK-NEXT:    br i1 [[RANGE_CHECK_FIRST_ITER]], label [[BACKEDGE]], label [[FAIL:%.*]]
482; CHECK:       backedge:
483; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
484; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
485; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
486; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
487; CHECK:       exit:
488; CHECK-NEXT:    ret void
489; CHECK:       fail:
490; CHECK-NEXT:    unreachable
491;
492preheader:
493  %len = load i32, ptr %p
494  br label %loop
495
496loop:
497  %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
498  %zero_cond = icmp eq i32 %iv, 0
499  br i1 %zero_cond, label %exit, label %range_check_block
500
501range_check_block:
502  %iv.next = sub i32 %iv, 1
503  %range_check = icmp ult i32 %iv.next, %len
504  br i1 %range_check, label %backedge, label %fail
505
506backedge:
507  %el.ptr = getelementptr i32, ptr %p, i32 %iv
508  %el = load i32, ptr %el.ptr
509  %loop.cond = icmp eq i32 %el, 0
510  br i1 %loop.cond, label %loop, label %exit
511
512exit:
513  ret void
514
515fail:
516  unreachable
517}
518
519define void @test_can_predicate_simple_unsigned_inverted(ptr %p, ptr %arr) {
520; CHECK-LABEL: @test_can_predicate_simple_unsigned_inverted(
521; CHECK-NEXT:  preheader:
522; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
523; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[LEN]], -1
524; CHECK-NEXT:    [[RANGE_CHECK_FIRST_ITER:%.*]] = icmp uge i32 [[TMP0]], [[LEN]]
525; CHECK-NEXT:    br label [[LOOP:%.*]]
526; CHECK:       loop:
527; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
528; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
529; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
530; CHECK:       range_check_block:
531; CHECK-NEXT:    [[IV_NEXT]] = sub nuw i32 [[IV]], 1
532; CHECK-NEXT:    br i1 [[RANGE_CHECK_FIRST_ITER]], label [[FAIL:%.*]], label [[BACKEDGE]]
533; CHECK:       backedge:
534; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
535; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
536; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
537; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
538; CHECK:       exit:
539; CHECK-NEXT:    ret void
540; CHECK:       fail:
541; CHECK-NEXT:    unreachable
542;
543preheader:
544  %len = load i32, ptr %p
545  br label %loop
546
547loop:
548  %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
549  %zero_cond = icmp eq i32 %iv, 0
550  br i1 %zero_cond, label %exit, label %range_check_block
551
552range_check_block:
553  %iv.next = sub i32 %iv, 1
554  %range_check = icmp uge i32 %iv.next, %len
555  br i1 %range_check, label %fail, label %backedge
556
557backedge:
558  %el.ptr = getelementptr i32, ptr %p, i32 %iv
559  %el = load i32, ptr %el.ptr
560  %loop.cond = icmp eq i32 %el, 0
561  br i1 %loop.cond, label %loop, label %exit
562
563exit:
564  ret void
565
566fail:
567  unreachable
568}
569
570
571define void @test_can_predicate_simple_signed(ptr %p, ptr %arr) {
572; CHECK-LABEL: @test_can_predicate_simple_signed(
573; CHECK-NEXT:  preheader:
574; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
575; CHECK-NEXT:    br label [[LOOP:%.*]]
576; CHECK:       loop:
577; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
578; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
579; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
580; CHECK:       range_check_block:
581; CHECK-NEXT:    [[IV_NEXT]] = sub nuw i32 [[IV]], 1
582; CHECK-NEXT:    [[RANGE_CHECK:%.*]] = icmp slt i32 [[IV_NEXT]], [[LEN]]
583; CHECK-NEXT:    br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
584; CHECK:       backedge:
585; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
586; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
587; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
588; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
589; CHECK:       exit:
590; CHECK-NEXT:    ret void
591; CHECK:       fail:
592; CHECK-NEXT:    unreachable
593;
594preheader:
595  %len = load i32, ptr %p
596  br label %loop
597
598loop:
599  %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
600  %zero_cond = icmp eq i32 %iv, 0
601  br i1 %zero_cond, label %exit, label %range_check_block
602
603range_check_block:
604  %iv.next = sub i32 %iv, 1
605  %range_check = icmp slt i32 %iv.next, %len
606  br i1 %range_check, label %backedge, label %fail
607
608backedge:
609  %el.ptr = getelementptr i32, ptr %p, i32 %iv
610  %el = load i32, ptr %el.ptr
611  %loop.cond = icmp eq i32 %el, 0
612  br i1 %loop.cond, label %loop, label %exit
613
614exit:
615  ret void
616
617fail:
618  unreachable
619}
620
621define void @test_can_predicate_trunc_unsigned(ptr %p, ptr %arr) {
622; CHECK-LABEL: @test_can_predicate_trunc_unsigned(
623; CHECK-NEXT:  preheader:
624; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
625; CHECK-NEXT:    [[START:%.*]] = zext i32 [[LEN]] to i64
626; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[LEN]], -1
627; CHECK-NEXT:    [[RANGE_CHECK_FIRST_ITER:%.*]] = icmp ult i32 [[TMP0]], [[LEN]]
628; CHECK-NEXT:    br label [[LOOP:%.*]]
629; CHECK:       loop:
630; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
631; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i64 [[IV]], 0
632; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
633; CHECK:       range_check_block:
634; CHECK-NEXT:    [[IV_NEXT]] = sub nuw nsw i64 [[IV]], 1
635; CHECK-NEXT:    br i1 [[RANGE_CHECK_FIRST_ITER]], label [[BACKEDGE]], label [[FAIL:%.*]]
636; CHECK:       backedge:
637; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i64 [[IV]]
638; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
639; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
640; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
641; CHECK:       exit:
642; CHECK-NEXT:    ret void
643; CHECK:       fail:
644; CHECK-NEXT:    unreachable
645;
646preheader:
647  %len = load i32, ptr %p
648  %start = zext i32 %len to i64
649  br label %loop
650
651loop:
652  %iv = phi i64 [%start, %preheader], [%iv.next, %backedge]
653  %zero_cond = icmp eq i64 %iv, 0
654  br i1 %zero_cond, label %exit, label %range_check_block
655
656range_check_block:
657  %iv.next = sub i64 %iv, 1
658  %narrow = trunc i64 %iv.next to i32
659  %range_check = icmp ult i32 %narrow, %len
660  br i1 %range_check, label %backedge, label %fail
661
662backedge:
663  %el.ptr = getelementptr i32, ptr %arr, i64 %iv
664  %el = load i32, ptr %el.ptr
665  %loop.cond = icmp eq i32 %el, 0
666  br i1 %loop.cond, label %loop, label %exit
667
668exit:
669  ret void
670
671fail:
672  unreachable
673}
674
675define void @test_can_predicate_trunc_unsigned_inverted(ptr %p, ptr %arr) {
676; CHECK-LABEL: @test_can_predicate_trunc_unsigned_inverted(
677; CHECK-NEXT:  preheader:
678; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
679; CHECK-NEXT:    [[START:%.*]] = zext i32 [[LEN]] to i64
680; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[LEN]], -1
681; CHECK-NEXT:    [[RANGE_CHECK_FIRST_ITER:%.*]] = icmp uge i32 [[TMP0]], [[LEN]]
682; CHECK-NEXT:    br label [[LOOP:%.*]]
683; CHECK:       loop:
684; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
685; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i64 [[IV]], 0
686; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
687; CHECK:       range_check_block:
688; CHECK-NEXT:    [[IV_NEXT]] = sub nuw nsw i64 [[IV]], 1
689; CHECK-NEXT:    br i1 [[RANGE_CHECK_FIRST_ITER]], label [[FAIL:%.*]], label [[BACKEDGE]]
690; CHECK:       backedge:
691; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i64 [[IV]]
692; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
693; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
694; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
695; CHECK:       exit:
696; CHECK-NEXT:    ret void
697; CHECK:       fail:
698; CHECK-NEXT:    unreachable
699;
700preheader:
701  %len = load i32, ptr %p
702  %start = zext i32 %len to i64
703  br label %loop
704
705loop:
706  %iv = phi i64 [%start, %preheader], [%iv.next, %backedge]
707  %zero_cond = icmp eq i64 %iv, 0
708  br i1 %zero_cond, label %exit, label %range_check_block
709
710range_check_block:
711  %iv.next = sub i64 %iv, 1
712  %narrow = trunc i64 %iv.next to i32
713  %range_check = icmp uge i32 %narrow, %len
714  br i1 %range_check, label %fail, label %backedge
715
716backedge:
717  %el.ptr = getelementptr i32, ptr %arr, i64 %iv
718  %el = load i32, ptr %el.ptr
719  %loop.cond = icmp eq i32 %el, 0
720  br i1 %loop.cond, label %loop, label %exit
721
722exit:
723  ret void
724
725fail:
726  unreachable
727}
728
729define void @test_can_predicate_trunc_unsigned_different_start_and_len(ptr %p, i64 %start, ptr %arr) {
730; CHECK-LABEL: @test_can_predicate_trunc_unsigned_different_start_and_len(
731; CHECK-NEXT:  preheader:
732; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
733; CHECK-NEXT:    br label [[LOOP:%.*]]
734; CHECK:       loop:
735; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START:%.*]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
736; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i64 [[IV]], 0
737; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
738; CHECK:       range_check_block:
739; CHECK-NEXT:    [[IV_NEXT]] = sub nuw i64 [[IV]], 1
740; CHECK-NEXT:    [[NARROW:%.*]] = trunc i64 [[IV_NEXT]] to i32
741; CHECK-NEXT:    [[RANGE_CHECK:%.*]] = icmp ult i32 [[NARROW]], [[LEN]]
742; CHECK-NEXT:    br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
743; CHECK:       backedge:
744; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i64 [[IV]]
745; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
746; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
747; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
748; CHECK:       exit:
749; CHECK-NEXT:    ret void
750; CHECK:       fail:
751; CHECK-NEXT:    unreachable
752;
753preheader:
754  %len = load i32, ptr %p
755  br label %loop
756
757loop:
758  %iv = phi i64 [%start, %preheader], [%iv.next, %backedge]
759  %zero_cond = icmp eq i64 %iv, 0
760  br i1 %zero_cond, label %exit, label %range_check_block
761
762range_check_block:
763  %iv.next = sub i64 %iv, 1
764  %narrow = trunc i64 %iv.next to i32
765  %range_check = icmp ult i32 %narrow, %len
766  br i1 %range_check, label %backedge, label %fail
767
768backedge:
769  %el.ptr = getelementptr i32, ptr %arr, i64 %iv
770  %el = load i32, ptr %el.ptr
771  %loop.cond = icmp eq i32 %el, 0
772  br i1 %loop.cond, label %loop, label %exit
773
774exit:
775  ret void
776
777fail:
778  unreachable
779}
780
781define void @test_can_predicate_trunc_unsigned_different_start_and_len_inverted(ptr %p, i64 %start, ptr %arr) {
782; CHECK-LABEL: @test_can_predicate_trunc_unsigned_different_start_and_len_inverted(
783; CHECK-NEXT:  preheader:
784; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
785; CHECK-NEXT:    br label [[LOOP:%.*]]
786; CHECK:       loop:
787; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START:%.*]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
788; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i64 [[IV]], 0
789; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
790; CHECK:       range_check_block:
791; CHECK-NEXT:    [[IV_NEXT]] = sub nuw i64 [[IV]], 1
792; CHECK-NEXT:    [[NARROW:%.*]] = trunc i64 [[IV_NEXT]] to i32
793; CHECK-NEXT:    [[RANGE_CHECK:%.*]] = icmp uge i32 [[NARROW]], [[LEN]]
794; CHECK-NEXT:    br i1 [[RANGE_CHECK]], label [[FAIL:%.*]], label [[BACKEDGE]]
795; CHECK:       backedge:
796; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i64 [[IV]]
797; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
798; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
799; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
800; CHECK:       exit:
801; CHECK-NEXT:    ret void
802; CHECK:       fail:
803; CHECK-NEXT:    unreachable
804;
805preheader:
806  %len = load i32, ptr %p
807  br label %loop
808
809loop:
810  %iv = phi i64 [%start, %preheader], [%iv.next, %backedge]
811  %zero_cond = icmp eq i64 %iv, 0
812  br i1 %zero_cond, label %exit, label %range_check_block
813
814range_check_block:
815  %iv.next = sub i64 %iv, 1
816  %narrow = trunc i64 %iv.next to i32
817  %range_check = icmp uge i32 %narrow, %len
818  br i1 %range_check, label %fail, label %backedge
819
820backedge:
821  %el.ptr = getelementptr i32, ptr %arr, i64 %iv
822  %el = load i32, ptr %el.ptr
823  %loop.cond = icmp eq i32 %el, 0
824  br i1 %loop.cond, label %loop, label %exit
825
826exit:
827  ret void
828
829fail:
830  unreachable
831}
832
833define void @test_can_predicate_simple_unsigned_different_start(i32 %start, ptr %p, ptr %arr) {
834; CHECK-LABEL: @test_can_predicate_simple_unsigned_different_start(
835; CHECK-NEXT:  preheader:
836; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
837; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[START:%.*]], -1
838; CHECK-NEXT:    [[RANGE_CHECK_FIRST_ITER:%.*]] = icmp ult i32 [[TMP0]], [[LEN]]
839; CHECK-NEXT:    br label [[LOOP:%.*]]
840; CHECK:       loop:
841; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
842; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
843; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
844; CHECK:       range_check_block:
845; CHECK-NEXT:    [[IV_NEXT]] = sub nuw i32 [[IV]], 1
846; CHECK-NEXT:    br i1 [[RANGE_CHECK_FIRST_ITER]], label [[BACKEDGE]], label [[FAIL:%.*]]
847; CHECK:       backedge:
848; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
849; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
850; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
851; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
852; CHECK:       exit:
853; CHECK-NEXT:    ret void
854; CHECK:       fail:
855; CHECK-NEXT:    unreachable
856;
857preheader:
858  %len = load i32, ptr %p
859  br label %loop
860
861loop:
862  %iv = phi i32 [%start, %preheader], [%iv.next, %backedge]
863  %zero_cond = icmp eq i32 %iv, 0
864  br i1 %zero_cond, label %exit, label %range_check_block
865
866range_check_block:
867  %iv.next = sub i32 %iv, 1
868  %range_check = icmp ult i32 %iv.next, %len
869  br i1 %range_check, label %backedge, label %fail
870
871backedge:
872  %el.ptr = getelementptr i32, ptr %p, i32 %iv
873  %el = load i32, ptr %el.ptr
874  %loop.cond = icmp eq i32 %el, 0
875  br i1 %loop.cond, label %loop, label %exit
876
877exit:
878  ret void
879
880fail:
881  unreachable
882}
883
884define void @test_can_predicate_simple_unsigned_inverted_different_start(i32 %start, ptr %p, ptr %arr) {
885; CHECK-LABEL: @test_can_predicate_simple_unsigned_inverted_different_start(
886; CHECK-NEXT:  preheader:
887; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
888; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[START:%.*]], -1
889; CHECK-NEXT:    [[RANGE_CHECK_FIRST_ITER:%.*]] = icmp uge i32 [[TMP0]], [[LEN]]
890; CHECK-NEXT:    br label [[LOOP:%.*]]
891; CHECK:       loop:
892; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
893; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
894; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
895; CHECK:       range_check_block:
896; CHECK-NEXT:    [[IV_NEXT]] = sub nuw i32 [[IV]], 1
897; CHECK-NEXT:    br i1 [[RANGE_CHECK_FIRST_ITER]], label [[FAIL:%.*]], label [[BACKEDGE]]
898; CHECK:       backedge:
899; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
900; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
901; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
902; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
903; CHECK:       exit:
904; CHECK-NEXT:    ret void
905; CHECK:       fail:
906; CHECK-NEXT:    unreachable
907;
908preheader:
909  %len = load i32, ptr %p
910  br label %loop
911
912loop:
913  %iv = phi i32 [%start, %preheader], [%iv.next, %backedge]
914  %zero_cond = icmp eq i32 %iv, 0
915  br i1 %zero_cond, label %exit, label %range_check_block
916
917range_check_block:
918  %iv.next = sub i32 %iv, 1
919  %range_check = icmp uge i32 %iv.next, %len
920  br i1 %range_check, label %fail, label %backedge
921
922backedge:
923  %el.ptr = getelementptr i32, ptr %p, i32 %iv
924  %el = load i32, ptr %el.ptr
925  %loop.cond = icmp eq i32 %el, 0
926  br i1 %loop.cond, label %loop, label %exit
927
928exit:
929  ret void
930
931fail:
932  unreachable
933}
934
935
936define void @test_can_predicate_simple_signed_different_start(i32 %start, ptr %p, ptr %arr) {
937; CHECK-LABEL: @test_can_predicate_simple_signed_different_start(
938; CHECK-NEXT:  preheader:
939; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P:%.*]], align 4
940; CHECK-NEXT:    br label [[LOOP:%.*]]
941; CHECK:       loop:
942; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START:%.*]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
943; CHECK-NEXT:    [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
944; CHECK-NEXT:    br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
945; CHECK:       range_check_block:
946; CHECK-NEXT:    [[IV_NEXT]] = sub nuw i32 [[IV]], 1
947; CHECK-NEXT:    [[RANGE_CHECK:%.*]] = icmp slt i32 [[IV_NEXT]], [[LEN]]
948; CHECK-NEXT:    br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
949; CHECK:       backedge:
950; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]
951; CHECK-NEXT:    [[EL:%.*]] = load i32, ptr [[EL_PTR]], align 4
952; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
953; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
954; CHECK:       exit:
955; CHECK-NEXT:    ret void
956; CHECK:       fail:
957; CHECK-NEXT:    unreachable
958;
959preheader:
960  %len = load i32, ptr %p
961  br label %loop
962
963loop:
964  %iv = phi i32 [%start, %preheader], [%iv.next, %backedge]
965  %zero_cond = icmp eq i32 %iv, 0
966  br i1 %zero_cond, label %exit, label %range_check_block
967
968range_check_block:
969  %iv.next = sub i32 %iv, 1
970  %range_check = icmp slt i32 %iv.next, %len
971  br i1 %range_check, label %backedge, label %fail
972
973backedge:
974  %el.ptr = getelementptr i32, ptr %p, i32 %iv
975  %el = load i32, ptr %el.ptr
976  %loop.cond = icmp eq i32 %el, 0
977  br i1 %loop.cond, label %loop, label %exit
978
979exit:
980  ret void
981
982fail:
983  unreachable
984}
985
986!0 = !{i32 0, i32 2147483647}
987