460 lines
12 KiB
LLVM
460 lines
12 KiB
LLVM
|
; RUN: opt -verify-loop-info -irce-print-changed-loops -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: @test_increasing_slt_slt_wide_simple_no_postloop(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK-NOT: postloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: br i1 true, label %backedge, label %check_failed
|
||
|
|
||
|
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: @test_increasing_slt_slt_wide_simple_postloop(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: br i1 true, label %backedge, label %check_failed
|
||
|
; CHECK: backedge
|
||
|
; CHECK: [[COND:%[^ ]+]] = icmp slt i64 %wide.narrow.iv, 99
|
||
|
; CHECK: br i1 [[COND]], label %loop, label %main.exit.selector
|
||
|
; CHECK: postloop
|
||
|
|
||
|
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(i32* %n_ptr, i64* %m_ptr) {
|
||
|
|
||
|
; CHECK-LABEL: @test_increasing_slt_slt_wide_non-negative(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: br i1 true, label %backedge, label %check_failed
|
||
|
; CHECK: backedge
|
||
|
; CHECK: [[COND:%[^ ]+]] = icmp slt i64 %wide.narrow.iv, %exit.mainloop.at
|
||
|
; CHECK: br i1 [[COND]], label %loop, label %main.exit.selector
|
||
|
; CHECK: postloop
|
||
|
|
||
|
entry:
|
||
|
%N = load i32, i32* %n_ptr, !range !2
|
||
|
%M = load i64, i64* %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(i32* %n_ptr, i64* %m_ptr) {
|
||
|
|
||
|
; CHECK-LABEL: @test_increasing_slt_slt_wide_general(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: br i1 true, label %backedge, label %check_failed
|
||
|
; CHECK: backedge
|
||
|
; CHECK: [[COND:%[^ ]+]] = icmp slt i64
|
||
|
; CHECK: br i1 [[COND]], label %loop, label %main.exit.selector
|
||
|
; CHECK: postloop
|
||
|
|
||
|
entry:
|
||
|
%N = load i32, i32* %n_ptr, !range !2
|
||
|
%M = load i64, i64* %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(i32* %n_ptr, i64* %m_ptr) {
|
||
|
|
||
|
; CHECK-LABEL: @test_increasing_slt_slt_wide_general_preloop(
|
||
|
; CHECK: loop:
|
||
|
; CHECK: br i1 true, label %backedge, label %check_failed
|
||
|
; CHECK: backedge
|
||
|
; CHECK: [[COND:%[^ ]+]] = icmp slt i64
|
||
|
; CHECK: br i1 [[COND]], label %loop, label %main.exit.selector
|
||
|
; CHECK: preloop
|
||
|
; CHECK: postloop
|
||
|
|
||
|
entry:
|
||
|
%N = load i32, i32* %n_ptr, !range !2
|
||
|
%M = load i64, i64* %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(i32* %n_ptr, i64* %m1_ptr, i64* %m2_ptr, i64* %m3_ptr, i64* %m4_ptr) {
|
||
|
; CHECK-LABEL: @test_increasing_slt_slt_wide_multiple_checks(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: %c1 = and i1 true, true
|
||
|
; CHECK: %c2 = and i1 %c1, true
|
||
|
; CHECK: %rc = and i1 %c2, true
|
||
|
; CHECK: br i1 %rc, label %backedge, label %check_failed.loopexit
|
||
|
; CHECK: backedge
|
||
|
; CHECK: [[COND:%[^ ]+]] = icmp slt i64
|
||
|
; CHECK: br i1 [[COND]], label %loop, label %main.exit.selector
|
||
|
; CHECK: postloop
|
||
|
|
||
|
entry:
|
||
|
%N = load i32, i32* %n_ptr, !range !2
|
||
|
%M1 = load i64, i64* %m1_ptr
|
||
|
%M2 = load i64, i64* %m2_ptr
|
||
|
%M3 = load i64, i64* %m3_ptr
|
||
|
%M4 = load i64, i64* %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: @test_increasing_slt_slt_wide_simple_negtest_narrow_rc(
|
||
|
; CHECK-NOT: i1 true
|
||
|
; CHECK-NOT: main
|
||
|
|
||
|
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: @test_increasing_ult_ult_wide_simple_no_postloop(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK-NOT: postloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: br i1 true, label %backedge, label %check_failed
|
||
|
|
||
|
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: @test_increasing_ult_ult_wide_simple_postloop(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: br i1 true, label %backedge, label %check_failed
|
||
|
; CHECK: backedge
|
||
|
; CHECK: [[COND:%[^ ]+]] = icmp ult i64 %wide.narrow.iv, 99
|
||
|
; CHECK: br i1 [[COND]], label %loop, label %main.exit.selector
|
||
|
; CHECK: postloop
|
||
|
|
||
|
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(i32* %n_ptr, i64* %m_ptr) {
|
||
|
|
||
|
; CHECK-LABEL: @test_increasing_ult_ult_wide_non-negative(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: br i1 true, label %backedge, label %check_failed
|
||
|
; CHECK: backedge
|
||
|
; CHECK: [[COND:%[^ ]+]] = icmp ult i64 %wide.narrow.iv, %exit.mainloop.at
|
||
|
; CHECK: br i1 [[COND]], label %loop, label %main.exit.selector
|
||
|
; CHECK: postloop
|
||
|
|
||
|
entry:
|
||
|
%N = load i32, i32* %n_ptr, !range !2
|
||
|
%M = load i64, i64* %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(i32* %n_ptr, i64* %m_ptr) {
|
||
|
|
||
|
; CHECK-LABEL: @test_increasing_ult_ult_wide_general(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: br i1 true, label %backedge, label %check_failed
|
||
|
; CHECK: backedge
|
||
|
; CHECK: [[COND:%[^ ]+]] = icmp ult i64
|
||
|
; CHECK: br i1 [[COND]], label %loop, label %main.exit.selector
|
||
|
; CHECK: postloop
|
||
|
|
||
|
entry:
|
||
|
%N = load i32, i32* %n_ptr, !range !2
|
||
|
%M = load i64, i64* %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(i32* %n_ptr, i64* %m1_ptr, i64* %m2_ptr, i64* %m3_ptr, i64* %m4_ptr) {
|
||
|
; CHECK-LABEL: @test_increasing_ult_ult_wide_multiple_checks(
|
||
|
; CHECK-NOT: preloop
|
||
|
; CHECK: loop:
|
||
|
; CHECK: %c1 = and i1 true, true
|
||
|
; CHECK: %c2 = and i1 %c1, true
|
||
|
; CHECK: %rc = and i1 %c2, true
|
||
|
; CHECK: br i1 %rc, label %backedge, label %check_failed.loopexit
|
||
|
; CHECK: backedge
|
||
|
; CHECK: [[COND:%[^ ]+]] = icmp ult i64
|
||
|
; CHECK: br i1 [[COND]], label %loop, label %main.exit.selector
|
||
|
; CHECK: postloop
|
||
|
|
||
|
entry:
|
||
|
%N = load i32, i32* %n_ptr, !range !2
|
||
|
%M1 = load i64, i64* %m1_ptr
|
||
|
%M2 = load i64, i64* %m2_ptr
|
||
|
%M3 = load i64, i64* %m3_ptr
|
||
|
%M4 = load i64, i64* %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: @test_increasing_ult_ult_wide_simple_negtest_narrow_rc(
|
||
|
; CHECK-NOT: i1 true
|
||
|
; CHECK-NOT: main
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
!0 = !{i32 0, i32 2147483647}
|
||
|
!1 = !{i64 0, i64 9223372036854775807}
|
||
|
!2 = !{i32 1, i32 2147483647}
|