blob: 9e6908c308d2b3b09ec498d60ca3fe36572dfc7f [file] [log] [blame]
Max Kazantsevda9e7b12020-08-07 16:46:39 +07001; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -indvars -S < %s | FileCheck %s
3; RUN: opt -passes=indvars -S < %s | FileCheck %s
4
5; TODO: should be able to remove the range check basing on the following facts:
Max Kazantsev8a3907c2020-09-02 18:26:11 +07006; 0 <= len <= MAX_INT [1];
Max Kazantsevda9e7b12020-08-07 16:46:39 +07007; iv starts from len and goes down stopping at zero and [1], therefore
8; 0 <= iv <= len [2];
9; 3. In range_check_block, iv != 0 and [2], therefore
10; 1 <= iv <= len [3];
11; 4. iv.next = iv - 1 and [3], therefore
12; 0 <= iv.next < len.
Max Kazantsev8a04cdb2020-09-16 11:30:21 +070013define void @test_predicated_simple_unsigned(i32* %p, i32* %arr) {
14; CHECK-LABEL: @test_predicated_simple_unsigned(
Max Kazantsev8a3907c2020-09-02 18:26:11 +070015; CHECK-NEXT: preheader:
16; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4, [[RNG0:!range !.*]]
Max Kazantsevda9e7b12020-08-07 16:46:39 +070017; CHECK-NEXT: br label [[LOOP:%.*]]
18; CHECK: loop:
Max Kazantsev8a3907c2020-09-02 18:26:11 +070019; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
Max Kazantsevda9e7b12020-08-07 16:46:39 +070020; CHECK-NEXT: [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
21; CHECK-NEXT: br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
22; CHECK: range_check_block:
23; CHECK-NEXT: [[IV_NEXT]] = sub i32 [[IV]], 1
24; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[IV_NEXT]], [[LEN]]
Max Kazantsev8a3907c2020-09-02 18:26:11 +070025; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
Max Kazantsevda9e7b12020-08-07 16:46:39 +070026; CHECK: backedge:
27; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[P]], i32 [[IV]]
28; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4
29; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
30; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
31; CHECK: exit:
32; CHECK-NEXT: ret void
Max Kazantsevda9e7b12020-08-07 16:46:39 +070033; CHECK: fail:
34; CHECK-NEXT: unreachable
35;
Max Kazantsevda9e7b12020-08-07 16:46:39 +070036preheader:
Max Kazantsev8a3907c2020-09-02 18:26:11 +070037 %len = load i32, i32* %p, !range !0
Max Kazantsevda9e7b12020-08-07 16:46:39 +070038 br label %loop
39
40loop:
41 %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
42 %zero_cond = icmp eq i32 %iv, 0
43 br i1 %zero_cond, label %exit, label %range_check_block
44
45range_check_block:
46 %iv.next = sub i32 %iv, 1
47 %range_check = icmp ult i32 %iv.next, %len
48 br i1 %range_check, label %backedge, label %fail
49
50backedge:
51 %el.ptr = getelementptr i32, i32* %p, i32 %iv
52 %el = load i32, i32* %el.ptr
53 %loop.cond = icmp eq i32 %el, 0
54 br i1 %loop.cond, label %loop, label %exit
55
56exit:
57 ret void
58
59fail:
60 unreachable
61}
62
Max Kazantsev8a04cdb2020-09-16 11:30:21 +070063define void @test_predicated_simple_signed(i32* %p, i32* %arr) {
64; CHECK-LABEL: @test_predicated_simple_signed(
65; CHECK-NEXT: preheader:
66; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4, [[RNG0]]
67; CHECK-NEXT: br label [[LOOP:%.*]]
68; CHECK: loop:
69; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
70; CHECK-NEXT: [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
71; CHECK-NEXT: br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
72; CHECK: range_check_block:
73; CHECK-NEXT: [[IV_NEXT]] = sub i32 [[IV]], 1
Max Kazantsevc6ca26c2020-10-27 11:35:16 +070074; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAIL:%.*]]
Max Kazantsev8a04cdb2020-09-16 11:30:21 +070075; CHECK: backedge:
76; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[P]], i32 [[IV]]
77; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4
78; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
79; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
80; CHECK: exit:
81; CHECK-NEXT: ret void
82; CHECK: fail:
83; CHECK-NEXT: unreachable
84;
85preheader:
86 %len = load i32, i32* %p, !range !0
87 br label %loop
88
89loop:
90 %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
91 %zero_cond = icmp eq i32 %iv, 0
92 br i1 %zero_cond, label %exit, label %range_check_block
93
94range_check_block:
95 %iv.next = sub i32 %iv, 1
96 %range_check = icmp slt i32 %iv.next, %len
97 br i1 %range_check, label %backedge, label %fail
98
99backedge:
100 %el.ptr = getelementptr i32, i32* %p, i32 %iv
101 %el = load i32, i32* %el.ptr
102 %loop.cond = icmp eq i32 %el, 0
103 br i1 %loop.cond, label %loop, label %exit
104
105exit:
106 ret void
107
108fail:
109 unreachable
110}
111
Max Kazantsev69851352020-09-16 14:24:00 +0700112; Cannot remove checks because the range check fails on the last iteration.
113define void @predicated_outside_loop_signed_neg(i32 %arg) nounwind #0 {
114; CHECK-LABEL: @predicated_outside_loop_signed_neg(
Max Kazantsev94f7d3d2020-09-16 13:59:41 +0700115; CHECK-NEXT: entry:
116; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
117; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
118; CHECK-NEXT: br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
119; CHECK: outer.preheader:
120; CHECK-NEXT: br label [[OUTER:%.*]]
121; CHECK: outer:
122; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
123; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
124; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
125; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
126; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
127; CHECK: inner.ph:
128; CHECK-NEXT: br label [[INNER:%.*]]
129; CHECK: inner:
130; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
131; CHECK: outer.inc.loopexit:
132; CHECK-NEXT: br label [[OUTER_INC]]
133; CHECK: outer.inc:
134; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
135; CHECK-NEXT: br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
136; CHECK: exit.loopexit:
137; CHECK-NEXT: br label [[EXIT]]
138; CHECK: exit:
139; CHECK-NEXT: ret void
140;
141entry:
142 %sub1 = sub nsw i32 %arg, 1
143 %cmp1 = icmp slt i32 0, %sub1
144 br i1 %cmp1, label %outer, label %exit
145
146outer:
147 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
148 %sub2 = sub nsw i32 %arg, %i
149 %sub3 = sub nsw i32 %sub2, 1
150 %cmp2 = icmp slt i32 0, %sub3
151 br i1 %cmp2, label %inner.ph, label %outer.inc
152
153inner.ph:
154 br label %inner
155
156inner:
157 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
158 %j.inc = add nsw i32 %j, 1
159 %cmp3 = icmp slt i32 %j.inc, %sub3
160 br i1 %cmp3, label %inner, label %outer.inc
161
162outer.inc:
163 %i.inc = add nsw i32 %i, 1
164 %cmp4 = icmp slt i32 %i.inc, %arg
165 br i1 %cmp4, label %outer, label %exit
166
167exit:
168 ret void
169}
170
Max Kazantsev69851352020-09-16 14:24:00 +0700171; Range check can be removed.
172define void @predicated_outside_loop_signed_pos(i32 %arg) nounwind #0 {
173; CHECK-LABEL: @predicated_outside_loop_signed_pos(
174; CHECK-NEXT: entry:
175; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
176; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
177; CHECK-NEXT: br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
178; CHECK: outer.preheader:
179; CHECK-NEXT: br label [[OUTER:%.*]]
180; CHECK: outer:
181; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
182; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
183; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
184; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
185; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
186; CHECK: inner.ph:
187; CHECK-NEXT: br label [[INNER:%.*]]
188; CHECK: inner:
189; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
190; CHECK: outer.inc.loopexit:
191; CHECK-NEXT: br label [[OUTER_INC]]
192; CHECK: outer.inc:
193; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
194; CHECK-NEXT: br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
195; CHECK: exit.loopexit:
196; CHECK-NEXT: br label [[EXIT]]
197; CHECK: exit:
198; CHECK-NEXT: ret void
199;
200entry:
201 %sub1 = sub nsw i32 %arg, 1
202 %cmp1 = icmp slt i32 0, %sub1
203 br i1 %cmp1, label %outer, label %exit
204
205outer:
206 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
207 %sub2 = sub nsw i32 %arg, %i
208 %sub3 = sub nsw i32 %sub2, 1
209 %cmp2 = icmp slt i32 0, %sub3
210 br i1 %cmp2, label %inner.ph, label %outer.inc
211
212inner.ph:
213 br label %inner
214
215inner:
216 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
217 %j.inc = add nsw i32 %j, 1
218 %cmp3 = icmp slt i32 %j.inc, %sub3
219 br i1 %cmp3, label %inner, label %outer.inc
220
221outer.inc:
222 %i.inc = add nsw i32 %i, 1
223 %cmp4 = icmp slt i32 %i.inc, %sub1
224 br i1 %cmp4, label %outer, label %exit
225
226exit:
227 ret void
228}
229
Max Kazantsev94f7d3d2020-09-16 13:59:41 +0700230define void @predicated_outside_loop_unsigned(i32 %arg) nounwind #0 {
231; CHECK-LABEL: @predicated_outside_loop_unsigned(
232; CHECK-NEXT: entry:
233; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
234; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
235; CHECK-NEXT: br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
236; CHECK: outer.preheader:
237; CHECK-NEXT: br label [[OUTER:%.*]]
238; CHECK: outer:
239; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
240; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
241; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
242; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 0, [[SUB3]]
243; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
244; CHECK: inner.ph:
245; CHECK-NEXT: br label [[INNER:%.*]]
246; CHECK: inner:
247; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
248; CHECK: outer.inc.loopexit:
249; CHECK-NEXT: br label [[OUTER_INC]]
250; CHECK: outer.inc:
251; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
252; CHECK-NEXT: br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
253; CHECK: exit.loopexit:
254; CHECK-NEXT: br label [[EXIT]]
255; CHECK: exit:
256; CHECK-NEXT: ret void
257;
258entry:
259 %sub1 = sub nsw i32 %arg, 1
260 %cmp1 = icmp slt i32 0, %sub1
261 br i1 %cmp1, label %outer, label %exit
262
263outer:
264 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
265 %sub2 = sub nsw i32 %arg, %i
266 %sub3 = sub nsw i32 %sub2, 1
267 %cmp2 = icmp ult i32 0, %sub3
268 br i1 %cmp2, label %inner.ph, label %outer.inc
269
270inner.ph:
271 br label %inner
272
273inner:
274 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
275 %j.inc = add nsw i32 %j, 1
276 %cmp3 = icmp slt i32 %j.inc, %sub3
277 br i1 %cmp3, label %inner, label %outer.inc
278
279outer.inc:
280 %i.inc = add nsw i32 %i, 1
281 %cmp4 = icmp slt i32 %i.inc, %arg
282 br i1 %cmp4, label %outer, label %exit
283
284exit:
285 ret void
286}
287
Max Kazantsev69851352020-09-16 14:24:00 +0700288; Cannot remove checks because the range check fails on the last iteration.
289define void @predicated_inside_loop_signed_neg(i32 %arg) nounwind #0 {
290; CHECK-LABEL: @predicated_inside_loop_signed_neg(
Max Kazantsev94f7d3d2020-09-16 13:59:41 +0700291; CHECK-NEXT: entry:
292; CHECK-NEXT: br label [[OUTER:%.*]]
293; CHECK: outer:
294; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ]
295; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
296; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
297; CHECK-NEXT: br i1 [[CMP1]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
298; CHECK: guarded:
299; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
300; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
301; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
302; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
303; CHECK: inner.ph:
304; CHECK-NEXT: br label [[INNER:%.*]]
305; CHECK: inner:
306; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
307; CHECK: outer.inc.loopexit:
308; CHECK-NEXT: br label [[OUTER_INC]]
309; CHECK: outer.inc:
310; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
311; CHECK-NEXT: [[CMP4:%.*]] = icmp slt i32 [[I_INC]], [[ARG]]
312; CHECK-NEXT: br i1 [[CMP4]], label [[OUTER]], label [[EXIT]]
313; CHECK: exit:
314; CHECK-NEXT: ret void
315;
316entry:
317 br label %outer
318
319outer:
320 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
321 %sub1 = sub nsw i32 %arg, 1
322 %cmp1 = icmp slt i32 0, %sub1
323 br i1 %cmp1, label %guarded, label %exit
324
325guarded:
326 %sub2 = sub nsw i32 %arg, %i
327 %sub3 = sub nsw i32 %sub2, 1
328 %cmp2 = icmp slt i32 0, %sub3
329 br i1 %cmp2, label %inner.ph, label %outer.inc
330
331inner.ph:
332 br label %inner
333
334inner:
335 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
336 %j.inc = add nsw i32 %j, 1
337 %cmp3 = icmp slt i32 %j.inc, %sub3
338 br i1 %cmp3, label %inner, label %outer.inc
339
340outer.inc:
341 %i.inc = add nsw i32 %i, 1
342 %cmp4 = icmp slt i32 %i.inc, %arg
343 br i1 %cmp4, label %outer, label %exit
344
345exit:
346 ret void
347}
348
Max Kazantsev69851352020-09-16 14:24:00 +0700349; Range check can be trivially removed.
350define void @predicated_inside_loop_signed_pos(i32 %arg) nounwind #0 {
351; CHECK-LABEL: @predicated_inside_loop_signed_pos(
352; CHECK-NEXT: entry:
353; CHECK-NEXT: br label [[OUTER:%.*]]
354; CHECK: outer:
355; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ]
356; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
357; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
358; CHECK-NEXT: br i1 [[CMP1]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
359; CHECK: guarded:
360; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
361; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
362; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
363; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
364; CHECK: inner.ph:
365; CHECK-NEXT: br label [[INNER:%.*]]
366; CHECK: inner:
367; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
368; CHECK: outer.inc.loopexit:
369; CHECK-NEXT: br label [[OUTER_INC]]
370; CHECK: outer.inc:
371; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
372; CHECK-NEXT: [[CMP4:%.*]] = icmp slt i32 [[I_INC]], [[SUB1]]
373; CHECK-NEXT: br i1 [[CMP4]], label [[OUTER]], label [[EXIT]]
374; CHECK: exit:
375; CHECK-NEXT: ret void
376;
377entry:
378 br label %outer
379
380outer:
381 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
382 %sub1 = sub nsw i32 %arg, 1
383 %cmp1 = icmp slt i32 0, %sub1
384 br i1 %cmp1, label %guarded, label %exit
385
386guarded:
387 %sub2 = sub nsw i32 %arg, %i
388 %sub3 = sub nsw i32 %sub2, 1
389 %cmp2 = icmp slt i32 0, %sub3
390 br i1 %cmp2, label %inner.ph, label %outer.inc
391
392inner.ph:
393 br label %inner
394
395inner:
396 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
397 %j.inc = add nsw i32 %j, 1
398 %cmp3 = icmp slt i32 %j.inc, %sub3
399 br i1 %cmp3, label %inner, label %outer.inc
400
401outer.inc:
402 %i.inc = add nsw i32 %i, 1
403 %cmp4 = icmp slt i32 %i.inc, %sub1
404 br i1 %cmp4, label %outer, label %exit
405
406exit:
407 ret void
408}
409
Max Kazantsev94f7d3d2020-09-16 13:59:41 +0700410define void @predicated_inside_loop_unsigned(i32 %arg) nounwind #0 {
411; CHECK-LABEL: @predicated_inside_loop_unsigned(
412; CHECK-NEXT: entry:
413; CHECK-NEXT: br label [[OUTER:%.*]]
414; CHECK: outer:
415; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ]
416; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
417; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
418; CHECK-NEXT: br i1 [[CMP1]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
419; CHECK: guarded:
420; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
421; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
422; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 0, [[SUB3]]
423; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
424; CHECK: inner.ph:
425; CHECK-NEXT: br label [[INNER:%.*]]
426; CHECK: inner:
427; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
428; CHECK: outer.inc.loopexit:
429; CHECK-NEXT: br label [[OUTER_INC]]
430; CHECK: outer.inc:
431; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
432; CHECK-NEXT: [[CMP4:%.*]] = icmp slt i32 [[I_INC]], [[ARG]]
433; CHECK-NEXT: br i1 [[CMP4]], label [[OUTER]], label [[EXIT]]
434; CHECK: exit:
435; CHECK-NEXT: ret void
436;
437entry:
438 br label %outer
439
440outer:
441 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
442 %sub1 = sub nsw i32 %arg, 1
443 %cmp1 = icmp slt i32 0, %sub1
444 br i1 %cmp1, label %guarded, label %exit
445
446guarded:
447 %sub2 = sub nsw i32 %arg, %i
448 %sub3 = sub nsw i32 %sub2, 1
449 %cmp2 = icmp ult i32 0, %sub3
450 br i1 %cmp2, label %inner.ph, label %outer.inc
451
452inner.ph:
453 br label %inner
454
455inner:
456 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
457 %j.inc = add nsw i32 %j, 1
458 %cmp3 = icmp slt i32 %j.inc, %sub3
459 br i1 %cmp3, label %inner, label %outer.inc
460
461outer.inc:
462 %i.inc = add nsw i32 %i, 1
463 %cmp4 = icmp slt i32 %i.inc, %arg
464 br i1 %cmp4, label %outer, label %exit
465
466exit:
467 ret void
468}
469
Max Kazantsev15985952020-09-28 12:04:20 +0700470define void @test_can_predicate_simple_unsigned(i32* %p, i32* %arr) {
471; CHECK-LABEL: @test_can_predicate_simple_unsigned(
472; CHECK-NEXT: preheader:
473; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4
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 i32 [[IV]], 1
481; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[IV_NEXT]], [[LEN]]
482; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
483; CHECK: backedge:
484; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[P]], i32 [[IV]]
485; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4
486; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
487; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
488; CHECK: exit:
489; CHECK-NEXT: ret void
490; CHECK: fail:
491; CHECK-NEXT: unreachable
492;
493preheader:
494 %len = load i32, i32* %p
495 br label %loop
496
497loop:
498 %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
499 %zero_cond = icmp eq i32 %iv, 0
500 br i1 %zero_cond, label %exit, label %range_check_block
501
502range_check_block:
503 %iv.next = sub i32 %iv, 1
504 %range_check = icmp ult i32 %iv.next, %len
505 br i1 %range_check, label %backedge, label %fail
506
507backedge:
508 %el.ptr = getelementptr i32, i32* %p, i32 %iv
509 %el = load i32, i32* %el.ptr
510 %loop.cond = icmp eq i32 %el, 0
511 br i1 %loop.cond, label %loop, label %exit
512
513exit:
514 ret void
515
516fail:
517 unreachable
518}
519
520define void @test_can_predicate_simple_signed(i32* %p, i32* %arr) {
521; CHECK-LABEL: @test_can_predicate_simple_signed(
522; CHECK-NEXT: preheader:
523; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4
524; CHECK-NEXT: br label [[LOOP:%.*]]
525; CHECK: loop:
526; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
527; CHECK-NEXT: [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
528; CHECK-NEXT: br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
529; CHECK: range_check_block:
530; CHECK-NEXT: [[IV_NEXT]] = sub i32 [[IV]], 1
531; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp slt i32 [[IV_NEXT]], [[LEN]]
532; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
533; CHECK: backedge:
534; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[P]], i32 [[IV]]
535; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[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, i32* %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 slt i32 %iv.next, %len
555 br i1 %range_check, label %backedge, label %fail
556
557backedge:
558 %el.ptr = getelementptr i32, i32* %p, i32 %iv
559 %el = load i32, i32* %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
Max Kazantsev63354462020-10-27 14:50:00 +0700570define void @test_can_predicate_trunc_unsigned(i32* %p, i32* %arr) {
571; CHECK-LABEL: @test_can_predicate_trunc_unsigned(
572; CHECK-NEXT: preheader:
573; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4
574; CHECK-NEXT: [[START:%.*]] = zext i32 [[LEN]] to i64
575; CHECK-NEXT: br label [[LOOP:%.*]]
576; CHECK: loop:
577; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
578; CHECK-NEXT: [[ZERO_COND:%.*]] = icmp eq i64 [[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 nsw i64 [[IV]], 1
582; CHECK-NEXT: [[NARROW:%.*]] = trunc i64 [[IV_NEXT]] to i32
583; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[NARROW]], [[LEN]]
584; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
585; CHECK: backedge:
586; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[ARR:%.*]], i64 [[IV]]
587; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4
588; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
589; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
590; CHECK: exit:
591; CHECK-NEXT: ret void
592; CHECK: fail:
593; CHECK-NEXT: unreachable
594;
595preheader:
596 %len = load i32, i32* %p
597 %start = zext i32 %len to i64
598 br label %loop
599
600loop:
601 %iv = phi i64 [%start, %preheader], [%iv.next, %backedge]
602 %zero_cond = icmp eq i64 %iv, 0
603 br i1 %zero_cond, label %exit, label %range_check_block
604
605range_check_block:
606 %iv.next = sub i64 %iv, 1
607 %narrow = trunc i64 %iv.next to i32
608 %range_check = icmp ult i32 %narrow, %len
609 br i1 %range_check, label %backedge, label %fail
610
611backedge:
612 %el.ptr = getelementptr i32, i32* %arr, i64 %iv
613 %el = load i32, i32* %el.ptr
614 %loop.cond = icmp eq i32 %el, 0
615 br i1 %loop.cond, label %loop, label %exit
616
617exit:
618 ret void
619
620fail:
621 unreachable
622}
623
Max Kazantsevda9e7b12020-08-07 16:46:39 +0700624!0 = !{i32 0, i32 2147483647}