1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=indvars -indvars-post-increment-ranges -S | FileCheck %s
4 target datalayout = "p:64:64:64-n32:64"
6 ; When the IV in this loop is widened we want to widen this use as well:
7 ; icmp slt i32 %i.inc, %limit
8 ; In order to do this indvars need to prove that the narrow IV def (%i.inc)
9 ; is not-negative from the range check inside of the loop.
10 define void @test(ptr %base, i32 %limit, i32 %start) {
12 ; CHECK-NEXT: for.body.lr.ph:
13 ; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[START:%.*]], i32 64)
14 ; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[UMAX]], [[START]]
15 ; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[START]], 1
16 ; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[LIMIT:%.*]], i32 [[TMP1]])
17 ; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SMAX]], -1
18 ; CHECK-NEXT: [[TMP3:%.*]] = sub i32 [[TMP2]], [[START]]
19 ; CHECK-NEXT: [[TMP4:%.*]] = freeze i32 [[TMP3]]
20 ; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP4]], i32 [[TMP0]])
21 ; CHECK-NEXT: [[TMP5:%.*]] = icmp ne i32 [[TMP0]], [[UMIN]]
22 ; CHECK-NEXT: [[TMP6:%.*]] = icmp ne i32 [[TMP3]], [[UMIN]]
23 ; CHECK-NEXT: br label [[FOR_BODY:%.*]]
25 ; CHECK-NEXT: br i1 [[TMP5]], label [[CONTINUE:%.*]], label [[FOR_END:%.*]]
27 ; CHECK-NEXT: br label [[FOR_INC:%.*]]
29 ; CHECK-NEXT: br i1 [[TMP6]], label [[FOR_BODY]], label [[FOR_END]]
31 ; CHECK-NEXT: br label [[EXIT:%.*]]
33 ; CHECK-NEXT: ret void
40 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ]
41 %within_limits = icmp ult i32 %i, 64
42 br i1 %within_limits, label %continue, label %for.end
45 %i.i64 = zext i32 %i to i64
46 %arrayidx = getelementptr inbounds i32, ptr %base, i64 %i.i64
47 %val = load i32, ptr %arrayidx, align 4
51 %i.inc = add nsw nuw i32 %i, 1
52 %cmp = icmp slt i32 %i.inc, %limit
53 br i1 %cmp, label %for.body, label %for.end
62 define void @test_false_edge(ptr %base, i32 %limit, i32 %start) {
63 ; CHECK-LABEL: @test_false_edge(
64 ; CHECK-NEXT: for.body.lr.ph:
65 ; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[START:%.*]], i32 65)
66 ; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[UMAX]], [[START]]
67 ; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[START]], 1
68 ; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[LIMIT:%.*]], i32 [[TMP1]])
69 ; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SMAX]], -1
70 ; CHECK-NEXT: [[TMP3:%.*]] = sub i32 [[TMP2]], [[START]]
71 ; CHECK-NEXT: [[TMP4:%.*]] = freeze i32 [[TMP3]]
72 ; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP4]], i32 [[TMP0]])
73 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP0]], [[UMIN]]
74 ; CHECK-NEXT: [[TMP6:%.*]] = icmp ne i32 [[TMP3]], [[UMIN]]
75 ; CHECK-NEXT: br label [[FOR_BODY:%.*]]
77 ; CHECK-NEXT: br i1 [[TMP5]], label [[FOR_END:%.*]], label [[CONTINUE:%.*]]
79 ; CHECK-NEXT: br label [[FOR_INC:%.*]]
81 ; CHECK-NEXT: br i1 [[TMP6]], label [[FOR_BODY]], label [[FOR_END]]
83 ; CHECK-NEXT: br label [[EXIT:%.*]]
85 ; CHECK-NEXT: ret void
92 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ]
93 %out_of_bounds = icmp ugt i32 %i, 64
94 br i1 %out_of_bounds, label %for.end, label %continue
97 %i.i64 = zext i32 %i to i64
98 %arrayidx = getelementptr inbounds i32, ptr %base, i64 %i.i64
99 %val = load i32, ptr %arrayidx, align 4
103 %i.inc = add nsw nuw i32 %i, 1
104 %cmp = icmp slt i32 %i.inc, %limit
105 br i1 %cmp, label %for.body, label %for.end
114 define void @test_range_metadata(ptr %array_length_ptr, ptr %base,
115 ; CHECK-LABEL: @test_range_metadata(
116 ; CHECK-NEXT: for.body.lr.ph:
117 ; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[START:%.*]] to i64
118 ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[LIMIT:%.*]] to i64
119 ; CHECK-NEXT: br label [[FOR_BODY:%.*]]
121 ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[FOR_INC:%.*]] ], [ [[TMP0]], [[FOR_BODY_LR_PH:%.*]] ]
122 ; CHECK-NEXT: [[ARRAY_LENGTH:%.*]] = load i32, ptr [[ARRAY_LENGTH_PTR:%.*]], align 4, !range [[RNG0:![0-9]+]]
123 ; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[ARRAY_LENGTH]] to i64
124 ; CHECK-NEXT: [[WITHIN_LIMITS:%.*]] = icmp ult i64 [[INDVARS_IV]], [[TMP2]]
125 ; CHECK-NEXT: br i1 [[WITHIN_LIMITS]], label [[CONTINUE:%.*]], label [[FOR_END:%.*]]
127 ; CHECK-NEXT: br label [[FOR_INC]]
129 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
130 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[INDVARS_IV_NEXT]], [[TMP1]]
131 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END]]
133 ; CHECK-NEXT: br label [[EXIT:%.*]]
135 ; CHECK-NEXT: ret void
137 i32 %limit, i32 %start) {
143 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ]
144 %array_length = load i32, ptr %array_length_ptr, !range !{i32 0, i32 64 }
145 %within_limits = icmp ult i32 %i, %array_length
146 br i1 %within_limits, label %continue, label %for.end
149 %i.i64 = zext i32 %i to i64
150 %arrayidx = getelementptr inbounds i32, ptr %base, i64 %i.i64
151 %val = load i32, ptr %arrayidx, align 4
155 %i.inc = add nsw nuw i32 %i, 1
156 %cmp = icmp slt i32 %i.inc, %limit
157 br i1 %cmp, label %for.body, label %for.end
166 ; Negative version of the test above, we don't know anything about
167 ; array_length_ptr range.
168 define void @test_neg(ptr %array_length_ptr, ptr %base,
169 ; CHECK-LABEL: @test_neg(
170 ; CHECK-NEXT: for.body.lr.ph:
171 ; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[START:%.*]] to i64
172 ; CHECK-NEXT: br label [[FOR_BODY:%.*]]
174 ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[FOR_INC:%.*]] ], [ [[TMP0]], [[FOR_BODY_LR_PH:%.*]] ]
175 ; CHECK-NEXT: [[ARRAY_LENGTH:%.*]] = load i32, ptr [[ARRAY_LENGTH_PTR:%.*]], align 4
176 ; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[ARRAY_LENGTH]] to i64
177 ; CHECK-NEXT: [[WITHIN_LIMITS:%.*]] = icmp ult i64 [[INDVARS_IV]], [[TMP1]]
178 ; CHECK-NEXT: br i1 [[WITHIN_LIMITS]], label [[CONTINUE:%.*]], label [[FOR_END:%.*]]
180 ; CHECK-NEXT: br label [[FOR_INC]]
182 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
183 ; CHECK-NEXT: [[TMP2:%.*]] = trunc nuw i64 [[INDVARS_IV_NEXT]] to i32
184 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP2]], [[LIMIT:%.*]]
185 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END]]
187 ; CHECK-NEXT: br label [[EXIT:%.*]]
189 ; CHECK-NEXT: ret void
191 i32 %limit, i32 %start) {
197 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ]
198 %array_length = load i32, ptr %array_length_ptr
199 %within_limits = icmp ult i32 %i, %array_length
200 br i1 %within_limits, label %continue, label %for.end
203 %i.i64 = zext i32 %i to i64
204 %arrayidx = getelementptr inbounds i32, ptr %base, i64 %i.i64
205 %val = load i32, ptr %arrayidx, align 4
209 %i.inc = add nsw nuw i32 %i, 1
210 %cmp = icmp slt i32 %i.inc, %limit
211 br i1 %cmp, label %for.body, label %for.end
220 define void @test_transitive_use(ptr %base, i32 %limit, i32 %start) {
221 ; CHECK-LABEL: @test_transitive_use(
222 ; CHECK-NEXT: for.body.lr.ph:
223 ; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[START:%.*]] to i64
224 ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[LIMIT:%.*]] to i64
225 ; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[LIMIT]] to i64
226 ; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[START]], i32 64)
227 ; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext i32 [[UMAX]] to i64
228 ; CHECK-NEXT: br label [[FOR_BODY:%.*]]
230 ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[FOR_INC:%.*]] ], [ [[TMP0]], [[FOR_BODY_LR_PH:%.*]] ]
231 ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV]], [[WIDE_TRIP_COUNT]]
232 ; CHECK-NEXT: br i1 [[EXITCOND]], label [[CONTINUE:%.*]], label [[FOR_END:%.*]]
234 ; CHECK-NEXT: [[TMP3:%.*]] = mul nuw nsw i64 [[INDVARS_IV]], 3
235 ; CHECK-NEXT: [[MUL_WITHIN:%.*]] = icmp ult i64 [[TMP3]], 64
236 ; CHECK-NEXT: br i1 [[MUL_WITHIN]], label [[GUARDED:%.*]], label [[CONTINUE_2:%.*]]
238 ; CHECK-NEXT: [[TMP4:%.*]] = add nuw nsw i64 [[TMP3]], 1
239 ; CHECK-NEXT: [[RESULT:%.*]] = icmp slt i64 [[TMP4]], [[TMP1]]
240 ; CHECK-NEXT: br i1 [[RESULT]], label [[CONTINUE_2]], label [[FOR_END]]
242 ; CHECK-NEXT: br label [[FOR_INC]]
244 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
245 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[INDVARS_IV_NEXT]], [[TMP2]]
246 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END]]
248 ; CHECK-NEXT: br label [[EXIT:%.*]]
250 ; CHECK-NEXT: ret void
257 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ]
258 %within_limits = icmp ult i32 %i, 64
259 br i1 %within_limits, label %continue, label %for.end
262 %i.mul.3 = mul nsw nuw i32 %i, 3
263 %mul_within = icmp ult i32 %i.mul.3, 64
264 br i1 %mul_within, label %guarded, label %continue.2
267 %i.mul.3.inc = add nsw nuw i32 %i.mul.3, 1
268 %result = icmp slt i32 %i.mul.3.inc, %limit
269 br i1 %result, label %continue.2, label %for.end
272 %i.i64 = zext i32 %i to i64
273 %arrayidx = getelementptr inbounds i32, ptr %base, i64 %i.i64
274 %val = load i32, ptr %arrayidx, align 4
278 %i.inc = add nsw nuw i32 %i, 1
279 %cmp = icmp slt i32 %i.inc, %limit
280 br i1 %cmp, label %for.body, label %for.end
290 declare void @llvm.experimental.guard(i1, ...)
292 define void @test_guard_one_bb(ptr %base, i32 %limit, i32 %start) {
293 ; CHECK-LABEL: @test_guard_one_bb(
294 ; CHECK-NEXT: for.body.lr.ph:
295 ; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[START:%.*]] to i64
296 ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[LIMIT:%.*]] to i64
297 ; CHECK-NEXT: br label [[FOR_BODY:%.*]]
299 ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[TMP0]], [[FOR_BODY_LR_PH:%.*]] ]
300 ; CHECK-NEXT: [[WITHIN_LIMITS:%.*]] = icmp ult i64 [[INDVARS_IV]], 64
301 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_LIMITS]]) [ "deopt"() ]
302 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
303 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[INDVARS_IV_NEXT]], [[TMP1]]
304 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
306 ; CHECK-NEXT: br label [[EXIT:%.*]]
308 ; CHECK-NEXT: ret void
315 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.body ]
316 %within_limits = icmp ult i32 %i, 64
317 %i.i64 = zext i32 %i to i64
318 %arrayidx = getelementptr inbounds i32, ptr %base, i64 %i.i64
319 %val = load i32, ptr %arrayidx, align 4
320 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits) [ "deopt"() ]
321 %i.inc = add nsw nuw i32 %i, 1
322 %cmp = icmp slt i32 %i.inc, %limit
323 br i1 %cmp, label %for.body, label %for.end
332 define void @test_guard_in_the_same_bb(ptr %base, i32 %limit, i32 %start) {
333 ; CHECK-LABEL: @test_guard_in_the_same_bb(
334 ; CHECK-NEXT: for.body.lr.ph:
335 ; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[START:%.*]] to i64
336 ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[LIMIT:%.*]] to i64
337 ; CHECK-NEXT: br label [[FOR_BODY:%.*]]
339 ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[FOR_INC:%.*]] ], [ [[TMP0]], [[FOR_BODY_LR_PH:%.*]] ]
340 ; CHECK-NEXT: [[WITHIN_LIMITS:%.*]] = icmp ult i64 [[INDVARS_IV]], 64
341 ; CHECK-NEXT: br label [[FOR_INC]]
343 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_LIMITS]]) [ "deopt"() ]
344 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
345 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[INDVARS_IV_NEXT]], [[TMP1]]
346 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
348 ; CHECK-NEXT: br label [[EXIT:%.*]]
350 ; CHECK-NEXT: ret void
357 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ]
358 %within_limits = icmp ult i32 %i, 64
359 %i.i64 = zext i32 %i to i64
360 %arrayidx = getelementptr inbounds i32, ptr %base, i64 %i.i64
361 %val = load i32, ptr %arrayidx, align 4
365 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits) [ "deopt"() ]
366 %i.inc = add nsw nuw i32 %i, 1
367 %cmp = icmp slt i32 %i.inc, %limit
368 br i1 %cmp, label %for.body, label %for.end
377 define void @test_guard_in_idom(ptr %base, i32 %limit, i32 %start) {
378 ; CHECK-LABEL: @test_guard_in_idom(
379 ; CHECK-NEXT: for.body.lr.ph:
380 ; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[START:%.*]] to i64
381 ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[LIMIT:%.*]] to i64
382 ; CHECK-NEXT: br label [[FOR_BODY:%.*]]
384 ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[FOR_INC:%.*]] ], [ [[TMP0]], [[FOR_BODY_LR_PH:%.*]] ]
385 ; CHECK-NEXT: [[WITHIN_LIMITS:%.*]] = icmp ult i64 [[INDVARS_IV]], 64
386 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_LIMITS]]) [ "deopt"() ]
387 ; CHECK-NEXT: br label [[FOR_INC]]
389 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
390 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[INDVARS_IV_NEXT]], [[TMP1]]
391 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
393 ; CHECK-NEXT: br label [[EXIT:%.*]]
395 ; CHECK-NEXT: ret void
402 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.inc ]
403 %within_limits = icmp ult i32 %i, 64
404 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits) [ "deopt"() ]
405 %i.i64 = zext i32 %i to i64
406 %arrayidx = getelementptr inbounds i32, ptr %base, i64 %i.i64
407 %val = load i32, ptr %arrayidx, align 4
411 %i.inc = add nsw nuw i32 %i, 1
412 %cmp = icmp slt i32 %i.inc, %limit
413 br i1 %cmp, label %for.body, label %for.end
422 define void @test_guard_merge_ranges(ptr %base, i32 %limit, i32 %start) {
423 ; CHECK-LABEL: @test_guard_merge_ranges(
424 ; CHECK-NEXT: for.body.lr.ph:
425 ; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[START:%.*]] to i64
426 ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[LIMIT:%.*]] to i64
427 ; CHECK-NEXT: br label [[FOR_BODY:%.*]]
429 ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[TMP0]], [[FOR_BODY_LR_PH:%.*]] ]
430 ; CHECK-NEXT: [[WITHIN_LIMITS_1:%.*]] = icmp ult i64 [[INDVARS_IV]], 64
431 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_LIMITS_1]]) [ "deopt"() ]
432 ; CHECK-NEXT: [[WITHIN_LIMITS_2:%.*]] = icmp ult i64 [[INDVARS_IV]], 2147483647
433 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_LIMITS_2]]) [ "deopt"() ]
434 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
435 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[INDVARS_IV_NEXT]], [[TMP1]]
436 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
438 ; CHECK-NEXT: br label [[EXIT:%.*]]
440 ; CHECK-NEXT: ret void
447 %i = phi i32 [ %start, %for.body.lr.ph ], [ %i.inc, %for.body ]
448 %within_limits.1 = icmp ult i32 %i, 64
449 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits.1) [ "deopt"() ]
450 %within_limits.2 = icmp ult i32 %i, 2147483647
451 call void(i1, ...) @llvm.experimental.guard(i1 %within_limits.2) [ "deopt"() ]
452 %i.i64 = zext i32 %i to i64
453 %arrayidx = getelementptr inbounds i32, ptr %base, i64 %i.i64
454 %val = load i32, ptr %arrayidx, align 4
455 %i.inc = add nsw nuw i32 %i, 1
456 %cmp = icmp slt i32 %i.inc, %limit
457 br i1 %cmp, label %for.body, label %for.end