; 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
,%inbounds ; 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)) ; 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
,%inbounds ; 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)) ; 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
,%inbounds ; 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)) ; CHECK-NEXT: CheckUse: br i1 %check, label %inbounds, label %out_of_bounds Operand: 0 ; IV = 0; 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 = 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 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 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 -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 = -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}