| ; 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} |