blob: 415ed5750dcc496563f2a772f6290b3b15701e81 [file] [log] [blame]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -verify-loop-info -irce-print-changed-loops -passes=irce -irce-allow-narrow-latch=true -S < %s 2>&1 | FileCheck %s
; RUN: opt -verify-loop-info -irce-print-changed-loops -passes='require<branch-prob>,irce' -irce-allow-narrow-latch=true -S < %s 2>&1 | FileCheck %s
; Check that we can remove trivially non-failing range check.
define i32 @test_increasing_slt_slt_wide_simple_no_postloop() {
; CHECK-LABEL: define i32 @test_increasing_slt_slt_wide_simple_no_postloop() {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp slt i64 [[IV]], 100
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[CHECK_FAILED:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp slt i32 [[NARROW_IV]], 100
; CHECK-NEXT: br i1 [[LATCH_COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
;
entry:
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc = icmp slt i64 %iv, 100
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp slt i32 %narrow.iv, 100
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; This range check fails on the last iteration, so it needs a postloop.
define i32 @test_increasing_slt_slt_wide_simple_postloop() {
; CHECK-LABEL: define i32 @test_increasing_slt_slt_wide_simple_postloop() {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 true, label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp slt i64 [[IV]], 99
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[CHECK_FAILED_LOOPEXIT2:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp slt i32 [[NARROW_IV]], 100
; CHECK-NEXT: [[WIDE_NARROW_IV:%.*]] = sext i32 [[NARROW_IV]] to i64
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i64 [[WIDE_NARROW_IV]], 99
; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i64 [ [[IV_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: [[NARROW_IV_LCSSA1:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 [[WIDE_NARROW_IV_LCSSA]], 100
; CHECK-NEXT: br i1 [[TMP1]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IV_COPY:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[WIDE_NARROW_IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[NARROW_IV_LCSSA_PH:%.*]] = phi i32 [ [[NARROW_IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV_LCSSA1]], [[MAIN_EXIT_SELECTOR]] ], [ [[NARROW_IV_LCSSA_PH]], [[EXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed.loopexit:
; CHECK-NEXT: br label [[CHECK_FAILED:%.*]]
; CHECK: check_failed.loopexit2:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i64 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ]
; CHECK-NEXT: [[RC_POSTLOOP:%.*]] = icmp slt i64 [[IV_POSTLOOP]], 99
; CHECK-NEXT: br i1 [[RC_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[CHECK_FAILED_LOOPEXIT:%.*]]
; CHECK: backedge.postloop:
; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add i64 [[IV_POSTLOOP]], 1
; CHECK-NEXT: [[NARROW_IV_POSTLOOP]] = trunc i64 [[IV_NEXT_POSTLOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_POSTLOOP:%.*]] = icmp slt i32 [[NARROW_IV_POSTLOOP]], 100
; CHECK-NEXT: br i1 [[LATCH_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP0:![0-9]+]], !irce.loop.clone !5
;
entry:
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc = icmp slt i64 %iv, 99
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp slt i32 %narrow.iv, 100
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; General case. If both %N and %M are non-negative, we do not need a preloop.
define i32 @test_increasing_slt_slt_wide_non-negative(ptr %n_ptr, ptr %m_ptr) {
; CHECK-LABEL: define i32 @test_increasing_slt_slt_wide_non-negative
; CHECK-SAME: (ptr [[N_PTR:%.*]], ptr [[M_PTR:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i32, ptr [[N_PTR]], align 4, !range [[RNG6:![0-9]+]]
; CHECK-NEXT: [[M:%.*]] = load i64, ptr [[M_PTR]], align 4, !range [[RNG7:![0-9]+]]
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i64 @llvm.smin.i64(i64 [[M]], i64 [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp slt i64 [[IV]], [[M]]
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[CHECK_FAILED_LOOPEXIT2:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp slt i32 [[NARROW_IV]], [[N]]
; CHECK-NEXT: [[WIDE_NARROW_IV:%.*]] = sext i32 [[NARROW_IV]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i64 [[WIDE_NARROW_IV]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i64 [ [[IV_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: [[NARROW_IV_LCSSA1:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_N:%.*]] = sext i32 [[N]] to i64
; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i64 [[WIDE_NARROW_IV_LCSSA]], [[WIDE_N]]
; CHECK-NEXT: br i1 [[TMP3]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IV_COPY:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[WIDE_NARROW_IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[NARROW_IV_LCSSA_PH:%.*]] = phi i32 [ [[NARROW_IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV_LCSSA1]], [[MAIN_EXIT_SELECTOR]] ], [ [[NARROW_IV_LCSSA_PH]], [[EXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed.loopexit:
; CHECK-NEXT: br label [[CHECK_FAILED:%.*]]
; CHECK: check_failed.loopexit2:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i64 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ]
; CHECK-NEXT: [[RC_POSTLOOP:%.*]] = icmp slt i64 [[IV_POSTLOOP]], [[M]]
; CHECK-NEXT: br i1 [[RC_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[CHECK_FAILED_LOOPEXIT:%.*]]
; CHECK: backedge.postloop:
; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add i64 [[IV_POSTLOOP]], 1
; CHECK-NEXT: [[NARROW_IV_POSTLOOP]] = trunc i64 [[IV_NEXT_POSTLOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_POSTLOOP:%.*]] = icmp slt i32 [[NARROW_IV_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[LATCH_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP8:![0-9]+]], !irce.loop.clone !5
;
entry:
%N = load i32, ptr %n_ptr, !range !2
%M = load i64, ptr %m_ptr, !range !1
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc = icmp slt i64 %iv, %M
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp slt i32 %narrow.iv, %N
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; General case. Even though %M may be negative, we do not need a preloop because
; we make a non-negativity runtime check against M and do not go to main loop if
; M was negative.
define i32 @test_increasing_slt_slt_wide_general(ptr %n_ptr, ptr %m_ptr) {
; CHECK-LABEL: define i32 @test_increasing_slt_slt_wide_general
; CHECK-SAME: (ptr [[N_PTR:%.*]], ptr [[M_PTR:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i32, ptr [[N_PTR]], align 4, !range [[RNG6]]
; CHECK-NEXT: [[M:%.*]] = load i64, ptr [[M_PTR]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[M]], -9223372036854775807
; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[TMP0]], i64 0)
; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[M]], [[SMAX]]
; CHECK-NEXT: [[SMIN:%.*]] = call i64 @llvm.smin.i64(i64 [[M]], i64 0)
; CHECK-NEXT: [[SMAX1:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN]], i64 -1)
; CHECK-NEXT: [[TMP2:%.*]] = add nsw i64 [[SMAX1]], 1
; CHECK-NEXT: [[TMP3:%.*]] = mul i64 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[SMIN2:%.*]] = call i64 @llvm.smin.i64(i64 [[TMP3]], i64 [[TMP4]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN2]], i64 0)
; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i64 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP5]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp slt i64 [[IV]], [[M]]
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[CHECK_FAILED_LOOPEXIT5:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp slt i32 [[NARROW_IV]], [[N]]
; CHECK-NEXT: [[WIDE_NARROW_IV:%.*]] = sext i32 [[NARROW_IV]] to i64
; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i64 [[WIDE_NARROW_IV]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP6]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i64 [ [[IV_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: [[NARROW_IV_LCSSA4:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_N:%.*]] = sext i32 [[N]] to i64
; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i64 [[WIDE_NARROW_IV_LCSSA]], [[WIDE_N]]
; CHECK-NEXT: br i1 [[TMP7]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IV_COPY:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[WIDE_NARROW_IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[NARROW_IV_LCSSA_PH:%.*]] = phi i32 [ [[NARROW_IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV_LCSSA4]], [[MAIN_EXIT_SELECTOR]] ], [ [[NARROW_IV_LCSSA_PH]], [[EXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed.loopexit:
; CHECK-NEXT: br label [[CHECK_FAILED:%.*]]
; CHECK: check_failed.loopexit5:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i64 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ]
; CHECK-NEXT: [[RC_POSTLOOP:%.*]] = icmp slt i64 [[IV_POSTLOOP]], [[M]]
; CHECK-NEXT: br i1 [[RC_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[CHECK_FAILED_LOOPEXIT:%.*]]
; CHECK: backedge.postloop:
; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add i64 [[IV_POSTLOOP]], 1
; CHECK-NEXT: [[NARROW_IV_POSTLOOP]] = trunc i64 [[IV_NEXT_POSTLOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_POSTLOOP:%.*]] = icmp slt i32 [[NARROW_IV_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[LATCH_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP9:![0-9]+]], !irce.loop.clone !5
;
entry:
%N = load i32, ptr %n_ptr, !range !2
%M = load i64, ptr %m_ptr
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc = icmp slt i64 %iv, %M
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp slt i32 %narrow.iv, %N
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; General case with preloop.
define i32 @test_increasing_slt_slt_wide_general_preloop(ptr %n_ptr, ptr %m_ptr) {
; CHECK-LABEL: define i32 @test_increasing_slt_slt_wide_general_preloop
; CHECK-SAME: (ptr [[N_PTR:%.*]], ptr [[M_PTR:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i32, ptr [[N_PTR]], align 4, !range [[RNG6]]
; CHECK-NEXT: [[M:%.*]] = load i64, ptr [[M_PTR]], align 4
; CHECK-NEXT: [[SMIN:%.*]] = call i64 @llvm.smin.i64(i64 [[M]], i64 0)
; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN]], i64 -1)
; CHECK-NEXT: [[EXIT_PRELOOP_AT:%.*]] = sub i64 -1, [[SMAX]]
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[M]], -9223372036854775807
; CHECK-NEXT: [[SMAX1:%.*]] = call i64 @llvm.smax.i64(i64 [[TMP0]], i64 1)
; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[M]], [[SMAX1]]
; CHECK-NEXT: [[TMP2:%.*]] = add nsw i64 [[SMAX]], 1
; CHECK-NEXT: [[TMP3:%.*]] = mul i64 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[SMIN2:%.*]] = call i64 @llvm.smin.i64(i64 [[TMP3]], i64 [[TMP4]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN2]], i64 -1)
; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i64 -1, [[EXIT_PRELOOP_AT]]
; CHECK-NEXT: br i1 [[TMP5]], label [[LOOP_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]]
; CHECK: loop.preloop.preheader:
; CHECK-NEXT: br label [[LOOP_PRELOOP:%.*]]
; CHECK: mainloop:
; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i64 [[INDVAR_END:%.*]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP6]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[IV_PRELOOP_COPY:%.*]], [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp slt i64 [[IV]], [[M]]
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[CHECK_FAILED_LOOPEXIT8:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp slt i32 [[NARROW_IV]], [[N]]
; CHECK-NEXT: [[WIDE_NARROW_IV:%.*]] = sext i32 [[NARROW_IV]] to i64
; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i64 [[WIDE_NARROW_IV]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP7]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i64 [ [[IV_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: [[NARROW_IV_LCSSA7:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_N4:%.*]] = sext i32 [[N]] to i64
; CHECK-NEXT: [[TMP8:%.*]] = icmp slt i64 [[WIDE_NARROW_IV_LCSSA]], [[WIDE_N4]]
; CHECK-NEXT: br i1 [[TMP8]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IV_COPY:%.*]] = phi i64 [ [[IV_PRELOOP_COPY]], [[MAINLOOP:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END5:%.*]] = phi i64 [ [[INDVAR_END]], [[MAINLOOP]] ], [ [[WIDE_NARROW_IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[NARROW_IV_LCSSA_PH:%.*]] = phi i32 [ [[NARROW_IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV_LCSSA7]], [[MAIN_EXIT_SELECTOR]] ], [ [[NARROW_IV_PRELOOP_LCSSA:%.*]], [[PRELOOP_EXIT_SELECTOR:%.*]] ], [ [[NARROW_IV_LCSSA_PH]], [[EXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed.loopexit:
; CHECK-NEXT: br label [[CHECK_FAILED:%.*]]
; CHECK: check_failed.loopexit6:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed.loopexit8:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
; CHECK: loop.preloop:
; CHECK-NEXT: [[IV_PRELOOP:%.*]] = phi i64 [ [[IV_NEXT_PRELOOP:%.*]], [[BACKEDGE_PRELOOP:%.*]] ], [ 0, [[LOOP_PRELOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC_PRELOOP:%.*]] = icmp slt i64 [[IV_PRELOOP]], [[M]]
; CHECK-NEXT: br i1 [[RC_PRELOOP]], label [[BACKEDGE_PRELOOP]], label [[CHECK_FAILED_LOOPEXIT:%.*]]
; CHECK: backedge.preloop:
; CHECK-NEXT: [[IV_NEXT_PRELOOP]] = add i64 [[IV_PRELOOP]], 1
; CHECK-NEXT: [[NARROW_IV_PRELOOP:%.*]] = trunc i64 [[IV_PRELOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_PRELOOP:%.*]] = icmp slt i32 [[NARROW_IV_PRELOOP]], [[N]]
; CHECK-NEXT: [[WIDE_NARROW_IV_PRELOOP:%.*]] = sext i32 [[NARROW_IV_PRELOOP]] to i64
; CHECK-NEXT: [[TMP9:%.*]] = icmp slt i64 [[WIDE_NARROW_IV_PRELOOP]], [[EXIT_PRELOOP_AT]]
; CHECK-NEXT: br i1 [[TMP9]], label [[LOOP_PRELOOP]], label [[PRELOOP_EXIT_SELECTOR]], !llvm.loop [[LOOP10:![0-9]+]], !irce.loop.clone !5
; CHECK: preloop.exit.selector:
; CHECK-NEXT: [[IV_NEXT_PRELOOP_LCSSA:%.*]] = phi i64 [ [[IV_NEXT_PRELOOP]], [[BACKEDGE_PRELOOP]] ]
; CHECK-NEXT: [[NARROW_IV_PRELOOP_LCSSA]] = phi i32 [ [[NARROW_IV_PRELOOP]], [[BACKEDGE_PRELOOP]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_PRELOOP_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV_PRELOOP]], [[BACKEDGE_PRELOOP]] ]
; CHECK-NEXT: [[WIDE_N:%.*]] = sext i32 [[N]] to i64
; CHECK-NEXT: [[TMP10:%.*]] = icmp slt i64 [[WIDE_NARROW_IV_PRELOOP_LCSSA]], [[WIDE_N]]
; CHECK-NEXT: br i1 [[TMP10]], label [[PRELOOP_PSEUDO_EXIT]], label [[EXIT]]
; CHECK: preloop.pseudo.exit:
; CHECK-NEXT: [[IV_PRELOOP_COPY]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END]] = phi i64 [ -1, [[ENTRY]] ], [ [[WIDE_NARROW_IV_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[MAINLOOP]]
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i64 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ]
; CHECK-NEXT: [[RC_POSTLOOP:%.*]] = icmp slt i64 [[IV_POSTLOOP]], [[M]]
; CHECK-NEXT: br i1 [[RC_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[CHECK_FAILED_LOOPEXIT6:%.*]]
; CHECK: backedge.postloop:
; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add i64 [[IV_POSTLOOP]], 1
; CHECK-NEXT: [[NARROW_IV_POSTLOOP]] = trunc i64 [[IV_POSTLOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_POSTLOOP:%.*]] = icmp slt i32 [[NARROW_IV_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[LATCH_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP11:![0-9]+]], !irce.loop.clone !5
;
entry:
%N = load i32, ptr %n_ptr, !range !2
%M = load i64, ptr %m_ptr
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc = icmp slt i64 %iv, %M
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv to i32
%latch.cond = icmp slt i32 %narrow.iv, %N
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; Same as above, multiple checks.
define i32 @test_increasing_slt_slt_wide_multiple_checks(ptr %n_ptr, ptr %m1_ptr, ptr %m2_ptr, ptr %m3_ptr, ptr %m4_ptr) {
; CHECK-LABEL: define i32 @test_increasing_slt_slt_wide_multiple_checks
; CHECK-SAME: (ptr [[N_PTR:%.*]], ptr [[M1_PTR:%.*]], ptr [[M2_PTR:%.*]], ptr [[M3_PTR:%.*]], ptr [[M4_PTR:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i32, ptr [[N_PTR]], align 4, !range [[RNG6]]
; CHECK-NEXT: [[M1:%.*]] = load i64, ptr [[M1_PTR]], align 4
; CHECK-NEXT: [[M2:%.*]] = load i64, ptr [[M2_PTR]], align 4
; CHECK-NEXT: [[M3:%.*]] = load i64, ptr [[M3_PTR]], align 4
; CHECK-NEXT: [[M4:%.*]] = load i64, ptr [[M4_PTR]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[M2]], -9223372036854775807
; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[TMP0]], i64 0)
; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[M2]], [[SMAX]]
; CHECK-NEXT: [[SMIN:%.*]] = call i64 @llvm.smin.i64(i64 [[M2]], i64 0)
; CHECK-NEXT: [[SMAX1:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN]], i64 -1)
; CHECK-NEXT: [[TMP2:%.*]] = add nsw i64 [[SMAX1]], 1
; CHECK-NEXT: [[TMP3:%.*]] = mul i64 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = add i64 [[M1]], -9223372036854775807
; CHECK-NEXT: [[SMAX2:%.*]] = call i64 @llvm.smax.i64(i64 [[TMP4]], i64 0)
; CHECK-NEXT: [[TMP5:%.*]] = sub i64 [[M1]], [[SMAX2]]
; CHECK-NEXT: [[SMIN3:%.*]] = call i64 @llvm.smin.i64(i64 [[M1]], i64 0)
; CHECK-NEXT: [[SMAX4:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN3]], i64 -1)
; CHECK-NEXT: [[TMP6:%.*]] = add nsw i64 [[SMAX4]], 1
; CHECK-NEXT: [[TMP7:%.*]] = mul i64 [[TMP5]], [[TMP6]]
; CHECK-NEXT: [[SMIN5:%.*]] = call i64 @llvm.smin.i64(i64 [[TMP3]], i64 [[TMP7]])
; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[M3]], -9223372036854775807
; CHECK-NEXT: [[SMAX6:%.*]] = call i64 @llvm.smax.i64(i64 [[TMP8]], i64 0)
; CHECK-NEXT: [[TMP9:%.*]] = sub i64 [[M3]], [[SMAX6]]
; CHECK-NEXT: [[SMIN7:%.*]] = call i64 @llvm.smin.i64(i64 [[M3]], i64 0)
; CHECK-NEXT: [[SMAX8:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN7]], i64 -1)
; CHECK-NEXT: [[TMP10:%.*]] = add nsw i64 [[SMAX8]], 1
; CHECK-NEXT: [[TMP11:%.*]] = mul i64 [[TMP9]], [[TMP10]]
; CHECK-NEXT: [[SMIN9:%.*]] = call i64 @llvm.smin.i64(i64 [[SMIN5]], i64 [[TMP11]])
; CHECK-NEXT: [[TMP12:%.*]] = add i64 [[M4]], -9223372036854775807
; CHECK-NEXT: [[SMAX10:%.*]] = call i64 @llvm.smax.i64(i64 [[TMP12]], i64 0)
; CHECK-NEXT: [[TMP13:%.*]] = sub i64 [[M4]], [[SMAX10]]
; CHECK-NEXT: [[SMIN11:%.*]] = call i64 @llvm.smin.i64(i64 [[M4]], i64 0)
; CHECK-NEXT: [[SMAX12:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN11]], i64 -1)
; CHECK-NEXT: [[TMP14:%.*]] = add nsw i64 [[SMAX12]], 1
; CHECK-NEXT: [[TMP15:%.*]] = mul i64 [[TMP13]], [[TMP14]]
; CHECK-NEXT: [[SMIN13:%.*]] = call i64 @llvm.smin.i64(i64 [[SMIN9]], i64 [[TMP15]])
; CHECK-NEXT: [[TMP16:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[SMIN14:%.*]] = call i64 @llvm.smin.i64(i64 [[SMIN13]], i64 [[TMP16]])
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN14]], i64 0)
; CHECK-NEXT: [[TMP17:%.*]] = icmp slt i64 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP17]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC1:%.*]] = icmp slt i64 [[IV]], [[M1]]
; CHECK-NEXT: [[RC2:%.*]] = icmp slt i64 [[IV]], [[M2]]
; CHECK-NEXT: [[RC3:%.*]] = icmp slt i64 [[IV]], [[M3]]
; CHECK-NEXT: [[RC4:%.*]] = icmp slt i64 [[IV]], [[M4]]
; CHECK-NEXT: [[C1:%.*]] = and i1 true, true
; CHECK-NEXT: [[C2:%.*]] = and i1 [[C1]], true
; CHECK-NEXT: [[RC:%.*]] = and i1 [[C2]], true
; CHECK-NEXT: br i1 [[RC]], label [[BACKEDGE]], label [[CHECK_FAILED_LOOPEXIT17:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp slt i32 [[NARROW_IV]], [[N]]
; CHECK-NEXT: [[WIDE_NARROW_IV:%.*]] = sext i32 [[NARROW_IV]] to i64
; CHECK-NEXT: [[TMP18:%.*]] = icmp slt i64 [[WIDE_NARROW_IV]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP18]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i64 [ [[IV_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: [[NARROW_IV_LCSSA16:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_N:%.*]] = sext i32 [[N]] to i64
; CHECK-NEXT: [[TMP19:%.*]] = icmp slt i64 [[WIDE_NARROW_IV_LCSSA]], [[WIDE_N]]
; CHECK-NEXT: br i1 [[TMP19]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IV_COPY:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[WIDE_NARROW_IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[NARROW_IV_LCSSA_PH:%.*]] = phi i32 [ [[NARROW_IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV_LCSSA16]], [[MAIN_EXIT_SELECTOR]] ], [ [[NARROW_IV_LCSSA_PH]], [[EXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed.loopexit:
; CHECK-NEXT: br label [[CHECK_FAILED:%.*]]
; CHECK: check_failed.loopexit17:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i64 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ]
; CHECK-NEXT: [[RC1_POSTLOOP:%.*]] = icmp slt i64 [[IV_POSTLOOP]], [[M1]]
; CHECK-NEXT: [[RC2_POSTLOOP:%.*]] = icmp slt i64 [[IV_POSTLOOP]], [[M2]]
; CHECK-NEXT: [[RC3_POSTLOOP:%.*]] = icmp slt i64 [[IV_POSTLOOP]], [[M3]]
; CHECK-NEXT: [[RC4_POSTLOOP:%.*]] = icmp slt i64 [[IV_POSTLOOP]], [[M4]]
; CHECK-NEXT: [[C1_POSTLOOP:%.*]] = and i1 [[RC1_POSTLOOP]], [[RC2_POSTLOOP]]
; CHECK-NEXT: [[C2_POSTLOOP:%.*]] = and i1 [[C1_POSTLOOP]], [[RC3_POSTLOOP]]
; CHECK-NEXT: [[RC_POSTLOOP:%.*]] = and i1 [[C2_POSTLOOP]], [[RC4_POSTLOOP]]
; CHECK-NEXT: br i1 [[RC_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[CHECK_FAILED_LOOPEXIT:%.*]]
; CHECK: backedge.postloop:
; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add i64 [[IV_POSTLOOP]], 1
; CHECK-NEXT: [[NARROW_IV_POSTLOOP]] = trunc i64 [[IV_NEXT_POSTLOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_POSTLOOP:%.*]] = icmp slt i32 [[NARROW_IV_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[LATCH_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP12:![0-9]+]], !irce.loop.clone !5
;
entry:
%N = load i32, ptr %n_ptr, !range !2
%M1 = load i64, ptr %m1_ptr
%M2 = load i64, ptr %m2_ptr
%M3 = load i64, ptr %m3_ptr
%M4 = load i64, ptr %m4_ptr
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc1 = icmp slt i64 %iv, %M1
%rc2 = icmp slt i64 %iv, %M2
%rc3 = icmp slt i64 %iv, %M3
%rc4 = icmp slt i64 %iv, %M4
%c1 = and i1 %rc1, %rc2
%c2 = and i1 %c1, %rc3
%rc = and i1 %c2, %rc4
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp slt i32 %narrow.iv, %N
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; Wide IV against narrow range check. We don't currently support it.
define i32 @test_increasing_slt_slt_wide_simple_negtest_narrow_rc() {
; CHECK-LABEL: define i32 @test_increasing_slt_slt_wide_simple_negtest_narrow_rc() {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32
; CHECK-NEXT: [[RC:%.*]] = icmp slt i32 [[NARROW_IV]], 101
; CHECK-NEXT: br i1 [[RC]], label [[BACKEDGE]], label [[CHECK_FAILED:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp slt i64 [[IV]], 100
; CHECK-NEXT: br i1 [[LATCH_COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA1:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA1]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
;
entry:
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%narrow.iv = trunc i64 %iv to i32
%rc = icmp slt i32 %narrow.iv, 101
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%latch.cond = icmp slt i64 %iv, 100
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; Check that we can remove trivially non-failing range check.
define i32 @test_increasing_ult_ult_wide_simple_no_postloop() {
; CHECK-LABEL: define i32 @test_increasing_ult_ult_wide_simple_no_postloop() {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp ult i64 [[IV]], 100
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[CHECK_FAILED:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp ult i32 [[NARROW_IV]], 100
; CHECK-NEXT: br i1 [[LATCH_COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
;
entry:
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc = icmp ult i64 %iv, 100
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp ult i32 %narrow.iv, 100
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; This range check fails on the last iteration, so it needs a postloop.
define i32 @test_increasing_ult_ult_wide_simple_postloop() {
; CHECK-LABEL: define i32 @test_increasing_ult_ult_wide_simple_postloop() {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 true, label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp ult i64 [[IV]], 99
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[CHECK_FAILED_LOOPEXIT2:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp ult i32 [[NARROW_IV]], 100
; CHECK-NEXT: [[WIDE_NARROW_IV:%.*]] = zext i32 [[NARROW_IV]] to i64
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i64 [[WIDE_NARROW_IV]], 99
; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i64 [ [[IV_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: [[NARROW_IV_LCSSA1:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[WIDE_NARROW_IV_LCSSA]], 100
; CHECK-NEXT: br i1 [[TMP1]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IV_COPY:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[WIDE_NARROW_IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[NARROW_IV_LCSSA_PH:%.*]] = phi i32 [ [[NARROW_IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV_LCSSA1]], [[MAIN_EXIT_SELECTOR]] ], [ [[NARROW_IV_LCSSA_PH]], [[EXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed.loopexit:
; CHECK-NEXT: br label [[CHECK_FAILED:%.*]]
; CHECK: check_failed.loopexit2:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i64 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ]
; CHECK-NEXT: [[RC_POSTLOOP:%.*]] = icmp ult i64 [[IV_POSTLOOP]], 99
; CHECK-NEXT: br i1 [[RC_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[CHECK_FAILED_LOOPEXIT:%.*]]
; CHECK: backedge.postloop:
; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add i64 [[IV_POSTLOOP]], 1
; CHECK-NEXT: [[NARROW_IV_POSTLOOP]] = trunc i64 [[IV_NEXT_POSTLOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_POSTLOOP:%.*]] = icmp ult i32 [[NARROW_IV_POSTLOOP]], 100
; CHECK-NEXT: br i1 [[LATCH_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP13:![0-9]+]], !irce.loop.clone !5
;
entry:
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc = icmp ult i64 %iv, 99
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp ult i32 %narrow.iv, 100
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; General case. If both %N and %M are non-negative, we do not need a preloop.
define i32 @test_increasing_ult_ult_wide_non-negative(ptr %n_ptr, ptr %m_ptr) {
; CHECK-LABEL: define i32 @test_increasing_ult_ult_wide_non-negative
; CHECK-SAME: (ptr [[N_PTR:%.*]], ptr [[M_PTR:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i32, ptr [[N_PTR]], align 4, !range [[RNG6]]
; CHECK-NEXT: [[M:%.*]] = load i64, ptr [[M_PTR]], align 4, !range [[RNG7]]
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i64 @llvm.umin.i64(i64 [[M]], i64 [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP1]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp ult i64 [[IV]], [[M]]
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[CHECK_FAILED_LOOPEXIT2:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp ult i32 [[NARROW_IV]], [[N]]
; CHECK-NEXT: [[WIDE_NARROW_IV:%.*]] = zext i32 [[NARROW_IV]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i64 [[WIDE_NARROW_IV]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i64 [ [[IV_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: [[NARROW_IV_LCSSA1:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_N:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i64 [[WIDE_NARROW_IV_LCSSA]], [[WIDE_N]]
; CHECK-NEXT: br i1 [[TMP3]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IV_COPY:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[WIDE_NARROW_IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[NARROW_IV_LCSSA_PH:%.*]] = phi i32 [ [[NARROW_IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV_LCSSA1]], [[MAIN_EXIT_SELECTOR]] ], [ [[NARROW_IV_LCSSA_PH]], [[EXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed.loopexit:
; CHECK-NEXT: br label [[CHECK_FAILED:%.*]]
; CHECK: check_failed.loopexit2:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i64 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ]
; CHECK-NEXT: [[RC_POSTLOOP:%.*]] = icmp ult i64 [[IV_POSTLOOP]], [[M]]
; CHECK-NEXT: br i1 [[RC_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[CHECK_FAILED_LOOPEXIT:%.*]]
; CHECK: backedge.postloop:
; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add i64 [[IV_POSTLOOP]], 1
; CHECK-NEXT: [[NARROW_IV_POSTLOOP]] = trunc i64 [[IV_NEXT_POSTLOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_POSTLOOP:%.*]] = icmp ult i32 [[NARROW_IV_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[LATCH_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP14:![0-9]+]], !irce.loop.clone !5
;
entry:
%N = load i32, ptr %n_ptr, !range !2
%M = load i64, ptr %m_ptr, !range !1
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc = icmp ult i64 %iv, %M
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp ult i32 %narrow.iv, %N
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; General case. Even though %M may be negative, we do not need a preloop because
; we make a non-negativity runtime check against M and do not go to main loop if
; M was negative.
define i32 @test_increasing_ult_ult_wide_general(ptr %n_ptr, ptr %m_ptr) {
; CHECK-LABEL: define i32 @test_increasing_ult_ult_wide_general
; CHECK-SAME: (ptr [[N_PTR:%.*]], ptr [[M_PTR:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i32, ptr [[N_PTR]], align 4, !range [[RNG6]]
; CHECK-NEXT: [[M:%.*]] = load i64, ptr [[M_PTR]], align 4
; CHECK-NEXT: [[SMIN:%.*]] = call i64 @llvm.smin.i64(i64 [[M]], i64 0)
; CHECK-NEXT: [[TMP0:%.*]] = sub i64 [[M]], [[SMIN]]
; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN]], i64 -1)
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[SMAX]], 1
; CHECK-NEXT: [[TMP2:%.*]] = mul i64 [[TMP0]], [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP2]], i64 [[TMP3]])
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i64 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP4]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp ult i64 [[IV]], [[M]]
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[CHECK_FAILED_LOOPEXIT2:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp ult i32 [[NARROW_IV]], [[N]]
; CHECK-NEXT: [[WIDE_NARROW_IV:%.*]] = zext i32 [[NARROW_IV]] to i64
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i64 [[WIDE_NARROW_IV]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP5]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i64 [ [[IV_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: [[NARROW_IV_LCSSA1:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_N:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[TMP6:%.*]] = icmp ult i64 [[WIDE_NARROW_IV_LCSSA]], [[WIDE_N]]
; CHECK-NEXT: br i1 [[TMP6]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IV_COPY:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[WIDE_NARROW_IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[NARROW_IV_LCSSA_PH:%.*]] = phi i32 [ [[NARROW_IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV_LCSSA1]], [[MAIN_EXIT_SELECTOR]] ], [ [[NARROW_IV_LCSSA_PH]], [[EXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed.loopexit:
; CHECK-NEXT: br label [[CHECK_FAILED:%.*]]
; CHECK: check_failed.loopexit2:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i64 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ]
; CHECK-NEXT: [[RC_POSTLOOP:%.*]] = icmp ult i64 [[IV_POSTLOOP]], [[M]]
; CHECK-NEXT: br i1 [[RC_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[CHECK_FAILED_LOOPEXIT:%.*]]
; CHECK: backedge.postloop:
; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add i64 [[IV_POSTLOOP]], 1
; CHECK-NEXT: [[NARROW_IV_POSTLOOP]] = trunc i64 [[IV_NEXT_POSTLOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_POSTLOOP:%.*]] = icmp ult i32 [[NARROW_IV_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[LATCH_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP15:![0-9]+]], !irce.loop.clone !5
;
entry:
%N = load i32, ptr %n_ptr, !range !2
%M = load i64, ptr %m_ptr
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc = icmp ult i64 %iv, %M
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp ult i32 %narrow.iv, %N
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; Same as above, multiple checks.
define i32 @test_increasing_ult_ult_wide_multiple_checks(ptr %n_ptr, ptr %m1_ptr, ptr %m2_ptr, ptr %m3_ptr, ptr %m4_ptr) {
; CHECK-LABEL: define i32 @test_increasing_ult_ult_wide_multiple_checks
; CHECK-SAME: (ptr [[N_PTR:%.*]], ptr [[M1_PTR:%.*]], ptr [[M2_PTR:%.*]], ptr [[M3_PTR:%.*]], ptr [[M4_PTR:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N:%.*]] = load i32, ptr [[N_PTR]], align 4, !range [[RNG6]]
; CHECK-NEXT: [[M1:%.*]] = load i64, ptr [[M1_PTR]], align 4
; CHECK-NEXT: [[M2:%.*]] = load i64, ptr [[M2_PTR]], align 4
; CHECK-NEXT: [[M3:%.*]] = load i64, ptr [[M3_PTR]], align 4
; CHECK-NEXT: [[M4:%.*]] = load i64, ptr [[M4_PTR]], align 4
; CHECK-NEXT: [[SMIN:%.*]] = call i64 @llvm.smin.i64(i64 [[M2]], i64 0)
; CHECK-NEXT: [[TMP0:%.*]] = sub i64 [[M2]], [[SMIN]]
; CHECK-NEXT: [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN]], i64 -1)
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[SMAX]], 1
; CHECK-NEXT: [[TMP2:%.*]] = mul i64 [[TMP0]], [[TMP1]]
; CHECK-NEXT: [[SMIN1:%.*]] = call i64 @llvm.smin.i64(i64 [[M1]], i64 0)
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 [[M1]], [[SMIN1]]
; CHECK-NEXT: [[SMAX2:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN1]], i64 -1)
; CHECK-NEXT: [[TMP4:%.*]] = add nsw i64 [[SMAX2]], 1
; CHECK-NEXT: [[TMP5:%.*]] = mul i64 [[TMP3]], [[TMP4]]
; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP2]], i64 [[TMP5]])
; CHECK-NEXT: [[SMIN3:%.*]] = call i64 @llvm.smin.i64(i64 [[M3]], i64 0)
; CHECK-NEXT: [[TMP6:%.*]] = sub i64 [[M3]], [[SMIN3]]
; CHECK-NEXT: [[SMAX4:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN3]], i64 -1)
; CHECK-NEXT: [[TMP7:%.*]] = add nsw i64 [[SMAX4]], 1
; CHECK-NEXT: [[TMP8:%.*]] = mul i64 [[TMP6]], [[TMP7]]
; CHECK-NEXT: [[UMIN5:%.*]] = call i64 @llvm.umin.i64(i64 [[UMIN]], i64 [[TMP8]])
; CHECK-NEXT: [[SMIN6:%.*]] = call i64 @llvm.smin.i64(i64 [[M4]], i64 0)
; CHECK-NEXT: [[TMP9:%.*]] = sub i64 [[M4]], [[SMIN6]]
; CHECK-NEXT: [[SMAX7:%.*]] = call i64 @llvm.smax.i64(i64 [[SMIN6]], i64 -1)
; CHECK-NEXT: [[TMP10:%.*]] = add nsw i64 [[SMAX7]], 1
; CHECK-NEXT: [[TMP11:%.*]] = mul i64 [[TMP9]], [[TMP10]]
; CHECK-NEXT: [[UMIN8:%.*]] = call i64 @llvm.umin.i64(i64 [[UMIN5]], i64 [[TMP11]])
; CHECK-NEXT: [[TMP12:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i64 @llvm.umin.i64(i64 [[UMIN8]], i64 [[TMP12]])
; CHECK-NEXT: [[TMP13:%.*]] = icmp ult i64 0, [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP13]], label [[LOOP_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[RC1:%.*]] = icmp ult i64 [[IV]], [[M1]]
; CHECK-NEXT: [[RC2:%.*]] = icmp ult i64 [[IV]], [[M2]]
; CHECK-NEXT: [[RC3:%.*]] = icmp ult i64 [[IV]], [[M3]]
; CHECK-NEXT: [[RC4:%.*]] = icmp ult i64 [[IV]], [[M4]]
; CHECK-NEXT: [[C1:%.*]] = and i1 true, true
; CHECK-NEXT: [[C2:%.*]] = and i1 [[C1]], true
; CHECK-NEXT: [[RC:%.*]] = and i1 [[C2]], true
; CHECK-NEXT: br i1 [[RC]], label [[BACKEDGE]], label [[CHECK_FAILED_LOOPEXIT11:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp ult i32 [[NARROW_IV]], [[N]]
; CHECK-NEXT: [[WIDE_NARROW_IV:%.*]] = zext i32 [[NARROW_IV]] to i64
; CHECK-NEXT: [[TMP14:%.*]] = icmp ult i64 [[WIDE_NARROW_IV]], [[EXIT_MAINLOOP_AT]]
; CHECK-NEXT: br i1 [[TMP14]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i64 [ [[IV_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: [[NARROW_IV_LCSSA10:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_NARROW_IV_LCSSA:%.*]] = phi i64 [ [[WIDE_NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: [[WIDE_N:%.*]] = zext i32 [[N]] to i64
; CHECK-NEXT: [[TMP15:%.*]] = icmp ult i64 [[WIDE_NARROW_IV_LCSSA]], [[WIDE_N]]
; CHECK-NEXT: br i1 [[TMP15]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[IV_COPY:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[WIDE_NARROW_IV_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[NARROW_IV_LCSSA_PH:%.*]] = phi i32 [ [[NARROW_IV_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP:%.*]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i32 [ [[NARROW_IV_LCSSA10]], [[MAIN_EXIT_SELECTOR]] ], [ [[NARROW_IV_LCSSA_PH]], [[EXIT_LOOPEXIT:%.*]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA]]
; CHECK: check_failed.loopexit:
; CHECK-NEXT: br label [[CHECK_FAILED:%.*]]
; CHECK: check_failed.loopexit11:
; CHECK-NEXT: br label [[CHECK_FAILED]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
; CHECK: postloop:
; CHECK-NEXT: br label [[LOOP_POSTLOOP:%.*]]
; CHECK: loop.postloop:
; CHECK-NEXT: [[IV_POSTLOOP:%.*]] = phi i64 [ [[IV_COPY]], [[POSTLOOP]] ], [ [[IV_NEXT_POSTLOOP:%.*]], [[BACKEDGE_POSTLOOP]] ]
; CHECK-NEXT: [[RC1_POSTLOOP:%.*]] = icmp ult i64 [[IV_POSTLOOP]], [[M1]]
; CHECK-NEXT: [[RC2_POSTLOOP:%.*]] = icmp ult i64 [[IV_POSTLOOP]], [[M2]]
; CHECK-NEXT: [[RC3_POSTLOOP:%.*]] = icmp ult i64 [[IV_POSTLOOP]], [[M3]]
; CHECK-NEXT: [[RC4_POSTLOOP:%.*]] = icmp ult i64 [[IV_POSTLOOP]], [[M4]]
; CHECK-NEXT: [[C1_POSTLOOP:%.*]] = and i1 [[RC1_POSTLOOP]], [[RC2_POSTLOOP]]
; CHECK-NEXT: [[C2_POSTLOOP:%.*]] = and i1 [[C1_POSTLOOP]], [[RC3_POSTLOOP]]
; CHECK-NEXT: [[RC_POSTLOOP:%.*]] = and i1 [[C2_POSTLOOP]], [[RC4_POSTLOOP]]
; CHECK-NEXT: br i1 [[RC_POSTLOOP]], label [[BACKEDGE_POSTLOOP]], label [[CHECK_FAILED_LOOPEXIT:%.*]]
; CHECK: backedge.postloop:
; CHECK-NEXT: [[IV_NEXT_POSTLOOP]] = add i64 [[IV_POSTLOOP]], 1
; CHECK-NEXT: [[NARROW_IV_POSTLOOP]] = trunc i64 [[IV_NEXT_POSTLOOP]] to i32
; CHECK-NEXT: [[LATCH_COND_POSTLOOP:%.*]] = icmp ult i32 [[NARROW_IV_POSTLOOP]], [[N]]
; CHECK-NEXT: br i1 [[LATCH_COND_POSTLOOP]], label [[LOOP_POSTLOOP]], label [[EXIT_LOOPEXIT]], !llvm.loop [[LOOP16:![0-9]+]], !irce.loop.clone !5
;
entry:
%N = load i32, ptr %n_ptr, !range !2
%M1 = load i64, ptr %m1_ptr
%M2 = load i64, ptr %m2_ptr
%M3 = load i64, ptr %m3_ptr
%M4 = load i64, ptr %m4_ptr
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%rc1 = icmp ult i64 %iv, %M1
%rc2 = icmp ult i64 %iv, %M2
%rc3 = icmp ult i64 %iv, %M3
%rc4 = icmp ult i64 %iv, %M4
%c1 = and i1 %rc1, %rc2
%c2 = and i1 %c1, %rc3
%rc = and i1 %c2, %rc4
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%narrow.iv = trunc i64 %iv.next to i32
%latch.cond = icmp ult i32 %narrow.iv, %N
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; Wide IV against narrow range check. We don't currently support it.
define i32 @test_increasing_ult_ult_wide_simple_negtest_narrow_rc() {
; CHECK-LABEL: define i32 @test_increasing_ult_ult_wide_simple_negtest_narrow_rc() {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32
; CHECK-NEXT: [[RC:%.*]] = icmp ult i32 [[NARROW_IV]], 101
; CHECK-NEXT: br i1 [[RC]], label [[BACKEDGE]], label [[CHECK_FAILED:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp ult i64 [[IV]], 100
; CHECK-NEXT: br i1 [[LATCH_COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA1:%.*]] = phi i32 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[NARROW_IV_LCSSA1]]
; CHECK: check_failed:
; CHECK-NEXT: ret i32 -1
;
entry:
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
%narrow.iv = trunc i64 %iv to i32
%rc = icmp ult i32 %narrow.iv, 101
br i1 %rc, label %backedge, label %check_failed
backedge:
%iv.next = add i64 %iv, 1
%latch.cond = icmp ult i64 %iv, 100
br i1 %latch.cond, label %loop, label %exit
exit:
ret i32 %narrow.iv
check_failed:
ret i32 -1
}
; Check that fake wide exit doesn't inhibit the transform.
define i16 @test_fake_wide_exit(i64 %x) {
; CHECK-LABEL: define i16 @test_fake_wide_exit
; CHECK-SAME: (i64 [[X:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[IV_WIDE:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[IV_WIDE_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[RC:%.*]] = icmp slt i32 [[IV]], 100
; CHECK-NEXT: br i1 true, label [[CHECKED:%.*]], label [[CHECK_FAILED:%.*]]
; CHECK: checked:
; CHECK-NEXT: [[RC_WIDE:%.*]] = icmp ult i64 [[IV_WIDE]], [[X]]
; CHECK-NEXT: br i1 [[RC_WIDE]], label [[BACKEDGE]], label [[CHECK_FAILED]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[IV_WIDE_NEXT]] = add i64 [[IV_WIDE]], 1
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i32 [[IV_NEXT]] to i16
; CHECK-NEXT: [[LATCH_COND:%.*]] = icmp slt i16 [[NARROW_IV]], 100
; CHECK-NEXT: br i1 [[LATCH_COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[NARROW_IV_LCSSA:%.*]] = phi i16 [ [[NARROW_IV]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i16 [[NARROW_IV_LCSSA]]
; CHECK: check_failed:
; CHECK-NEXT: ret i16 -1
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
%iv.wide = phi i64 [ 0, %entry ], [ %iv.wide.next, %backedge ]
%rc = icmp slt i32 %iv, 100
br i1 %rc, label %checked, label %check_failed
checked:
%rc.wide = icmp ult i64 %iv.wide, %x
br i1 %rc.wide, label %backedge, label %check_failed
backedge:
%iv.next = add i32 %iv, 1
%iv.wide.next = add i64 %iv.wide, 1
%narrow.iv = trunc i32 %iv.next to i16
%latch.cond = icmp slt i16 %narrow.iv, 100
br i1 %latch.cond, label %loop, label %exit
exit:
ret i16 %narrow.iv
check_failed:
ret i16 -1
}
!0 = !{i32 0, i32 2147483647}
!1 = !{i64 0, i64 9223372036854775807}
!2 = !{i32 1, i32 2147483647}