blob: cfcd931b6f5be53066cb78e2b6895c77cabb71e8 [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
Raphael Isemanne038b602020-10-27 13:37:23 +010074; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp slt i32 [[IV_NEXT]], [[LEN]]
75; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
Max Kazantsev8a04cdb2020-09-16 11:30:21 +070076; CHECK: backedge:
77; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[P]], i32 [[IV]]
78; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4
79; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
80; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
81; CHECK: exit:
82; CHECK-NEXT: ret void
83; CHECK: fail:
84; CHECK-NEXT: unreachable
85;
86preheader:
87 %len = load i32, i32* %p, !range !0
88 br label %loop
89
90loop:
91 %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
92 %zero_cond = icmp eq i32 %iv, 0
93 br i1 %zero_cond, label %exit, label %range_check_block
94
95range_check_block:
96 %iv.next = sub i32 %iv, 1
97 %range_check = icmp slt i32 %iv.next, %len
98 br i1 %range_check, label %backedge, label %fail
99
100backedge:
101 %el.ptr = getelementptr i32, i32* %p, i32 %iv
102 %el = load i32, i32* %el.ptr
103 %loop.cond = icmp eq i32 %el, 0
104 br i1 %loop.cond, label %loop, label %exit
105
106exit:
107 ret void
108
109fail:
110 unreachable
111}
112
Max Kazantsev69851352020-09-16 14:24:00 +0700113; Cannot remove checks because the range check fails on the last iteration.
114define void @predicated_outside_loop_signed_neg(i32 %arg) nounwind #0 {
115; CHECK-LABEL: @predicated_outside_loop_signed_neg(
Max Kazantsev94f7d3d2020-09-16 13:59:41 +0700116; CHECK-NEXT: entry:
117; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
118; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
119; CHECK-NEXT: br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
120; CHECK: outer.preheader:
121; CHECK-NEXT: br label [[OUTER:%.*]]
122; CHECK: outer:
123; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
124; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
125; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
126; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
127; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
128; CHECK: inner.ph:
129; CHECK-NEXT: br label [[INNER:%.*]]
130; CHECK: inner:
131; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
132; CHECK: outer.inc.loopexit:
133; CHECK-NEXT: br label [[OUTER_INC]]
134; CHECK: outer.inc:
135; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
136; CHECK-NEXT: br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
137; CHECK: exit.loopexit:
138; CHECK-NEXT: br label [[EXIT]]
139; CHECK: exit:
140; CHECK-NEXT: ret void
141;
142entry:
143 %sub1 = sub nsw i32 %arg, 1
144 %cmp1 = icmp slt i32 0, %sub1
145 br i1 %cmp1, label %outer, label %exit
146
147outer:
148 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
149 %sub2 = sub nsw i32 %arg, %i
150 %sub3 = sub nsw i32 %sub2, 1
151 %cmp2 = icmp slt i32 0, %sub3
152 br i1 %cmp2, label %inner.ph, label %outer.inc
153
154inner.ph:
155 br label %inner
156
157inner:
158 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
159 %j.inc = add nsw i32 %j, 1
160 %cmp3 = icmp slt i32 %j.inc, %sub3
161 br i1 %cmp3, label %inner, label %outer.inc
162
163outer.inc:
164 %i.inc = add nsw i32 %i, 1
165 %cmp4 = icmp slt i32 %i.inc, %arg
166 br i1 %cmp4, label %outer, label %exit
167
168exit:
169 ret void
170}
171
Max Kazantsev69851352020-09-16 14:24:00 +0700172; Range check can be removed.
173define void @predicated_outside_loop_signed_pos(i32 %arg) nounwind #0 {
174; CHECK-LABEL: @predicated_outside_loop_signed_pos(
175; CHECK-NEXT: entry:
176; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
177; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
178; CHECK-NEXT: br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
179; CHECK: outer.preheader:
180; CHECK-NEXT: br label [[OUTER:%.*]]
181; CHECK: outer:
182; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
183; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
184; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
185; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
186; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
187; CHECK: inner.ph:
188; CHECK-NEXT: br label [[INNER:%.*]]
189; CHECK: inner:
190; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
191; CHECK: outer.inc.loopexit:
192; CHECK-NEXT: br label [[OUTER_INC]]
193; CHECK: outer.inc:
194; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
195; CHECK-NEXT: br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
196; CHECK: exit.loopexit:
197; CHECK-NEXT: br label [[EXIT]]
198; CHECK: exit:
199; CHECK-NEXT: ret void
200;
201entry:
202 %sub1 = sub nsw i32 %arg, 1
203 %cmp1 = icmp slt i32 0, %sub1
204 br i1 %cmp1, label %outer, label %exit
205
206outer:
207 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
208 %sub2 = sub nsw i32 %arg, %i
209 %sub3 = sub nsw i32 %sub2, 1
210 %cmp2 = icmp slt i32 0, %sub3
211 br i1 %cmp2, label %inner.ph, label %outer.inc
212
213inner.ph:
214 br label %inner
215
216inner:
217 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
218 %j.inc = add nsw i32 %j, 1
219 %cmp3 = icmp slt i32 %j.inc, %sub3
220 br i1 %cmp3, label %inner, label %outer.inc
221
222outer.inc:
223 %i.inc = add nsw i32 %i, 1
224 %cmp4 = icmp slt i32 %i.inc, %sub1
225 br i1 %cmp4, label %outer, label %exit
226
227exit:
228 ret void
229}
230
Max Kazantsev94f7d3d2020-09-16 13:59:41 +0700231define void @predicated_outside_loop_unsigned(i32 %arg) nounwind #0 {
232; CHECK-LABEL: @predicated_outside_loop_unsigned(
233; CHECK-NEXT: entry:
234; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
235; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
236; CHECK-NEXT: br i1 [[CMP1]], label [[OUTER_PREHEADER:%.*]], label [[EXIT:%.*]]
237; CHECK: outer.preheader:
238; CHECK-NEXT: br label [[OUTER:%.*]]
239; CHECK: outer:
240; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ], [ 0, [[OUTER_PREHEADER]] ]
241; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
242; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
243; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 0, [[SUB3]]
244; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
245; CHECK: inner.ph:
246; CHECK-NEXT: br label [[INNER:%.*]]
247; CHECK: inner:
248; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
249; CHECK: outer.inc.loopexit:
250; CHECK-NEXT: br label [[OUTER_INC]]
251; CHECK: outer.inc:
252; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
253; CHECK-NEXT: br i1 false, label [[OUTER]], label [[EXIT_LOOPEXIT:%.*]]
254; CHECK: exit.loopexit:
255; CHECK-NEXT: br label [[EXIT]]
256; CHECK: exit:
257; CHECK-NEXT: ret void
258;
259entry:
260 %sub1 = sub nsw i32 %arg, 1
261 %cmp1 = icmp slt i32 0, %sub1
262 br i1 %cmp1, label %outer, label %exit
263
264outer:
265 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
266 %sub2 = sub nsw i32 %arg, %i
267 %sub3 = sub nsw i32 %sub2, 1
268 %cmp2 = icmp ult i32 0, %sub3
269 br i1 %cmp2, label %inner.ph, label %outer.inc
270
271inner.ph:
272 br label %inner
273
274inner:
275 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
276 %j.inc = add nsw i32 %j, 1
277 %cmp3 = icmp slt i32 %j.inc, %sub3
278 br i1 %cmp3, label %inner, label %outer.inc
279
280outer.inc:
281 %i.inc = add nsw i32 %i, 1
282 %cmp4 = icmp slt i32 %i.inc, %arg
283 br i1 %cmp4, label %outer, label %exit
284
285exit:
286 ret void
287}
288
Max Kazantsev69851352020-09-16 14:24:00 +0700289; Cannot remove checks because the range check fails on the last iteration.
290define void @predicated_inside_loop_signed_neg(i32 %arg) nounwind #0 {
291; CHECK-LABEL: @predicated_inside_loop_signed_neg(
Max Kazantsev94f7d3d2020-09-16 13:59:41 +0700292; CHECK-NEXT: entry:
293; CHECK-NEXT: br label [[OUTER:%.*]]
294; CHECK: outer:
295; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ]
296; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
297; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
298; CHECK-NEXT: br i1 [[CMP1]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
299; CHECK: guarded:
300; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
301; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
302; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
303; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
304; CHECK: inner.ph:
305; CHECK-NEXT: br label [[INNER:%.*]]
306; CHECK: inner:
307; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
308; CHECK: outer.inc.loopexit:
309; CHECK-NEXT: br label [[OUTER_INC]]
310; CHECK: outer.inc:
311; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
312; CHECK-NEXT: [[CMP4:%.*]] = icmp slt i32 [[I_INC]], [[ARG]]
313; CHECK-NEXT: br i1 [[CMP4]], label [[OUTER]], label [[EXIT]]
314; CHECK: exit:
315; CHECK-NEXT: ret void
316;
317entry:
318 br label %outer
319
320outer:
321 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
322 %sub1 = sub nsw i32 %arg, 1
323 %cmp1 = icmp slt i32 0, %sub1
324 br i1 %cmp1, label %guarded, label %exit
325
326guarded:
327 %sub2 = sub nsw i32 %arg, %i
328 %sub3 = sub nsw i32 %sub2, 1
329 %cmp2 = icmp slt i32 0, %sub3
330 br i1 %cmp2, label %inner.ph, label %outer.inc
331
332inner.ph:
333 br label %inner
334
335inner:
336 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
337 %j.inc = add nsw i32 %j, 1
338 %cmp3 = icmp slt i32 %j.inc, %sub3
339 br i1 %cmp3, label %inner, label %outer.inc
340
341outer.inc:
342 %i.inc = add nsw i32 %i, 1
343 %cmp4 = icmp slt i32 %i.inc, %arg
344 br i1 %cmp4, label %outer, label %exit
345
346exit:
347 ret void
348}
349
Max Kazantsev69851352020-09-16 14:24:00 +0700350; Range check can be trivially removed.
351define void @predicated_inside_loop_signed_pos(i32 %arg) nounwind #0 {
352; CHECK-LABEL: @predicated_inside_loop_signed_pos(
353; CHECK-NEXT: entry:
354; CHECK-NEXT: br label [[OUTER:%.*]]
355; CHECK: outer:
356; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ]
357; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
358; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
359; CHECK-NEXT: br i1 [[CMP1]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
360; CHECK: guarded:
361; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
362; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
363; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 0, [[SUB3]]
364; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
365; CHECK: inner.ph:
366; CHECK-NEXT: br label [[INNER:%.*]]
367; CHECK: inner:
368; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
369; CHECK: outer.inc.loopexit:
370; CHECK-NEXT: br label [[OUTER_INC]]
371; CHECK: outer.inc:
372; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
373; CHECK-NEXT: [[CMP4:%.*]] = icmp slt i32 [[I_INC]], [[SUB1]]
374; CHECK-NEXT: br i1 [[CMP4]], label [[OUTER]], label [[EXIT]]
375; CHECK: exit:
376; CHECK-NEXT: ret void
377;
378entry:
379 br label %outer
380
381outer:
382 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
383 %sub1 = sub nsw i32 %arg, 1
384 %cmp1 = icmp slt i32 0, %sub1
385 br i1 %cmp1, label %guarded, label %exit
386
387guarded:
388 %sub2 = sub nsw i32 %arg, %i
389 %sub3 = sub nsw i32 %sub2, 1
390 %cmp2 = icmp slt i32 0, %sub3
391 br i1 %cmp2, label %inner.ph, label %outer.inc
392
393inner.ph:
394 br label %inner
395
396inner:
397 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
398 %j.inc = add nsw i32 %j, 1
399 %cmp3 = icmp slt i32 %j.inc, %sub3
400 br i1 %cmp3, label %inner, label %outer.inc
401
402outer.inc:
403 %i.inc = add nsw i32 %i, 1
404 %cmp4 = icmp slt i32 %i.inc, %sub1
405 br i1 %cmp4, label %outer, label %exit
406
407exit:
408 ret void
409}
410
Max Kazantsev94f7d3d2020-09-16 13:59:41 +0700411define void @predicated_inside_loop_unsigned(i32 %arg) nounwind #0 {
412; CHECK-LABEL: @predicated_inside_loop_unsigned(
413; CHECK-NEXT: entry:
414; CHECK-NEXT: br label [[OUTER:%.*]]
415; CHECK: outer:
416; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_INC:%.*]] ]
417; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[ARG:%.*]], 1
418; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 0, [[SUB1]]
419; CHECK-NEXT: br i1 [[CMP1]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
420; CHECK: guarded:
421; CHECK-NEXT: [[SUB2:%.*]] = sub nsw i32 [[ARG]], [[I]]
422; CHECK-NEXT: [[SUB3:%.*]] = sub nsw i32 [[SUB2]], 1
423; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 0, [[SUB3]]
424; CHECK-NEXT: br i1 [[CMP2]], label [[INNER_PH:%.*]], label [[OUTER_INC]]
425; CHECK: inner.ph:
426; CHECK-NEXT: br label [[INNER:%.*]]
427; CHECK: inner:
428; CHECK-NEXT: br i1 false, label [[INNER]], label [[OUTER_INC_LOOPEXIT:%.*]]
429; CHECK: outer.inc.loopexit:
430; CHECK-NEXT: br label [[OUTER_INC]]
431; CHECK: outer.inc:
432; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1
433; CHECK-NEXT: [[CMP4:%.*]] = icmp slt i32 [[I_INC]], [[ARG]]
434; CHECK-NEXT: br i1 [[CMP4]], label [[OUTER]], label [[EXIT]]
435; CHECK: exit:
436; CHECK-NEXT: ret void
437;
438entry:
439 br label %outer
440
441outer:
442 %i = phi i32 [ 0, %entry ], [ %i.inc, %outer.inc ]
443 %sub1 = sub nsw i32 %arg, 1
444 %cmp1 = icmp slt i32 0, %sub1
445 br i1 %cmp1, label %guarded, label %exit
446
447guarded:
448 %sub2 = sub nsw i32 %arg, %i
449 %sub3 = sub nsw i32 %sub2, 1
450 %cmp2 = icmp ult i32 0, %sub3
451 br i1 %cmp2, label %inner.ph, label %outer.inc
452
453inner.ph:
454 br label %inner
455
456inner:
457 %j = phi i32 [ 0, %inner.ph ], [ %j.inc, %inner ]
458 %j.inc = add nsw i32 %j, 1
459 %cmp3 = icmp slt i32 %j.inc, %sub3
460 br i1 %cmp3, label %inner, label %outer.inc
461
462outer.inc:
463 %i.inc = add nsw i32 %i, 1
464 %cmp4 = icmp slt i32 %i.inc, %arg
465 br i1 %cmp4, label %outer, label %exit
466
467exit:
468 ret void
469}
470
Max Kazantsev15985952020-09-28 12:04:20 +0700471define void @test_can_predicate_simple_unsigned(i32* %p, i32* %arr) {
472; CHECK-LABEL: @test_can_predicate_simple_unsigned(
473; CHECK-NEXT: preheader:
474; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4
475; CHECK-NEXT: br label [[LOOP:%.*]]
476; CHECK: loop:
477; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[LEN]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
478; CHECK-NEXT: [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0
479; CHECK-NEXT: br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
480; CHECK: range_check_block:
481; CHECK-NEXT: [[IV_NEXT]] = sub i32 [[IV]], 1
482; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[IV_NEXT]], [[LEN]]
483; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
484; CHECK: backedge:
485; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[P]], i32 [[IV]]
486; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4
487; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
488; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
489; CHECK: exit:
490; CHECK-NEXT: ret void
491; CHECK: fail:
492; CHECK-NEXT: unreachable
493;
494preheader:
495 %len = load i32, i32* %p
496 br label %loop
497
498loop:
499 %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
500 %zero_cond = icmp eq i32 %iv, 0
501 br i1 %zero_cond, label %exit, label %range_check_block
502
503range_check_block:
504 %iv.next = sub i32 %iv, 1
505 %range_check = icmp ult i32 %iv.next, %len
506 br i1 %range_check, label %backedge, label %fail
507
508backedge:
509 %el.ptr = getelementptr i32, i32* %p, i32 %iv
510 %el = load i32, i32* %el.ptr
511 %loop.cond = icmp eq i32 %el, 0
512 br i1 %loop.cond, label %loop, label %exit
513
514exit:
515 ret void
516
517fail:
518 unreachable
519}
520
521define void @test_can_predicate_simple_signed(i32* %p, i32* %arr) {
522; CHECK-LABEL: @test_can_predicate_simple_signed(
523; CHECK-NEXT: preheader:
524; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4
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 i32 [[IV]], 1
532; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp slt i32 [[IV_NEXT]], [[LEN]]
533; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
534; CHECK: backedge:
535; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[P]], i32 [[IV]]
536; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4
537; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
538; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
539; CHECK: exit:
540; CHECK-NEXT: ret void
541; CHECK: fail:
542; CHECK-NEXT: unreachable
543;
544preheader:
545 %len = load i32, i32* %p
546 br label %loop
547
548loop:
549 %iv = phi i32 [%len, %preheader], [%iv.next, %backedge]
550 %zero_cond = icmp eq i32 %iv, 0
551 br i1 %zero_cond, label %exit, label %range_check_block
552
553range_check_block:
554 %iv.next = sub i32 %iv, 1
555 %range_check = icmp slt i32 %iv.next, %len
556 br i1 %range_check, label %backedge, label %fail
557
558backedge:
559 %el.ptr = getelementptr i32, i32* %p, i32 %iv
560 %el = load i32, i32* %el.ptr
561 %loop.cond = icmp eq i32 %el, 0
562 br i1 %loop.cond, label %loop, label %exit
563
564exit:
565 ret void
566
567fail:
568 unreachable
569}
570
Max Kazantsev63354462020-10-27 14:50:00 +0700571define void @test_can_predicate_trunc_unsigned(i32* %p, i32* %arr) {
572; CHECK-LABEL: @test_can_predicate_trunc_unsigned(
573; CHECK-NEXT: preheader:
574; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4
575; CHECK-NEXT: [[START:%.*]] = zext i32 [[LEN]] to i64
576; CHECK-NEXT: br label [[LOOP:%.*]]
577; CHECK: loop:
578; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
579; CHECK-NEXT: [[ZERO_COND:%.*]] = icmp eq i64 [[IV]], 0
580; CHECK-NEXT: br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
581; CHECK: range_check_block:
582; CHECK-NEXT: [[IV_NEXT]] = sub nsw i64 [[IV]], 1
583; CHECK-NEXT: [[NARROW:%.*]] = trunc i64 [[IV_NEXT]] to i32
584; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[NARROW]], [[LEN]]
585; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
586; CHECK: backedge:
587; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[ARR:%.*]], i64 [[IV]]
588; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4
589; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[EL]], 0
590; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT]]
591; CHECK: exit:
592; CHECK-NEXT: ret void
593; CHECK: fail:
594; CHECK-NEXT: unreachable
595;
596preheader:
597 %len = load i32, i32* %p
598 %start = zext i32 %len to i64
599 br label %loop
600
601loop:
602 %iv = phi i64 [%start, %preheader], [%iv.next, %backedge]
603 %zero_cond = icmp eq i64 %iv, 0
604 br i1 %zero_cond, label %exit, label %range_check_block
605
606range_check_block:
607 %iv.next = sub i64 %iv, 1
608 %narrow = trunc i64 %iv.next to i32
609 %range_check = icmp ult i32 %narrow, %len
610 br i1 %range_check, label %backedge, label %fail
611
612backedge:
613 %el.ptr = getelementptr i32, i32* %arr, i64 %iv
614 %el = load i32, i32* %el.ptr
615 %loop.cond = icmp eq i32 %el, 0
616 br i1 %loop.cond, label %loop, label %exit
617
618exit:
619 ret void
620
621fail:
622 unreachable
623}
624
Max Kazantsevda9e7b12020-08-07 16:46:39 +0700625!0 = !{i32 0, i32 2147483647}