; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -verify-loop-info -passes=irce -irce-print-scaled-boundary-range-checks -S < %s 2>&1 | FileCheck %s
; CHECK: irce: in function test1, in Loop at depth 1 containing: %loop<header><exiting>,%inbounds<latch><exiting>
; CHECK-NEXT: there is range check with scaled boundary:
; CHECK-NEXT: InductiveRangeCheck:
; CHECK-NEXT: Begin: 0 Step: 1 End: (-1 + (sext i8 %n to i16))<nsw>
; CHECK-NEXT: CheckUse: br i1 %check, label %inbounds, label %out_of_bounds Operand: 0
;
; CHECK-NEXT: irce: in function test4, in Loop at depth 1 containing: %loop<header><exiting>,%inbounds<latch><exiting>
; CHECK-NEXT: there is range check with scaled boundary:
; CHECK-NEXT: InductiveRangeCheck:
; CHECK-NEXT: Begin: 0 Step: 1 End: (-2 + (sext i8 %n to i16))<nsw>
; CHECK-NEXT: CheckUse: br i1 %check, label %inbounds, label %out_of_bounds Operand: 0
;
; CHECK-NEXT: irce: in function test_overflow_check_runtime, in Loop at depth 1 containing: %loop<header><exiting>,%inbounds<latch><exiting>
; CHECK-NEXT: there is range check with scaled boundary:
; CHECK-NEXT: InductiveRangeCheck:
; CHECK-NEXT: Begin: 0 Step: 1 End: (3 + (zext i8 %n to i16))<nuw><nsw>
; CHECK-NEXT: CheckUse: br i1 %check, label %inbounds, label %out_of_bounds Operand: 0
; IV = 0; IV <s limit; IV += 1;
; Check(N - IV >= 2)
; IRCE is allowed.
define i8 @test1(i8 %limit, i8 %n) {
; CHECK-LABEL: define i8 @test1
; CHECK-SAME: (i8 [[LIMIT:%.*]], i8 [[N:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[N]], -1
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[N]], -128
; CHECK-NEXT: [[SMAX:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 0)
; CHECK-NEXT: [[TMP2:%.*]] = sub i8 [[TMP0]], [[SMAX]]
; CHECK-NEXT: [[SMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[TMP0]], i8 0)
; CHECK-NEXT: [[SMAX2:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN]], i8 -1)
; CHECK-NEXT: [[TMP3:%.*]] = add nsw i8 [[SMAX2]], 1
; CHECK-NEXT: [[TMP4:%.*]] = mul i8 [[TMP2]], [[TMP3]]
; CHECK-NEXT: [[TMP5:%.*]] = sext i8 [[N]] to i16
; CHECK-NEXT: [[TMP6:%.*]] = add nsw i16 [[TMP5]], 127
; CHECK-NEXT: [[SMIN3:%.*]] = call i16 @llvm.smin.i16(i16 [[TMP6]], i16 0)
; CHECK-NEXT: [[TMP7:%.*]] = trunc i16 [[SMIN3]] to i8
; CHECK-NEXT: [[TMP8:%.*]] = add nsw i8 [[TMP7]], 1
; CHECK-NEXT: [[TMP9:%.*]] = mul i8 [[TMP4]], [[TMP8]]
; CHECK-NEXT: [[SMIN4:%.*]] = call i8 @llvm.smin.i8(i8 [[LIMIT]], i8 [[TMP9]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN4]], i8 0)
; CHECK-NEXT: [[TMP10:%.*]] = icmp slt i8 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP10]], label [[LOOP_PREHEADER7:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader7:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER7]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[N]], [[IDX]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp sge i8 [[SUB]], 2
; CHECK-NEXT: br i1 true, label [[INBOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT8:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: [[TMP11:%.*]] = icmp slt i8 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP11]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i8 [ [[IDX_NEXT]], [[INBOUNDS]] ]
; CHECK-NEXT: [[IDX_LCSSA6:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: [[TMP12:%.*]] = icmp slt i8 [[IDX_NEXT_LCSSA]], [[LIMIT]]
; CHECK-NEXT: br i1 [[TMP12]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX_LCSSA6]], [[MAIN_EXIT_SELECTOR]] ], [ [[IDX_LCSSA1_PH]], [[EXIT_LOOPEXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds.loopexit:
; CHECK-NEXT: [[IDX_LCSSA_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP]], [[LOOP_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]]
; CHECK: out_of_bounds.loopexit8:
; CHECK-NEXT: [[IDX_LCSSA_PH9:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX_LCSSA_PH]], [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] ], [ [[IDX_LCSSA_PH9]], [[OUT_OF_BOUNDS_LOOPEXIT8]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IDX_POSTLOOP]] = phi i8 [ [[IDX_NEXT_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP]] ], [ [[IDX_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: [[SUB_POSTLOOP:%.*]] = sub i8 [[N]], [[IDX_POSTLOOP]]
; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp sge i8 [[SUB_POSTLOOP]], 2
; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[INBOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT]]
; CHECK: inbounds.postloop:
; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw i8 [[IDX_POSTLOOP]], 1
; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i8 [[IDX_NEXT_POSTLOOP]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT_LOOPEXIT]], !llvm.loop [[LOOP0:![0-9]+]], !loop_constrainer.loop.clone !5
;
entry:
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %n, %idx
%check = icmp sge i8 %sub, 2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(N - IV >= 2)
; N is known to be non-negative.
; TODO: IRCE is allowed.
define i8 @test1a(i8 %limit, ptr %p) {
; CHECK-LABEL: define i8 @test1a
; CHECK-SAME: (i8 [[LIMIT:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG6:![0-9]+]]
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i8 [[N]], -1
; CHECK-NEXT: [[SMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[TMP0]], i8 0)
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i8 [[SMIN]], 1
; CHECK-NEXT: [[TMP2:%.*]] = mul i8 [[TMP0]], [[TMP1]]
; CHECK-NEXT: [[SMIN2:%.*]] = call i8 @llvm.smin.i8(i8 [[LIMIT]], i8 [[TMP2]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN2]], i8 0)
; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i8 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP3]], label [[LOOP_PREHEADER4:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader4:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER4]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[N]], [[IDX]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp sge i8 [[SUB]], 2
; CHECK-NEXT: br i1 true, label [[INBOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT5:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i8 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP4]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i8 [ [[IDX_NEXT]], [[INBOUNDS]] ]
; CHECK-NEXT: [[IDX_LCSSA3:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i8 [[IDX_NEXT_LCSSA]], [[LIMIT]]
; CHECK-NEXT: br i1 [[TMP5]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX_LCSSA3]], [[MAIN_EXIT_SELECTOR]] ], [ [[IDX_LCSSA1_PH]], [[EXIT_LOOPEXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds.loopexit:
; CHECK-NEXT: [[IDX_LCSSA_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP]], [[LOOP_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]]
; CHECK: out_of_bounds.loopexit5:
; CHECK-NEXT: [[IDX_LCSSA_PH6:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX_LCSSA_PH]], [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] ], [ [[IDX_LCSSA_PH6]], [[OUT_OF_BOUNDS_LOOPEXIT5]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IDX_POSTLOOP]] = phi i8 [ [[IDX_NEXT_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP]] ], [ [[IDX_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: [[SUB_POSTLOOP:%.*]] = sub i8 [[N]], [[IDX_POSTLOOP]]
; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp sge i8 [[SUB_POSTLOOP]], 2
; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[INBOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT]]
; CHECK: inbounds.postloop:
; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw i8 [[IDX_POSTLOOP]], 1
; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i8 [[IDX_NEXT_POSTLOOP]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT_LOOPEXIT]], !llvm.loop [[LOOP7:![0-9]+]], !loop_constrainer.loop.clone !5
;
entry:
%n = load i8, ptr %p, !range !0
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %n, %idx
%check = icmp sge i8 %sub, 2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(IV - N <= -2)
; TODO: IRCE is allowed.
define i8 @test2(i8 %limit, i8 %n) {
; CHECK-LABEL: define i8 @test2
; CHECK-SAME: (i8 [[LIMIT:%.*]], i8 [[N:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[IDX]], [[N]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp sle i8 [[SUB]], -2
; CHECK-NEXT: br i1 [[CHECK]], label [[INBOUNDS]], label [[OUT_OF_BOUNDS:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
;
entry:
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %idx, %n
%check = icmp sle i8 %sub, -2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(IV - N <= -2)
; N is known to be non-negative.
; TODO: IRCE is allowed.
define i8 @test2a(i8 %limit, ptr %p) {
; CHECK-LABEL: define i8 @test2a
; CHECK-SAME: (i8 [[LIMIT:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG6]]
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[IDX]], [[N]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp sle i8 [[SUB]], -2
; CHECK-NEXT: br i1 [[CHECK]], label [[INBOUNDS]], label [[OUT_OF_BOUNDS:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
;
entry:
%n = load i8, ptr %p, !range !0
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %idx, %n
%check = icmp sle i8 %sub, -2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(IV + 2 <= N)
; TODO: IRCE is allowed.
define i8 @test3(i8 %limit, i8 %n) {
; CHECK-LABEL: define i8 @test3
; CHECK-SAME: (i8 [[LIMIT:%.*]], i8 [[N:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[IDX]], 2
; CHECK-NEXT: [[CHECK:%.*]] = icmp sle i8 [[ADD]], [[N]]
; CHECK-NEXT: br i1 [[CHECK]], label [[INBOUNDS]], label [[OUT_OF_BOUNDS:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
;
entry:
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%add = add i8 %idx, 2
%check = icmp sle i8 %add, %n
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(IV + 2 <= N)
; N is known to be non-negative.
; IRCE is allowed.
define i8 @test3a(i8 %limit, ptr %p) {
; CHECK-LABEL: define i8 @test3a
; CHECK-SAME: (i8 [[LIMIT:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG6]]
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i8 [[N]], -1
; CHECK-NEXT: [[SMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[LIMIT]], i8 [[TMP0]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN]], i8 0)
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PREHEADER3:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader3:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER3]] ]
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[IDX]], 2
; CHECK-NEXT: [[CHECK:%.*]] = icmp sle i8 [[ADD]], [[N]]
; CHECK-NEXT: br i1 true, label [[INBOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT4:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i8 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i8 [ [[IDX_NEXT]], [[INBOUNDS]] ]
; CHECK-NEXT: [[IDX_LCSSA2:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i8 [[IDX_NEXT_LCSSA]], [[LIMIT]]
; CHECK-NEXT: br i1 [[TMP3]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX_LCSSA2]], [[MAIN_EXIT_SELECTOR]] ], [ [[IDX_LCSSA1_PH]], [[EXIT_LOOPEXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds.loopexit:
; CHECK-NEXT: [[IDX_LCSSA_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP]], [[LOOP_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]]
; CHECK: out_of_bounds.loopexit4:
; CHECK-NEXT: [[IDX_LCSSA_PH5:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX_LCSSA_PH]], [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] ], [ [[IDX_LCSSA_PH5]], [[OUT_OF_BOUNDS_LOOPEXIT4]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IDX_POSTLOOP]] = phi i8 [ [[IDX_NEXT_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP]] ], [ [[IDX_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: [[ADD_POSTLOOP:%.*]] = add i8 [[IDX_POSTLOOP]], 2
; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp sle i8 [[ADD_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[INBOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT]]
; CHECK: inbounds.postloop:
; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw i8 [[IDX_POSTLOOP]], 1
; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i8 [[IDX_NEXT_POSTLOOP]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT_LOOPEXIT]], !llvm.loop [[LOOP8:![0-9]+]], !loop_constrainer.loop.clone !5
;
entry:
%n = load i8, ptr %p, !range !0
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%add = add i8 %idx, 2
%check = icmp sle i8 %add, %n
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(N - IV > 2)
; IRCE is allowed.
define i8 @test4(i8 %limit, i8 %n) {
; CHECK-LABEL: define i8 @test4
; CHECK-SAME: (i8 [[LIMIT:%.*]], i8 [[N:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[N]], -2
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[N]], 127
; CHECK-NEXT: [[SMAX:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 0)
; CHECK-NEXT: [[TMP2:%.*]] = sub i8 [[TMP0]], [[SMAX]]
; CHECK-NEXT: [[SMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[TMP0]], i8 0)
; CHECK-NEXT: [[SMAX2:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN]], i8 -1)
; CHECK-NEXT: [[TMP3:%.*]] = add nsw i8 [[SMAX2]], 1
; CHECK-NEXT: [[TMP4:%.*]] = mul i8 [[TMP2]], [[TMP3]]
; CHECK-NEXT: [[TMP5:%.*]] = sext i8 [[N]] to i16
; CHECK-NEXT: [[TMP6:%.*]] = add nsw i16 [[TMP5]], 126
; CHECK-NEXT: [[SMIN3:%.*]] = call i16 @llvm.smin.i16(i16 [[TMP6]], i16 0)
; CHECK-NEXT: [[SMAX4:%.*]] = call i16 @llvm.smax.i16(i16 [[SMIN3]], i16 -1)
; CHECK-NEXT: [[TMP7:%.*]] = trunc i16 [[SMAX4]] to i8
; CHECK-NEXT: [[TMP8:%.*]] = add nsw i8 [[TMP7]], 1
; CHECK-NEXT: [[TMP9:%.*]] = mul i8 [[TMP4]], [[TMP8]]
; CHECK-NEXT: [[SMIN5:%.*]] = call i8 @llvm.smin.i8(i8 [[LIMIT]], i8 [[TMP9]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN5]], i8 0)
; CHECK-NEXT: [[TMP10:%.*]] = icmp slt i8 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP10]], label [[LOOP_PREHEADER8:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader8:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER8]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[N]], [[IDX]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp sgt i8 [[SUB]], 2
; CHECK-NEXT: br i1 true, label [[INBOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT9:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: [[TMP11:%.*]] = icmp slt i8 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP11]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i8 [ [[IDX_NEXT]], [[INBOUNDS]] ]
; CHECK-NEXT: [[IDX_LCSSA7:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: [[TMP12:%.*]] = icmp slt i8 [[IDX_NEXT_LCSSA]], [[LIMIT]]
; CHECK-NEXT: br i1 [[TMP12]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX_LCSSA7]], [[MAIN_EXIT_SELECTOR]] ], [ [[IDX_LCSSA1_PH]], [[EXIT_LOOPEXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds.loopexit:
; CHECK-NEXT: [[IDX_LCSSA_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP]], [[LOOP_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]]
; CHECK: out_of_bounds.loopexit9:
; CHECK-NEXT: [[IDX_LCSSA_PH10:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX_LCSSA_PH]], [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] ], [ [[IDX_LCSSA_PH10]], [[OUT_OF_BOUNDS_LOOPEXIT9]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IDX_POSTLOOP]] = phi i8 [ [[IDX_NEXT_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP]] ], [ [[IDX_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: [[SUB_POSTLOOP:%.*]] = sub i8 [[N]], [[IDX_POSTLOOP]]
; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp sgt i8 [[SUB_POSTLOOP]], 2
; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[INBOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT]]
; CHECK: inbounds.postloop:
; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw i8 [[IDX_POSTLOOP]], 1
; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i8 [[IDX_NEXT_POSTLOOP]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT_LOOPEXIT]], !llvm.loop [[LOOP9:![0-9]+]], !loop_constrainer.loop.clone !5
;
entry:
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %n, %idx
%check = icmp sgt i8 %sub, 2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(N - IV > 2)
; N is known to be non-negative.
; TODO: IRCE is allowed.
define i8 @test4a(i8 %limit, ptr %p) {
; CHECK-LABEL: define i8 @test4a
; CHECK-SAME: (i8 [[LIMIT:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG6]]
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[N]], -2
; CHECK-NEXT: [[TMP1:%.*]] = add nuw i8 [[N]], 127
; CHECK-NEXT: [[SMAX:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 0)
; CHECK-NEXT: [[TMP2:%.*]] = sub i8 [[TMP0]], [[SMAX]]
; CHECK-NEXT: [[TMP3:%.*]] = add nsw i8 [[N]], -2
; CHECK-NEXT: [[SMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[TMP3]], i8 0)
; CHECK-NEXT: [[SMAX2:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN]], i8 -1)
; CHECK-NEXT: [[TMP4:%.*]] = add nsw i8 [[SMAX2]], 1
; CHECK-NEXT: [[TMP5:%.*]] = mul i8 [[TMP2]], [[TMP4]]
; CHECK-NEXT: [[SMIN3:%.*]] = call i8 @llvm.smin.i8(i8 [[LIMIT]], i8 [[TMP5]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN3]], i8 0)
; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i8 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP6]], label [[LOOP_PREHEADER6:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader6:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER6]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[N]], [[IDX]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp sgt i8 [[SUB]], 2
; CHECK-NEXT: br i1 true, label [[INBOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT7:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i8 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP7]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i8 [ [[IDX_NEXT]], [[INBOUNDS]] ]
; CHECK-NEXT: [[IDX_LCSSA5:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: [[TMP8:%.*]] = icmp slt i8 [[IDX_NEXT_LCSSA]], [[LIMIT]]
; CHECK-NEXT: br i1 [[TMP8]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX_LCSSA5]], [[MAIN_EXIT_SELECTOR]] ], [ [[IDX_LCSSA1_PH]], [[EXIT_LOOPEXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds.loopexit:
; CHECK-NEXT: [[IDX_LCSSA_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP]], [[LOOP_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]]
; CHECK: out_of_bounds.loopexit7:
; CHECK-NEXT: [[IDX_LCSSA_PH8:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX_LCSSA_PH]], [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] ], [ [[IDX_LCSSA_PH8]], [[OUT_OF_BOUNDS_LOOPEXIT7]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IDX_POSTLOOP]] = phi i8 [ [[IDX_NEXT_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP]] ], [ [[IDX_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: [[SUB_POSTLOOP:%.*]] = sub i8 [[N]], [[IDX_POSTLOOP]]
; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp sgt i8 [[SUB_POSTLOOP]], 2
; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[INBOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT]]
; CHECK: inbounds.postloop:
; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw i8 [[IDX_POSTLOOP]], 1
; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i8 [[IDX_NEXT_POSTLOOP]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT_LOOPEXIT]], !llvm.loop [[LOOP10:![0-9]+]], !loop_constrainer.loop.clone !5
;
entry:
%n = load i8, ptr %p, !range !0
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %n, %idx
%check = icmp sgt i8 %sub, 2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(IV - N < -2)
; TODO: IRCE is allowed.
define i8 @test5(i8 %limit, i8 %n) {
; CHECK-LABEL: define i8 @test5
; CHECK-SAME: (i8 [[LIMIT:%.*]], i8 [[N:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[IDX]], [[N]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp slt i8 [[SUB]], -2
; CHECK-NEXT: br i1 [[CHECK]], label [[INBOUNDS]], label [[OUT_OF_BOUNDS:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
;
entry:
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %idx, %n
%check = icmp slt i8 %sub, -2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(IV - N < -2)
; N is known to be non-negative.
; TODO: IRCE is allowed.
define i8 @test5a(i8 %limit, ptr %p) {
; CHECK-LABEL: define i8 @test5a
; CHECK-SAME: (i8 [[LIMIT:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG6]]
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[IDX]], [[N]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp slt i8 [[SUB]], -2
; CHECK-NEXT: br i1 [[CHECK]], label [[INBOUNDS]], label [[OUT_OF_BOUNDS:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
;
entry:
%n = load i8, ptr %p, !range !0
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %idx, %n
%check = icmp slt i8 %sub, -2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(IV + 2 < N)
; IRCE is allowed.
define i8 @test6(i8 %limit, i8 %n) {
; CHECK-LABEL: define i8 @test6
; CHECK-SAME: (i8 [[LIMIT:%.*]], i8 [[N:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[N]], -127
; CHECK-NEXT: [[SMAX:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP0]], i8 2)
; CHECK-NEXT: [[TMP1:%.*]] = sub i8 [[N]], [[SMAX]]
; CHECK-NEXT: [[SMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[N]], i8 0)
; CHECK-NEXT: [[SMAX2:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN]], i8 -1)
; CHECK-NEXT: [[TMP2:%.*]] = add nsw i8 [[SMAX2]], 1
; CHECK-NEXT: [[TMP3:%.*]] = mul i8 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[SMIN3:%.*]] = call i8 @llvm.smin.i8(i8 [[LIMIT]], i8 [[TMP3]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN3]], i8 0)
; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i8 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP4]], label [[LOOP_PREHEADER6:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader6:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER6]] ]
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[IDX]], 2
; CHECK-NEXT: [[CHECK:%.*]] = icmp slt i8 [[ADD]], [[N]]
; CHECK-NEXT: br i1 true, label [[INBOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT7:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i8 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP5]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i8 [ [[IDX_NEXT]], [[INBOUNDS]] ]
; CHECK-NEXT: [[IDX_LCSSA5:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i8 [[IDX_NEXT_LCSSA]], [[LIMIT]]
; CHECK-NEXT: br i1 [[TMP6]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX_LCSSA5]], [[MAIN_EXIT_SELECTOR]] ], [ [[IDX_LCSSA1_PH]], [[EXIT_LOOPEXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds.loopexit:
; CHECK-NEXT: [[IDX_LCSSA_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP]], [[LOOP_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]]
; CHECK: out_of_bounds.loopexit7:
; CHECK-NEXT: [[IDX_LCSSA_PH8:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX_LCSSA_PH]], [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] ], [ [[IDX_LCSSA_PH8]], [[OUT_OF_BOUNDS_LOOPEXIT7]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IDX_POSTLOOP]] = phi i8 [ [[IDX_NEXT_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP]] ], [ [[IDX_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: [[ADD_POSTLOOP:%.*]] = add i8 [[IDX_POSTLOOP]], 2
; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp slt i8 [[ADD_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[INBOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT]]
; CHECK: inbounds.postloop:
; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw i8 [[IDX_POSTLOOP]], 1
; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i8 [[IDX_NEXT_POSTLOOP]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT_LOOPEXIT]], !llvm.loop [[LOOP11:![0-9]+]], !loop_constrainer.loop.clone !5
;
entry:
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%add = add i8 %idx, 2
%check = icmp slt i8 %add, %n
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(IV + 2 < N)
; N is known to be non-negative.
; IRCE is allowed.
define i8 @test6a(i8 %limit, ptr %p) {
; CHECK-LABEL: define i8 @test6a
; CHECK-SAME: (i8 [[LIMIT:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG6]]
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i8 [[N]], -2
; CHECK-NEXT: [[SMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[LIMIT]], i8 [[TMP0]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN]], i8 0)
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PREHEADER3:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader3:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER3]] ]
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[IDX]], 2
; CHECK-NEXT: [[CHECK:%.*]] = icmp slt i8 [[ADD]], [[N]]
; CHECK-NEXT: br i1 true, label [[INBOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT4:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i8 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i8 [ [[IDX_NEXT]], [[INBOUNDS]] ]
; CHECK-NEXT: [[IDX_LCSSA2:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i8 [[IDX_NEXT_LCSSA]], [[LIMIT]]
; CHECK-NEXT: br i1 [[TMP3]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX_LCSSA2]], [[MAIN_EXIT_SELECTOR]] ], [ [[IDX_LCSSA1_PH]], [[EXIT_LOOPEXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds.loopexit:
; CHECK-NEXT: [[IDX_LCSSA_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP]], [[LOOP_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]]
; CHECK: out_of_bounds.loopexit4:
; CHECK-NEXT: [[IDX_LCSSA_PH5:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX_LCSSA_PH]], [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] ], [ [[IDX_LCSSA_PH5]], [[OUT_OF_BOUNDS_LOOPEXIT4]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IDX_POSTLOOP]] = phi i8 [ [[IDX_NEXT_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP]] ], [ [[IDX_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: [[ADD_POSTLOOP:%.*]] = add i8 [[IDX_POSTLOOP]], 2
; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp slt i8 [[ADD_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[INBOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT]]
; CHECK: inbounds.postloop:
; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw i8 [[IDX_POSTLOOP]], 1
; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i8 [[IDX_NEXT_POSTLOOP]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT_LOOPEXIT]], !llvm.loop [[LOOP12:![0-9]+]], !loop_constrainer.loop.clone !5
;
entry:
%n = load i8, ptr %p, !range !0
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%add = add i8 %idx, 2
%check = icmp slt i8 %add, %n
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(N - IV > -2)
;
; IRCE is allowed.
; IRCE will reassociate this range check to the 'IV < N + 2',
; since N < 126 no-overflow fact is provable at compile time.
define i8 @test_overflow_check_compile_time(i8 %limit, ptr %p) {
; CHECK-LABEL: define i8 @test_overflow_check_compile_time
; CHECK-SAME: (i8 [[LIMIT:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG13:![0-9]+]]
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = add nuw nsw i8 [[N]], 2
; CHECK-NEXT: [[SMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[LIMIT]], i8 [[TMP0]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN]], i8 0)
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PREHEADER3:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader3:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER3]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[N]], [[IDX]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp sgt i8 [[SUB]], -2
; CHECK-NEXT: br i1 true, label [[INBOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT4:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i8 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i8 [ [[IDX_NEXT]], [[INBOUNDS]] ]
; CHECK-NEXT: [[IDX_LCSSA2:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i8 [[IDX_NEXT_LCSSA]], [[LIMIT]]
; CHECK-NEXT: br i1 [[TMP3]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX_LCSSA2]], [[MAIN_EXIT_SELECTOR]] ], [ [[IDX_LCSSA1_PH]], [[EXIT_LOOPEXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds.loopexit:
; CHECK-NEXT: [[IDX_LCSSA_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP]], [[LOOP_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]]
; CHECK: out_of_bounds.loopexit4:
; CHECK-NEXT: [[IDX_LCSSA_PH5:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX_LCSSA_PH]], [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] ], [ [[IDX_LCSSA_PH5]], [[OUT_OF_BOUNDS_LOOPEXIT4]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IDX_POSTLOOP]] = phi i8 [ [[IDX_NEXT_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP]] ], [ [[IDX_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: [[SUB_POSTLOOP:%.*]] = sub i8 [[N]], [[IDX_POSTLOOP]]
; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp sgt i8 [[SUB_POSTLOOP]], -2
; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[INBOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT]]
; CHECK: inbounds.postloop:
; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw i8 [[IDX_POSTLOOP]], 1
; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i8 [[IDX_NEXT_POSTLOOP]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT_LOOPEXIT]], !llvm.loop [[LOOP14:![0-9]+]], !loop_constrainer.loop.clone !5
;
entry:
%n = load i8, ptr %p, !range !1
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %n, %idx
%check = icmp sgt i8 %sub, -2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
; IV = 0; IV <s limit; IV += 1;
; Check(N - IV >= -2)
;
; IRCE is allowed.
; IRCE will reassociate this range check to the 'IV < (N + 2) + 1',
; since N < 126 no-overflow fact is NOT provable at compile time and
; runtime overflow check is required.
define i8 @test_overflow_check_runtime(i8 %limit, ptr %p) {
; CHECK-LABEL: define i8 @test_overflow_check_runtime
; CHECK-SAME: (i8 [[LIMIT:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG13]]
; CHECK-NEXT: [[PRECHECK:%.*]] = icmp sgt i8 [[LIMIT]], 0
; CHECK-NEXT: br i1 [[PRECHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[N]], 3
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i8 [[N]], -124
; CHECK-NEXT: [[SMAX:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 0)
; CHECK-NEXT: [[TMP2:%.*]] = sub i8 [[TMP0]], [[SMAX]]
; CHECK-NEXT: [[TMP3:%.*]] = add nuw i8 [[N]], 3
; CHECK-NEXT: [[SMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[TMP3]], i8 0)
; CHECK-NEXT: [[SMAX2:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN]], i8 -1)
; CHECK-NEXT: [[TMP4:%.*]] = add nsw i8 [[SMAX2]], 1
; CHECK-NEXT: [[TMP5:%.*]] = mul i8 [[TMP2]], [[TMP4]]
; CHECK-NEXT: [[TMP6:%.*]] = zext nneg i8 [[N]] to i16
; CHECK-NEXT: [[TMP7:%.*]] = sub i16 124, [[TMP6]]
; CHECK-NEXT: [[SMIN3:%.*]] = call i16 @llvm.smin.i16(i16 [[TMP7]], i16 0)
; CHECK-NEXT: [[TMP8:%.*]] = trunc i16 [[SMIN3]] to i8
; CHECK-NEXT: [[TMP9:%.*]] = add nsw i8 [[TMP8]], 1
; CHECK-NEXT: [[TMP10:%.*]] = mul i8 [[TMP5]], [[TMP9]]
; CHECK-NEXT: [[SMIN4:%.*]] = call i8 @llvm.smin.i8(i8 [[LIMIT]], i8 [[TMP10]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i8 @llvm.smax.i8(i8 [[SMIN4]], i8 0)
; CHECK-NEXT: [[TMP11:%.*]] = icmp slt i8 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP11]], label [[LOOP_PREHEADER7:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader7:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IDX:%.*]] = phi i8 [ [[IDX_NEXT:%.*]], [[INBOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER7]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[N]], [[IDX]]
; CHECK-NEXT: [[CHECK:%.*]] = icmp sge i8 [[SUB]], -2
; CHECK-NEXT: br i1 true, label [[INBOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT8:%.*]]
; CHECK: inbounds:
; CHECK-NEXT: [[IDX_NEXT]] = add nuw nsw i8 [[IDX]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[IDX_NEXT]], [[LIMIT]]
; CHECK-NEXT: [[TMP12:%.*]] = icmp slt i8 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP12]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i8 [ [[IDX_NEXT]], [[INBOUNDS]] ]
; CHECK-NEXT: [[IDX_LCSSA6:%.*]] = phi i8 [ [[IDX]], [[INBOUNDS]] ]
; CHECK-NEXT: [[TMP13:%.*]] = icmp slt i8 [[IDX_NEXT_LCSSA]], [[LIMIT]]
; CHECK-NEXT: br i1 [[TMP13]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i8 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[IDX_LCSSA1:%.*]] = phi i8 [ [[IDX_LCSSA6]], [[MAIN_EXIT_SELECTOR]] ], [ [[IDX_LCSSA1_PH]], [[EXIT_LOOPEXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IDX_LCSSA1]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: out_of_bounds.loopexit:
; CHECK-NEXT: [[IDX_LCSSA_PH:%.*]] = phi i8 [ [[IDX_POSTLOOP]], [[LOOP_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]]
; CHECK: out_of_bounds.loopexit8:
; CHECK-NEXT: [[IDX_LCSSA_PH9:%.*]] = phi i8 [ [[IDX]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUT_OF_BOUNDS]]
; CHECK: out_of_bounds:
; CHECK-NEXT: [[IDX_LCSSA:%.*]] = phi i8 [ [[IDX_LCSSA_PH]], [[OUT_OF_BOUNDS_LOOPEXIT:%.*]] ], [ [[IDX_LCSSA_PH9]], [[OUT_OF_BOUNDS_LOOPEXIT8]] ]
; CHECK-NEXT: ret i8 [[IDX_LCSSA]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IDX_POSTLOOP]] = phi i8 [ [[IDX_NEXT_POSTLOOP:%.*]], [[INBOUNDS_POSTLOOP]] ], [ [[IDX_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: [[SUB_POSTLOOP:%.*]] = sub i8 [[N]], [[IDX_POSTLOOP]]
; CHECK-NEXT: [[CHECK_POSTLOOP:%.*]] = icmp sge i8 [[SUB_POSTLOOP]], -2
; CHECK-NEXT: br i1 [[CHECK_POSTLOOP]], label [[INBOUNDS_POSTLOOP]], label [[OUT_OF_BOUNDS_LOOPEXIT]]
; CHECK: inbounds.postloop:
; CHECK-NEXT: [[IDX_NEXT_POSTLOOP]] = add nuw i8 [[IDX_POSTLOOP]], 1
; CHECK-NEXT: [[CMP_POSTLOOP:%.*]] = icmp slt i8 [[IDX_NEXT_POSTLOOP]], [[LIMIT]]
; CHECK-NEXT: br i1 [[CMP_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT_LOOPEXIT]], !llvm.loop [[LOOP15:![0-9]+]], !loop_constrainer.loop.clone !5
;
entry:
%n = load i8, ptr %p, !range !1
%precheck = icmp sgt i8 %limit, 0
br i1 %precheck, label %loop, label %exit
loop:
%idx = phi i8 [ %idx.next, %inbounds ], [ 0, %entry ]
%sub = sub i8 %n, %idx
%check = icmp sge i8 %sub, -2
br i1 %check, label %inbounds, label %out_of_bounds
inbounds:
%idx.next = add nuw i8 %idx, 1
%cmp = icmp slt i8 %idx.next, %limit
br i1 %cmp, label %loop, label %exit
exit:
%res = phi i8 [ 0, %entry ], [ %idx, %inbounds ]
ret i8 %res
out_of_bounds:
ret i8 %idx;
}
!0 = !{i8 0, i8 127}
!1 = !{i8 0, i8 126}