Imported Upstream version 5.18.0.167

Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-10-20 08:25:10 +00:00
parent e19d552987
commit b084638f15
28489 changed files with 184 additions and 3866856 deletions

View File

@ -1,81 +0,0 @@
; RUN: opt -irce -S < %s 2>&1 | FileCheck %s
; test that the pre and post loops have loop metadata which disables any further
; loop optimizations.
; generates a post loop, which should have metadata !llvm.loop !2
; Function Attrs: alwaysinline
define void @inner_loop(i32* %arr, i32* %a_len_ptr, i32 %n) #0 {
; CHECK-LABEL: inner_loop(
; CHECK-LABEL: in.bounds.postloop
; CHECK: br i1 %next.postloop, label %loop.postloop, label %exit.loopexit.loopexit, !llvm.loop !2, !irce.loop.clone !7
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop: ; preds = %in.bounds, %entry
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds: ; preds = %loop
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds: ; preds = %loop
ret void
exit: ; preds = %in.bounds, %entry
ret void
}
; add loop metadata for pre and post loops
define void @single_access_with_preloop(i32 *%arr, i32 *%a_len_ptr, i32 %n, i32 %offset) {
; CHECK-LABEL: @single_access_with_preloop(
; CHECK-LABEL: in.bounds.preloop
; CHECK: br i1 [[COND:%[^ ]+]], label %loop.preloop, label %preloop.exit.selector, !llvm.loop !8, !irce.loop.clone !7
; CHECK-LABEL: in.bounds.postloop
; CHECK: br i1 %next.postloop, label %loop.postloop, label %exit.loopexit.loopexit, !llvm.loop !9, !irce.loop.clone !7
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%array.idx = add i32 %idx, %offset
%abc.high = icmp slt i32 %array.idx, %len
%abc.low = icmp sge i32 %array.idx, 0
%abc = and i1 %abc.low, %abc.high
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %array.idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
attributes #0 = { alwaysinline }
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}
!2 = distinct !{!2, !3, !4, !5, !6}
!3 = !{!"llvm.loop.unroll.disable"}
!4 = !{!"llvm.loop.vectorize.enable", i1 false}
!5 = !{!"llvm.loop.licm_versioning.disable"}
!6 = !{!"llvm.loop.distribute.enable", i1 false}
!7 = !{}
!8 = distinct !{!8, !3, !4, !5}
!9 = distinct !{!9, !3, !4, !5}

View File

@ -1,45 +0,0 @@
; RUN: opt -S -irce -irce-print-changed-loops=true < %s | FileCheck %s
; CHECK-NOT: irce
define void @bad_loop_structure_increasing(i64 %iv.start) {
entry:
br label %for.body
for.body:
%indvars.iv = phi i64 [ %iv.start, %entry ], [ %indvars.iv.next, %for.inc ]
%cmp = icmp ult i64 %indvars.iv, 100
br i1 %cmp, label %switch.lookup, label %for.inc
switch.lookup:
br label %for.inc
for.inc:
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%cmp55 = icmp slt i64 %indvars.iv.next, 11
br i1 %cmp55, label %for.body, label %for.end
for.end:
ret void
}
define void @bad_loop_structure_decreasing(i64 %iv.start) {
entry:
br label %for.body
for.body:
%indvars.iv = phi i64 [ %iv.start, %entry ], [ %indvars.iv.next, %for.inc ]
%cmp = icmp ult i64 %indvars.iv, 100
br i1 %cmp, label %switch.lookup, label %for.inc
switch.lookup:
br label %for.inc
for.inc:
%indvars.iv.next = add nuw nsw i64 %indvars.iv, -1
%cmp55 = icmp sgt i64 %indvars.iv.next, 11
br i1 %cmp55, label %for.body, label %for.end
for.end:
ret void
}

View File

@ -1,135 +0,0 @@
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:1"
target triple = "x86_64-unknown-linux-gnu"
; IRCE should fail here because the preheader's exiting value is a phi from the
; loop, and this value cannot be expanded at loop's preheader.
; CHECK-NOT: irce: in function test_01: constrained Loop
; CHECK-NOT: irce: in function test_02: constrained Loop
; CHECK-LABEL: irce: in function test_03: constrained Loop
define void @test_01() {
; CHECK-NOT: irce: in function test_01: constrained Loop
; CHECK-LABEL: test_01
; CHECK-NOT: preloop
; CHECK-NOT: postloop
; CHECK-NOT: br i1 false
; CHECK-NOT: br i1 true
entry:
br label %loop
exit: ; preds = %guarded, %loop
ret void
loop: ; preds = %guarded, %entry
%iv = phi i64 [ 380, %entry ], [ %limit, %guarded ]
%bad_phi = phi i32 [ 3, %entry ], [ %bad_phi.next, %guarded ]
%bad_phi.next = add nuw nsw i32 %bad_phi, 1
%iv.next = add nuw nsw i64 %iv, 1
%rc = icmp slt i64 %iv.next, 5
br i1 %rc, label %guarded, label %exit
guarded:
%limit = add nsw i64 %iv, -1
%tmp5 = add nuw nsw i32 %bad_phi, 8
%tmp6 = zext i32 %tmp5 to i64
%tmp7 = icmp eq i64 %limit, %tmp6
br i1 %tmp7, label %exit, label %loop
}
; This test should fail because we are unable to prove that the division is
; safe to expand it to preheader: if we exit by maybe_exit condition, it is
; unsafe to execute it there.
define void @test_02(i64* %p1, i64* %p2, i1 %maybe_exit) {
; CHECK-LABEL: test_02
; CHECK-NOT: preloop
; CHECK-NOT: postloop
; CHECK-NOT: br i1 false
; CHECK-NOT: br i1 true
entry:
%num = load i64, i64* %p1, align 4, !range !0
%denom = load i64, i64* %p2, align 4, !range !0
br label %loop
exit: ; preds = %guarded, %loop
ret void
loop: ; preds = %guarded, %entry
%iv = phi i64 [ 0, %entry ], [ %iv.next, %guarded ]
%iv.next = add nuw nsw i64 %iv, 1
br i1 %maybe_exit, label %range_check, label %exit
range_check:
%div_result = udiv i64 %num, %denom
%rc = icmp slt i64 %iv.next, %div_result
br i1 %rc, label %guarded, label %exit
guarded:
%gep = getelementptr i64, i64* %p1, i64 %iv.next
%loaded = load i64, i64* %gep, align 4
%tmp7 = icmp slt i64 %iv.next, 1000
br i1 %tmp7, label %loop, label %exit
}
define void @test_03(i64* %p1, i64* %p2, i1 %maybe_exit) {
; Show that IRCE would hit test_02 if the division was safe (denom not zero).
; CHECK-LABEL: test_03
; CHECK: entry:
; CHECK-NEXT: %num = load i64, i64* %p1, align 4
; CHECK-NEXT: [[DIV:%[^ ]+]] = udiv i64 %num, 13
; CHECK-NEXT: [[DIV_MINUS_1:%[^ ]+]] = add i64 [[DIV]], -1
; CHECK-NEXT: [[COMP1:%[^ ]+]] = icmp sgt i64 [[DIV_MINUS_1]], 0
; CHECK-NEXT: %exit.mainloop.at = select i1 [[COMP1]], i64 [[DIV_MINUS_1]], i64 0
; CHECK-NEXT: [[COMP2:%[^ ]+]] = icmp slt i64 0, %exit.mainloop.at
; CHECK-NEXT: br i1 [[COMP2]], label %loop.preheader, label %main.pseudo.exit
; CHECK-NOT: preloop
; CHECK: loop:
; CHECK-NEXT: %iv = phi i64 [ %iv.next, %guarded ], [ 0, %loop.preheader ]
; CHECK-NEXT: %iv.next = add nuw nsw i64 %iv, 1
; CHECK-NEXT: %rc = icmp slt i64 %iv.next, %div_result
; CHECK-NEXT: %or.cond = and i1 %maybe_exit, true
; CHECK-NEXT: br i1 %or.cond, label %guarded, label %exit.loopexit1
; CHECK: guarded:
; CHECK-NEXT: %gep = getelementptr i64, i64* %p1, i64 %iv.next
; CHECK-NEXT: %loaded = load i64, i64* %gep, align 4
; CHECK-NEXT: %tmp7 = icmp slt i64 %iv.next, 1000
; CHECK-NEXT: [[EXIT_MAIN_LOOP:%[^ ]+]] = icmp slt i64 %iv.next, %exit.mainloop.at
; CHECK-NEXT: br i1 [[EXIT_MAIN_LOOP]], label %loop, label %main.exit.selector
; CHECK: postloop
entry:
%num = load i64, i64* %p1, align 4, !range !0
br label %loop
exit: ; preds = %guarded, %loop
ret void
loop: ; preds = %guarded, %entry
%iv = phi i64 [ 0, %entry ], [ %iv.next, %guarded ]
%iv.next = add nuw nsw i64 %iv, 1
br i1 %maybe_exit, label %range_check, label %exit
range_check:
%div_result = udiv i64 %num, 13
%rc = icmp slt i64 %iv.next, %div_result
br i1 %rc, label %guarded, label %exit
guarded:
%gep = getelementptr i64, i64* %p1, i64 %iv.next
%loaded = load i64, i64* %gep, align 4
%tmp7 = icmp slt i64 %iv.next, 1000
br i1 %tmp7, label %loop, label %exit
}
!0 = !{i64 0, i64 100}

View File

@ -1,31 +0,0 @@
; RUN: opt -irce-print-changed-loops -S -verify-loop-info -irce -verify < %s 2>&1 | FileCheck %s
; CHECK-NOT: constrained loop
define void @single_access_no_preloop_no_offset(i32 *%arr, i32 *%a_len_ptr, i32 %n) {
entry:
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%len = load i32, i32* %a_len_ptr, !range !0
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}

View File

@ -1,66 +0,0 @@
; RUN: opt -verify-loop-info -irce -S < %s
; These test cases don't check the correctness of the transform, but
; that -irce does not crash in the presence of certain things in
; the IR:
define void @mismatched_types_1() {
; In this test case, the safe range for the only range check in the
; loop is of type [i32, i32) while the backedge taken count is of type
; i64.
; CHECK-LABEL: @mismatched_types_1(
entry:
br label %for.body
for.body:
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.inc ]
%0 = trunc i64 %indvars.iv to i32
%1 = icmp ult i32 %0, 7
br i1 %1, label %switch.lookup, label %for.inc
switch.lookup:
br label %for.inc
for.inc:
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%cmp55 = icmp slt i64 %indvars.iv.next, 11
br i1 %cmp55, label %for.body, label %for.end
for.end:
unreachable
}
define void @mismatched_types_2() {
; In this test case, there are two range check in the loop, one with a
; safe range of type [i32, i32) and one with a safe range of type
; [i64, i64).
; CHECK-LABEL: @mismatched_types_2(
entry:
br label %for.body.a
for.body.a:
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.inc ]
%cond.a = icmp ult i64 %indvars.iv, 7
br i1 %cond.a, label %switch.lookup.a, label %for.body.b
switch.lookup.a:
br label %for.body.b
for.body.b:
%truncated = trunc i64 %indvars.iv to i32
%cond.b = icmp ult i32 %truncated, 7
br i1 %cond.b, label %switch.lookup.b, label %for.inc
switch.lookup.b:
br label %for.inc
for.inc:
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%cmp55 = icmp slt i64 %indvars.iv.next, 11
br i1 %cmp55, label %for.body.a, label %for.end
for.end:
unreachable
}

View File

@ -1,94 +0,0 @@
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s
; The test demonstrates that incorrect behavior of Clamp may lead to incorrect
; calculation of post-loop exit condition.
; CHECK-LABEL: irce: in function test_01: constrained Loop at depth 1 containing: %loop<header><exiting>,%in_bounds<exiting>,%not_zero<latch><exiting>
; CHECK-NOT: irce: in function test_02: constrained Loop
define void @test_01() {
; CHECK-LABEL: test_01
entry:
%indvars.iv.next467 = add nuw nsw i64 2, 1
%length.i167 = load i32, i32 addrspace(1)* undef, align 8
%tmp21 = zext i32 %length.i167 to i64
%tmp34 = load atomic i32, i32 addrspace(1)* undef unordered, align 4
%tmp35 = add i32 %tmp34, -9581
%tmp36 = icmp ugt i32 %length.i167, 1
br i1 %tmp36, label %preheader, label %exit
exit: ; preds = %in_bounds, %loop, %not_zero, %entry
ret void
preheader: ; preds = %entry
; CHECK: preheader:
; CHECK-NEXT: %length_gep.i146 = getelementptr inbounds i8, i8 addrspace(1)* undef, i64 8
; CHECK-NEXT: %length_gep_typed.i147 = bitcast i8 addrspace(1)* undef to i32 addrspace(1)*
; CHECK-NEXT: %tmp43 = icmp ult i64 %indvars.iv.next467, %tmp21
; CHECK-NEXT: [[C0:%[^ ]+]] = icmp ugt i64 %tmp21, 1
; CHECK-NEXT: %exit.mainloop.at = select i1 [[C0]], i64 %tmp21, i64 1
; CHECK-NEXT: [[C1:%[^ ]+]] = icmp ult i64 1, %exit.mainloop.at
; CHECK-NEXT: br i1 [[C1]], label %loop.preheader, label %main.pseudo.exit
%length_gep.i146 = getelementptr inbounds i8, i8 addrspace(1)* undef, i64 8
%length_gep_typed.i147 = bitcast i8 addrspace(1)* undef to i32 addrspace(1)*
%tmp43 = icmp ult i64 %indvars.iv.next467, %tmp21
br label %loop
not_zero: ; preds = %in_bounds
; CHECK: not_zero:
; CHECK: %tmp56 = icmp ult i64 %indvars.iv.next, %tmp21
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp ult i64 %indvars.iv.next, %exit.mainloop.at
; CHECK-NEXT: br i1 [[COND]], label %loop, label %main.exit.selector
%tmp51 = trunc i64 %indvars.iv.next to i32
%tmp53 = mul i32 %tmp51, %tmp51
%tmp54 = add i32 %tmp53, -9582
%tmp55 = add i32 %tmp54, %tmp62
%tmp56 = icmp ult i64 %indvars.iv.next, %tmp21
br i1 %tmp56, label %loop, label %exit
loop: ; preds = %not_zero, %preheader
%tmp62 = phi i32 [ 1, %preheader ], [ %tmp55, %not_zero ]
%indvars.iv750 = phi i64 [ 1, %preheader ], [ %indvars.iv.next, %not_zero ]
%length.i148 = load i32, i32 addrspace(1)* %length_gep_typed.i147, align 8
%tmp68 = zext i32 %length.i148 to i64
%tmp97 = icmp ult i64 2, %tmp68
%or.cond = and i1 %tmp43, %tmp97
%tmp99 = icmp ult i64 %indvars.iv750, %tmp21
%or.cond1 = and i1 %or.cond, %tmp99
br i1 %or.cond1, label %in_bounds, label %exit
in_bounds: ; preds = %loop
%indvars.iv.next = add nuw nsw i64 %indvars.iv750, 3
%tmp107 = icmp ult i64 %indvars.iv.next, 2
br i1 %tmp107, label %not_zero, label %exit
}
define void @test_02() {
; Now IRCE is smart enough to understand that the safe range here is empty.
; Previously it executed the entire loop in safe preloop and never actually
; entered the main loop.
entry:
br label %loop
loop: ; preds = %in_bounds, %entry
%iv1 = phi i64 [ 3, %entry ], [ %iv1.next, %in_bounds ]
%iv2 = phi i64 [ 4294967295, %entry ], [ %iv2.next, %in_bounds ]
%iv2.offset = add i64 %iv2, 1
%rc = icmp ult i64 %iv2.offset, 400
br i1 %rc, label %in_bounds, label %bci_321
bci_321: ; preds = %in_bounds, %loop
ret void
in_bounds: ; preds = %loop
%iv1.next = add nuw nsw i64 %iv1, 2
%iv2.next = add nuw nsw i64 %iv2, 2
%cond = icmp ugt i64 %iv1, 204
br i1 %cond, label %bci_321, label %loop
}

View File

@ -1,109 +0,0 @@
; RUN: opt -S -verify-loop-info -irce < %s | FileCheck %s
define void @f_0(i32 *%arr, i32 *%a_len_ptr, i32 %n, i1* %cond_buf) {
; CHECK-LABEL: @f_0(
; CHECK: loop.preheader:
; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n
; CHECK: [[not_safe_range_end:[^ ]+]] = sub i32 3, %len
; CHECK: [[not_exit_main_loop_at_hiclamp_cmp:[^ ]+]] = icmp sgt i32 [[not_n]], [[not_safe_range_end]]
; CHECK: [[not_exit_main_loop_at_hiclamp:[^ ]+]] = select i1 [[not_exit_main_loop_at_hiclamp_cmp]], i32 [[not_n]], i32 [[not_safe_range_end]]
; CHECK: [[exit_main_loop_at_hiclamp:[^ ]+]] = sub i32 -1, [[not_exit_main_loop_at_hiclamp]]
; CHECK: [[exit_main_loop_at_loclamp_cmp:[^ ]+]] = icmp sgt i32 [[exit_main_loop_at_hiclamp]], 0
; CHECK: [[exit_main_loop_at_loclamp:[^ ]+]] = select i1 [[exit_main_loop_at_loclamp_cmp]], i32 [[exit_main_loop_at_hiclamp]], i32 0
; CHECK: [[enter_main_loop:[^ ]+]] = icmp slt i32 0, [[exit_main_loop_at_loclamp]]
; CHECK: br i1 [[enter_main_loop]], label %loop.preheader2, label %main.pseudo.exit
; CHECK: loop.preheader2:
; CHECK: br label %loop
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.for.abc = add i32 %idx, 4
%abc.actual = icmp slt i32 %idx.for.abc, %len
%cond = load volatile i1, i1* %cond_buf
%abc = and i1 %cond, %abc.actual
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
; CHECK: loop:
; CHECK: %cond = load volatile i1, i1* %cond_buf
; CHECK: %abc = and i1 %cond, true
; CHECK: br i1 %abc, label %in.bounds, label %out.of.bounds.loopexit3, !prof !1
; CHECK: out.of.bounds.loopexit:
; CHECK: br label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx.for.abc
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
define void @f_1(
i32* %arr_a, i32* %a_len_ptr, i32* %arr_b, i32* %b_len_ptr, i32 %n) {
; CHECK-LABEL: @f_1(
; CHECK: loop.preheader:
; CHECK: [[not_len_b:[^ ]+]] = sub i32 -1, %len.b
; CHECK: [[not_len_a:[^ ]+]] = sub i32 -1, %len.a
; CHECK: [[smax_not_len_cond:[^ ]+]] = icmp sgt i32 [[not_len_b]], [[not_len_a]]
; CHECK: [[smax_not_len:[^ ]+]] = select i1 [[smax_not_len_cond]], i32 [[not_len_b]], i32 [[not_len_a]]
; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n
; CHECK: [[not_upper_limit_cond_loclamp:[^ ]+]] = icmp sgt i32 [[smax_not_len]], [[not_n]]
; CHECK: [[not_upper_limit_loclamp:[^ ]+]] = select i1 [[not_upper_limit_cond_loclamp]], i32 [[smax_not_len]], i32 [[not_n]]
; CHECK: [[upper_limit_loclamp:[^ ]+]] = sub i32 -1, [[not_upper_limit_loclamp]]
; CHECK: [[upper_limit_cmp:[^ ]+]] = icmp sgt i32 [[upper_limit_loclamp]], 0
; CHECK: [[upper_limit:[^ ]+]] = select i1 [[upper_limit_cmp]], i32 [[upper_limit_loclamp]], i32 0
entry:
%len.a = load i32, i32* %a_len_ptr, !range !0
%len.b = load i32, i32* %b_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc.a = icmp slt i32 %idx, %len.a
%abc.b = icmp slt i32 %idx, %len.b
%abc = and i1 %abc.a, %abc.b
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
; CHECK: loop:
; CHECK: %abc = and i1 true, true
; CHECK: br i1 %abc, label %in.bounds, label %out.of.bounds.loopexit4, !prof !1
; CHECK: out.of.bounds.loopexit:
; CHECK-NEXT: br label %out.of.bounds
in.bounds:
%addr.a = getelementptr i32, i32* %arr_a, i32 %idx
store i32 0, i32* %addr.a
%addr.b = getelementptr i32, i32* %arr_b, i32 %idx
store i32 -1, i32* %addr.b
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}

View File

@ -1,182 +0,0 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -irce < %s -S | FileCheck %s
; REQUIRES: asserts
; IRCE creates the pre and post loop, and invokes the
; canonicalizing these loops to LCSSA and loop-simplfy structure. Make sure that the update to the loopinfo does not
; incorrectly change the header while canonicalizing these pre/post loops. We
; were incorrectly updating LI when the split loop is a subloop as in the case below.
source_filename = "correct-loop-info.ll"
define void @baz() personality i32* ()* @ham {
; CHECK-LABEL: @baz(
; CHECK-NEXT: bb:
; CHECK-NEXT: br label [[OUTERHEADER:%.*]]
; CHECK: outerheader:
; CHECK-NEXT: [[TMP:%.*]] = icmp slt i32 undef, 84
; CHECK-NEXT: br i1 [[TMP]], label [[BB2:%.*]], label [[BB16:%.*]]
; CHECK: bb2:
; CHECK-NEXT: br i1 false, label [[INNERHEADER_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]]
; CHECK: innerheader.preloop.preheader:
; CHECK-NEXT: br label [[INNERHEADER_PRELOOP:%.*]]
; CHECK: mainloop:
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[INDVAR_END:%.*]], 0
; CHECK-NEXT: br i1 [[TMP0]], label [[INNERHEADER_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: innerheader.preheader:
; CHECK-NEXT: br label [[INNERHEADER:%.*]]
; CHECK: innerheader:
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ [[TMP6:%.*]], [[BB8:%.*]] ], [ [[TMP4_PRELOOP_COPY:%.*]], [[INNERHEADER_PREHEADER]] ]
; CHECK-NEXT: invoke void @pluto()
; CHECK-NEXT: to label [[BB5:%.*]] unwind label %outer_exiting.loopexit.split-lp.loopexit.split-lp
; CHECK: bb5:
; CHECK-NEXT: [[TMP6]] = add i32 [[TMP4]], 1
; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 1
; CHECK-NEXT: br i1 true, label [[BB8]], label [[EXIT3_LOOPEXIT5:%.*]]
; CHECK: bb8:
; CHECK-NEXT: [[TMP9:%.*]] = icmp slt i32 [[TMP6]], 84
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[TMP6]], 0
; CHECK-NEXT: br i1 [[TMP1]], label [[INNERHEADER]], label [[MAIN_EXIT_SELECTOR:%.*]]
; CHECK: main.exit.selector:
; CHECK-NEXT: [[TMP6_LCSSA:%.*]] = phi i32 [ [[TMP6]], [[BB8]] ]
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP6_LCSSA]], 84
; CHECK-NEXT: br i1 [[TMP2]], label [[MAIN_PSEUDO_EXIT]], label [[BB13:%.*]]
; CHECK: main.pseudo.exit:
; CHECK-NEXT: [[TMP4_COPY:%.*]] = phi i32 [ [[TMP4_PRELOOP_COPY]], [[MAINLOOP:%.*]] ], [ [[TMP6_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END1:%.*]] = phi i32 [ [[INDVAR_END]], [[MAINLOOP]] ], [ [[TMP6_LCSSA]], [[MAIN_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[POSTLOOP:%.*]]
; CHECK: outer_exiting.loopexit:
; CHECK-NEXT: [[LPAD_LOOPEXIT:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label [[OUTER_EXITING:%.*]]
; CHECK: outer_exiting.loopexit.split-lp.loopexit:
; CHECK-NEXT: [[LPAD_LOOPEXIT2:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label %outer_exiting.loopexit.split-lp
; CHECK: outer_exiting.loopexit.split-lp.loopexit.split-lp:
; CHECK-NEXT: %lpad.loopexit.split-lp3 = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label %outer_exiting.loopexit.split-lp
; CHECK: outer_exiting.loopexit.split-lp:
; CHECK-NEXT: br label [[OUTER_EXITING]]
; CHECK: outer_exiting:
; CHECK-NEXT: switch i32 undef, label [[EXIT2:%.*]] [
; CHECK-NEXT: i32 142, label [[BB14:%.*]]
; CHECK-NEXT: i32 448, label [[EXIT:%.*]]
; CHECK-NEXT: ]
; CHECK: exit3.loopexit:
; CHECK-NEXT: br label [[EXIT3:%.*]]
; CHECK: exit3.loopexit4:
; CHECK-NEXT: br label [[EXIT3]]
; CHECK: exit3.loopexit5:
; CHECK-NEXT: br label [[EXIT3]]
; CHECK: exit3:
; CHECK-NEXT: ret void
; CHECK: bb13.loopexit:
; CHECK-NEXT: br label [[BB13]]
; CHECK: bb13:
; CHECK-NEXT: unreachable
; CHECK: bb14:
; CHECK-NEXT: br label [[OUTERHEADER]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: bb16:
; CHECK-NEXT: ret void
; CHECK: exit2:
; CHECK-NEXT: ret void
; CHECK: innerheader.preloop:
; CHECK-NEXT: [[TMP4_PRELOOP:%.*]] = phi i32 [ [[TMP6_PRELOOP:%.*]], [[BB8_PRELOOP:%.*]] ], [ undef, [[INNERHEADER_PRELOOP_PREHEADER]] ]
; CHECK-NEXT: invoke void @pluto()
; CHECK-NEXT: to label [[BB5_PRELOOP:%.*]] unwind label [[OUTER_EXITING_LOOPEXIT:%.*]]
; CHECK: bb5.preloop:
; CHECK-NEXT: [[TMP6_PRELOOP]] = add i32 [[TMP4_PRELOOP]], 1
; CHECK-NEXT: [[TMP7_PRELOOP:%.*]] = icmp slt i32 [[TMP6_PRELOOP]], 1
; CHECK-NEXT: br i1 [[TMP7_PRELOOP]], label [[BB8_PRELOOP]], label [[EXIT3_LOOPEXIT:%.*]]
; CHECK: bb8.preloop:
; CHECK-NEXT: [[TMP9_PRELOOP:%.*]] = icmp slt i32 [[TMP6_PRELOOP]], 84
; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP6_PRELOOP]], -1
; CHECK-NEXT: br i1 [[TMP3]], label [[INNERHEADER_PRELOOP]], label [[PRELOOP_EXIT_SELECTOR:%.*]], !llvm.loop !0, !irce.loop.clone !5
; CHECK: preloop.exit.selector:
; CHECK-NEXT: [[TMP6_PRELOOP_LCSSA:%.*]] = phi i32 [ [[TMP6_PRELOOP]], [[BB8_PRELOOP]] ]
; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i32 [[TMP6_PRELOOP_LCSSA]], 84
; CHECK-NEXT: br i1 [[TMP4]], label [[PRELOOP_PSEUDO_EXIT]], label [[BB13]]
; CHECK: preloop.pseudo.exit:
; CHECK-NEXT: [[TMP4_PRELOOP_COPY]] = phi i32 [ undef, [[BB2]] ], [ [[TMP6_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ]
; CHECK-NEXT: [[INDVAR_END]] = phi i32 [ undef, [[BB2]] ], [ [[TMP6_PRELOOP_LCSSA]], [[PRELOOP_EXIT_SELECTOR]] ]
; CHECK-NEXT: br label [[MAINLOOP]]
; CHECK: postloop:
; CHECK-NEXT: br label [[INNERHEADER_POSTLOOP:%.*]]
; CHECK: innerheader.postloop:
; CHECK-NEXT: [[TMP4_POSTLOOP:%.*]] = phi i32 [ [[TMP6_POSTLOOP:%.*]], [[BB8_POSTLOOP:%.*]] ], [ [[TMP4_COPY]], [[POSTLOOP]] ]
; CHECK-NEXT: invoke void @pluto()
; CHECK-NEXT: to label [[BB5_POSTLOOP:%.*]] unwind label %outer_exiting.loopexit.split-lp.loopexit
; CHECK: bb5.postloop:
; CHECK-NEXT: [[TMP6_POSTLOOP]] = add i32 [[TMP4_POSTLOOP]], 1
; CHECK-NEXT: [[TMP7_POSTLOOP:%.*]] = icmp slt i32 [[TMP6_POSTLOOP]], 1
; CHECK-NEXT: br i1 [[TMP7_POSTLOOP]], label [[BB8_POSTLOOP]], label [[EXIT3_LOOPEXIT4:%.*]]
; CHECK: bb8.postloop:
; CHECK-NEXT: [[TMP9_POSTLOOP:%.*]] = icmp slt i32 [[TMP6_POSTLOOP]], 84
; CHECK-NEXT: br i1 [[TMP9_POSTLOOP]], label [[INNERHEADER_POSTLOOP]], label [[BB13_LOOPEXIT:%.*]], !llvm.loop !6, !irce.loop.clone !5
;
bb:
br label %outerheader
outerheader: ; preds = %bb14, %bb
%tmp = icmp slt i32 undef, 84
br i1 %tmp, label %bb2, label %bb16
bb2: ; preds = %outerheader
br label %innerheader
innerheader: ; preds = %bb8, %bb2
%tmp4 = phi i32 [ %tmp6, %bb8 ], [ undef, %bb2 ]
invoke void @pluto()
to label %bb5 unwind label %outer_exiting
bb5: ; preds = %innerheader
%tmp6 = add i32 %tmp4, 1
%tmp7 = icmp slt i32 %tmp6, 1
br i1 %tmp7, label %bb8, label %exit3
bb8: ; preds = %bb5
%tmp9 = icmp slt i32 %tmp6, 84
br i1 %tmp9, label %innerheader, label %bb13
outer_exiting: ; preds = %innerheader
%tmp11 = landingpad { i8*, i32 }
cleanup
switch i32 undef, label %exit2 [
i32 142, label %bb14
i32 448, label %exit
]
exit3: ; preds = %bb5
ret void
bb13: ; preds = %bb8
unreachable
bb14: ; preds = %outer_exiting
br label %outerheader
exit: ; preds = %outer_exiting
ret void
bb16: ; preds = %outerheader
ret void
exit2: ; preds = %outer_exiting
ret void
}
declare i32* @ham()
declare void @pluto()
!0 = distinct !{!0, !1, !2, !3, !4}
!1 = !{!"llvm.loop.unroll.disable"}
!2 = !{!"llvm.loop.vectorize.enable", i1 false}
!3 = !{!"llvm.loop.licm_versioning.disable"}
!4 = !{!"llvm.loop.distribute.enable", i1 false}
!5 = !{}
!6 = distinct !{!6, !1, !2, !3, !4}

View File

@ -1,42 +0,0 @@
; RUN: opt -verify-loop-info -irce -S < %s | FileCheck %s
define void @decrementing_loop(i32 *%arr, i32 *%a_len_ptr, i32 %n) {
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
%start = sub i32 %n, 1
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ %start, %entry ] , [ %idx.dec, %in.bounds ]
%idx.dec = sub i32 %idx, 1
%abc.high = icmp slt i32 %idx, %len
%abc.low = icmp sge i32 %idx, 0
%abc = and i1 %abc.low, %abc.high
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp sgt i32 %idx.dec, -1
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
; CHECK: loop.preheader:
; CHECK: [[not_len:[^ ]+]] = sub i32 -1, %len
; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n
; CHECK: [[not_len_hiclamp_cmp:[^ ]+]] = icmp sgt i32 [[not_len]], [[not_n]]
; CHECK: [[not_len_hiclamp:[^ ]+]] = select i1 [[not_len_hiclamp_cmp]], i32 [[not_len]], i32 [[not_n]]
; CHECK: [[len_hiclamp:[^ ]+]] = sub i32 -1, [[not_len_hiclamp]]
; CHECK: [[not_exit_preloop_at_cmp:[^ ]+]] = icmp sgt i32 [[len_hiclamp]], 0
; CHECK: [[not_exit_preloop_at:[^ ]+]] = select i1 [[not_exit_preloop_at_cmp]], i32 [[len_hiclamp]], i32 0
; CHECK: %exit.preloop.at = add i32 [[not_exit_preloop_at]], -1
}
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}

View File

@ -1,68 +0,0 @@
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S
; Make sure that IRCE doesn't apply in case of empty ranges.
; (i + 30 < 40) if i in [-30, 10).
; Intersected with iteration space, it is [0, 10).
; (i - 60 < 40) if i in [60 , 100).
; The intersection with safe iteration space is the empty range [60, 10).
; It is better to eliminate one range check than attempt to eliminate both given
; that we will never go to the main loop in the latter case and basically
; only duplicate code with no benefits.
define void @test_01(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK-LABEL: test_01(
; CHECK-NOT: preloop
; CHECK: entry:
; CHECK-NEXT: br i1 true, label %loop.preheader, label %main.pseudo.exit
; CHECK: in.bounds.1:
; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx
; CHECK-NEXT: store i32 0, i32* %addr
; CHECK-NEXT: %off1 = add i32 %idx, 30
; CHECK-NEXT: %c2 = icmp slt i32 %off1, 40
; CHECK-NEXT: br i1 true, label %in.bounds.2, label %exit.loopexit2
; CHECK: in.bounds.2:
; CHECK-NEXT: %off2 = add i32 %idx, -60
; CHECK-NEXT: %c3 = icmp slt i32 %off2, 40
; CHECK-NEXT: br i1 %c3, label %in.bounds.3, label %exit.loopexit2
; CHECK: in.bounds.3:
; CHECK-NEXT: %next = icmp ult i32 %idx.next, 100
; CHECK-NEXT: [[COND1:%[^ ]+]] = icmp ult i32 %idx.next, 10
; CHECK-NEXT: br i1 [[COND1]], label %loop, label %main.exit.selector
; CHECK: main.exit.selector:
; CHECK-NEXT: %idx.next.lcssa = phi i32 [ %idx.next, %in.bounds.3 ]
; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ult i32 %idx.next.lcssa, 100
; CHECK-NEXT: br i1 [[COND2]], label %main.pseudo.exit, label %exit
; CHECK: postloop:
entry:
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds.3 ]
%idx.next = add nsw nuw i32 %idx, 1
%c1 = icmp slt i32 %idx, 20
br i1 %c1, label %in.bounds.1, label %out.of.bounds
in.bounds.1:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%off1 = add i32 %idx, 30
%c2 = icmp slt i32 %off1, 40
br i1 %c2, label %in.bounds.2, label %exit
in.bounds.2:
%off2 = add i32 %idx, -60
%c3 = icmp slt i32 %off2, 40
br i1 %c3, label %in.bounds.3, label %exit
in.bounds.3:
%next = icmp ult i32 %idx.next, 100
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}

View File

@ -1,291 +0,0 @@
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s
; CHECK: irce: in function test_01: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; CHECK: irce: in function test_01u: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; CHECK-NOT: irce: in function test_02: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; CHECK: irce: in function test_03: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; CHECK-NOT: irce: in function test_04: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; CHECK: irce: in function test_05: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; CHECK-NOT: irce: in function test_06: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; CHECK: irce: in function test_07: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; CHECK-NOT: irce: in function test_08: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; Show that IRCE can turn 'ne' condition to 'slt' in increasing IV when the IV
; can be negative at some point.
define void @test_01(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK: test_01
; CHECK: main.exit.selector:
; CHECK-NEXT: [[PSEUDO_PHI:%[^ ]+]] = phi i32 [ %idx.next, %in.bounds ]
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp slt i32 [[PSEUDO_PHI]], 100
; CHECK-NEXT: br i1 [[COND]]
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ -3, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp ne i32 %idx.next, 100
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Show that IRCE can turn 'ne' condition to 'ult' in increasing IV when IV is
; non-negative.
define void @test_01u(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK: test_01u
; CHECK: main.exit.selector:
; CHECK-NEXT: [[PSEUDO_PHI:%[^ ]+]] = phi i32 [ %idx.next, %in.bounds ]
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp ult i32 [[PSEUDO_PHI]], 100
; CHECK-NEXT: br i1 [[COND]]
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp ne i32 %idx.next, 100
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Show that if n is not known to be greater than the starting value, IRCE
; doesn't apply.
define void @test_02(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK: test_02(
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp ne i32 %idx.next, -100
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Show that IRCE can turn 'eq' condition to 'sge' in increasing IV.
define void @test_03(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK: test_03(
; CHECK: main.exit.selector:
; CHECK-NEXT: [[PSEUDO_PHI:%[^ ]+]] = phi i32 [ %idx.next, %in.bounds ]
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp slt i32 [[PSEUDO_PHI]], 100
; CHECK-NEXT: br i1 [[COND]]
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp eq i32 %idx.next, 100
br i1 %next, label %exit, label %loop
out.of.bounds:
ret void
exit:
ret void
}
; Show that if n is not known to be greater than the starting value, IRCE
; doesn't apply.
define void @test_04(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK: test_04(
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp eq i32 %idx.next, -100
br i1 %next, label %exit, label %loop
out.of.bounds:
ret void
exit:
ret void
}
; Show that IRCE can turn 'ne' condition to 'sgt' in decreasing IV.
define void @test_05(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK: test_05(
; CHECK: preloop.exit.selector:
; CHECK-NEXT: [[PSEUDO_PHI:%[^ ]+]] = phi i32 [ %idx.next.preloop, %in.bounds.preloop ]
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp sgt i32 [[PSEUDO_PHI]], 0
; CHECK-NEXT: br i1 [[COND]]
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 100, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, -1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp ne i32 %idx.next, 0
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Show that IRCE cannot turn 'ne' condition to 'sgt' in decreasing IV if the end
; value is not proved to be less than the start value.
define void @test_06(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK: test_06(
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 100, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, -1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp ne i32 %idx.next, 120
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Show that IRCE can turn 'eq' condition to 'slt' in decreasing IV.
define void @test_07(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK: test_07(
; CHECK: preloop.exit.selector:
; CHECK-NEXT: [[PSEUDO_PHI:%[^ ]+]] = phi i32 [ %idx.next.preloop, %in.bounds.preloop ]
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp sgt i32 [[PSEUDO_PHI]], 0
; CHECK-NEXT: br i1 [[COND]]
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 100, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, -1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp eq i32 %idx.next, 0
br i1 %next, label %exit, label %loop
out.of.bounds:
ret void
exit:
ret void
}
; Show that IRCE cannot turn 'eq' condition to 'slt' in decreasing IV if the end
; value is not proved to be less than the start value.
define void @test_08(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK: test_08(
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 100, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, -1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp eq i32 %idx.next, 120
br i1 %next, label %exit, label %loop
out.of.bounds:
ret void
exit:
ret void
}
!0 = !{i32 0, i32 50}

View File

@ -1,32 +0,0 @@
; RUN: opt -irce-print-changed-loops -verify-loop-info -irce -S < %s 2>&1 | FileCheck %s
; CHECK-NOT: constrained Loop
define void @low_profiled_be_count(i32 *%arr, i32 *%a_len_ptr, i32 %n) {
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit, !prof !2
out.of.bounds:
ret void
exit:
ret void
}
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}
!2 = !{!"branch_weights", i32 4, i32 64}

View File

@ -1,66 +0,0 @@
; RUN: opt -verify-loop-info -irce -S < %s | FileCheck %s
define void @multiple_access_no_preloop(
i32* %arr_a, i32* %a_len_ptr, i32* %arr_b, i32* %b_len_ptr, i32 %n) {
entry:
%len.a = load i32, i32* %a_len_ptr, !range !0
%len.b = load i32, i32* %b_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds.b ]
%idx.next = add i32 %idx, 1
%abc.a = icmp slt i32 %idx, %len.a
br i1 %abc.a, label %in.bounds.a, label %out.of.bounds, !prof !1
in.bounds.a:
%addr.a = getelementptr i32, i32* %arr_a, i32 %idx
store i32 0, i32* %addr.a
%abc.b = icmp slt i32 %idx, %len.b
br i1 %abc.b, label %in.bounds.b, label %out.of.bounds, !prof !1
in.bounds.b:
%addr.b = getelementptr i32, i32* %arr_b, i32 %idx
store i32 -1, i32* %addr.b
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; CHECK-LABEL: @multiple_access_no_preloop(
; CHECK: loop.preheader:
; CHECK: [[not_len_b:[^ ]+]] = sub i32 -1, %len.b
; CHECK: [[not_len_a:[^ ]+]] = sub i32 -1, %len.a
; CHECK: [[smax_not_len_cond:[^ ]+]] = icmp sgt i32 [[not_len_b]], [[not_len_a]]
; CHECK: [[smax_not_len:[^ ]+]] = select i1 [[smax_not_len_cond]], i32 [[not_len_b]], i32 [[not_len_a]]
; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n
; CHECK: [[not_upper_limit_cond_loclamp:[^ ]+]] = icmp sgt i32 [[smax_not_len]], [[not_n]]
; CHECK: [[not_upper_limit_loclamp:[^ ]+]] = select i1 [[not_upper_limit_cond_loclamp]], i32 [[smax_not_len]], i32 [[not_n]]
; CHECK: [[upper_limit_loclamp:[^ ]+]] = sub i32 -1, [[not_upper_limit_loclamp]]
; CHECK: [[upper_limit_cmp:[^ ]+]] = icmp sgt i32 [[upper_limit_loclamp]], 0
; CHECK: [[upper_limit:[^ ]+]] = select i1 [[upper_limit_cmp]], i32 [[upper_limit_loclamp]], i32 0
; CHECK: loop:
; CHECK: br i1 true, label %in.bounds.a, label %out.of.bounds
; CHECK: in.bounds.a:
; CHECK: br i1 true, label %in.bounds.b, label %out.of.bounds
; CHECK: in.bounds.b:
; CHECK: [[main_loop_cond:[^ ]+]] = icmp slt i32 %idx.next, [[upper_limit]]
; CHECK: br i1 [[main_loop_cond]], label %loop, label %main.exit.selector
; CHECK: in.bounds.b.postloop:
; CHECK: %next.postloop = icmp slt i32 %idx.next.postloop, %n
; CHECK: br i1 %next.postloop, label %loop.postloop, label %exit.loopexit
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}

View File

@ -1,40 +0,0 @@
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce < %s 2>&1 | FileCheck %s
; CHECK-NOT: constrained Loop
define void @multiple_access_no_preloop(
i32* %arr_a, i32* %a_len_ptr, i32* %arr_b, i32* %b_len_ptr, i32 %n) {
entry:
%len.a = load i32, i32* %a_len_ptr, !range !0
%len.b = load i32, i32* %b_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds.b ]
%idx.next = add i32 %idx, 1
%abc.a = icmp slt i32 %idx, %len.a
br i1 %abc.a, label %in.bounds.a, label %out.of.bounds, !prof !1
in.bounds.a:
%addr.a = getelementptr i32, i32* %arr_a, i32 %idx
store i32 0, i32* %addr.a
%abc.b = icmp slt i32 %idx, %len.b
br i1 %abc.b, label %in.bounds.b, label %out.of.bounds, !prof !1
in.bounds.b:
%addr.b = getelementptr i32, i32* %arr_b, i32 %idx
store i32 -1, i32* %addr.b
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 1, i32 1}

View File

@ -1,37 +0,0 @@
; RUN: opt -irce-print-range-checks -irce-print-changed-loops -verify-loop-info -irce < %s 2>&1 | FileCheck %s
; CHECK: irce: loop has 1 inductive range checks:
; CHECK-NEXT: InductiveRangeCheck:
; CHECK-NEXT: Kind: RANGE_CHECK_LOWER
; CHECK-NEXT: Begin: (-1 + %n) Step: -1 End: (null)
; CHECK-NEXT: CheckUse: br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1 Operand: 0
; CHECK-NEXT: irce: in function only_lower_check: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
define void @only_lower_check(i32 *%arr, i32 *%a_len_ptr, i32 %n) {
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
%start = sub i32 %n, 1
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ %start, %entry ] , [ %idx.dec, %in.bounds ]
%idx.dec = sub i32 %idx, 1
%abc = icmp sge i32 %idx, 0
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp sgt i32 %idx.dec, -1
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}

View File

@ -1,37 +0,0 @@
; RUN: opt -verify-loop-info -irce -irce-print-range-checks -irce-print-changed-loops %s -S 2>&1 | FileCheck %s
; CHECK: irce: loop has 1 inductive range checks:
; CHECK-NEXT:InductiveRangeCheck:
; CHECK-NEXT: Kind: RANGE_CHECK_UPPER
; CHECK-NEXT: Begin: %offset Step: 1 End: %len
; CHECK-NEXT: CheckUse: br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1 Operand: 0
; CHECK-NEXT: irce: in function incrementing: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
define void @incrementing(i32 *%arr, i32 *%a_len_ptr, i32 %n, i32 %offset) {
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%array.idx = add i32 %idx, %offset
%abc = icmp slt i32 %array.idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %array.idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}

View File

@ -1,117 +0,0 @@
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s
; CHECK: irce: in function test_01: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; CHECK: irce: in function test_02: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
; Iterate from 0 to SINT_MAX, check that the post-loop is generated.
define void @test_01(i32* %arr, i32* %a_len_ptr) {
; CHECK: test_01(
; CHECK: entry:
; CHECK-NEXT: %exit.mainloop.at = load i32, i32* %a_len_ptr
; CHECK: loop:
; CHECK-NEXT: %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ]
; CHECK-NEXT: %idx.next = add i32 %idx, 1
; CHECK-NEXT: %abc = icmp slt i32 %idx, %exit.mainloop.at
; CHECK-NEXT: br i1 true, label %in.bounds,
; CHECK: in.bounds:
; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx
; CHECK-NEXT: store i32 0, i32* %addr
; CHECK-NEXT: %next = icmp slt i32 %idx.next, 2147483647
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp slt i32 %idx.next, %exit.mainloop.at
; CHECK-NEXT: br i1 [[COND]], label %loop, label %main.exit.selector
; CHECK: main.pseudo.exit:
; CHECK-NEXT: %idx.copy = phi i32 [ 0, %entry ], [ %idx.next.lcssa, %main.exit.selector ]
; CHECK-NEXT: %indvar.end = phi i32 [ 0, %entry ], [ %idx.next.lcssa, %main.exit.selector ]
; CHECK-NEXT: br label %postloop
; CHECK: postloop:
; CHECK-NEXT: br label %loop.postloop
; CHECK: loop.postloop:
; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ]
; CHECK-NEXT: %idx.next.postloop = add i32 %idx.postloop, 1
; CHECK-NEXT: %abc.postloop = icmp slt i32 %idx.postloop, %exit.mainloop.at
; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit
; CHECK: in.bounds.postloop:
; CHECK-NEXT: %addr.postloop = getelementptr i32, i32* %arr, i32 %idx.postloop
; CHECK-NEXT: store i32 0, i32* %addr.postloop
; CHECK-NEXT: %next.postloop = icmp slt i32 %idx.next.postloop, 2147483647
; CHECK-NEXT: br i1 %next.postloop, label %loop.postloop, label %exit.loopexit
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, 2147483647
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Iterate from SINT_MAX to 0, check that the pre-loop is generated.
define void @test_02(i32* %arr, i32* %a_len_ptr) {
; CHECK: test_02(
; CHECK: entry:
; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0
; CHECH-NEXT: br i1 true, label %loop.preloop.preheader
; CHECK: mainloop:
; CHECK-NEXT: br label %loop
; CHECK: loop:
; CHECK-NEXT: %idx = phi i32 [ %idx.preloop.copy, %mainloop ], [ %idx.next, %in.bounds ]
; CHECK-NEXT: %idx.next = add i32 %idx, -1
; CHECK-NEXT: %abc = icmp slt i32 %idx, %len
; CHECK-NEXT: br i1 true, label %in.bounds
; CHECK: in.bounds:
; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx
; CHECK-NEXT: store i32 0, i32* %addr
; CHECK-NEXT: %next = icmp sgt i32 %idx.next, -1
; CHECK-NEXT: br i1 %next, label %loop, label %exit.loopexit
; CHECK: loop.preloop:
; CHECK-NEXT: %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ 2147483647, %loop.preloop.preheader ]
; CHECK-NEXT: %idx.next.preloop = add i32 %idx.preloop, -1
; CHECK-NEXT: %abc.preloop = icmp slt i32 %idx.preloop, %len
; CHECK-NEXT: br i1 %abc.preloop, label %in.bounds.preloop, label %out.of.bounds.loopexit
; CHECK: in.bounds.preloop:
; CHECK-NEXT: %addr.preloop = getelementptr i32, i32* %arr, i32 %idx.preloop
; CHECK-NEXT: store i32 0, i32* %addr.preloop
; CHECK-NEXT: %next.preloop = icmp sgt i32 %idx.next.preloop, -1
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp sgt i32 %idx.next.preloop, -1
; CHECK-NEXT: br i1 [[COND]], label %loop.preloop, label %preloop.exit.selector
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 2147483647, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, -1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp sgt i32 %idx.next, -1
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
!0 = !{i32 0, i32 50}

View File

@ -1,286 +0,0 @@
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s
; CHECK-LABEL: irce: in function test_01: constrained Loop at depth 1 containing:
; CHECK-LABEL: irce: in function test_02: constrained Loop at depth 1 containing:
; CHECK-LABEL: irce: in function test_03: constrained Loop at depth 1 containing:
; CHECK-LABEL: irce: in function test_04: constrained Loop at depth 1 containing:
; CHECK-LABEL: irce: in function test_05: constrained Loop at depth 1 containing:
; This test used to demonstrate a miscompile: the outer loop's IV iterates in
; range of [2, 400) and the range check is done against value 331. Due to a bug
; in range intersection IRCE manages to eliminate the range check without
; inserting a postloop, which is incorrect. We treat the range of this test as
; an unsigned range and are able to intersect ranges correctly and insert a
; postloop.
define void @test_01() {
; CHECK-LABEL: test_01
; CHECK-NOT: preloop
; CHECK: range_check_block: ; preds = %inner_loop
; CHECK-NEXT: %range_check = icmp slt i32 %iv, 331
; CHECK-NEXT: br i1 true, label %loop_latch
; CHECK: loop_latch:
; CHECK-NEXT: %iv_next = add i32 %iv, 1
; CHECK-NEXT: %loop_cond = icmp ult i32 %iv_next, 400
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp ult i32 %iv_next, 331
; CHECK-NEXT: br i1 [[COND]], label %loop_header, label %main.exit.selector
; CHECK: main.exit.selector: ; preds = %loop_latch
; CHECK-NEXT: %iv_next.lcssa = phi i32 [ %iv_next, %loop_latch ]
; CHECK-NEXT: %iv.lcssa = phi i32 [ %iv, %loop_latch ]
; CHECK-NEXT: [[MES_COND:%[^ ]+]] = icmp ult i32 %iv_next.lcssa, 400
; CHECK-NEXT: br i1 [[MES_COND]], label %main.pseudo.exit, label %exit
; CHECK: loop_latch.postloop: ; preds = %range_check_block.postloop
; CHECK-NEXT: %iv_next.postloop = add i32 %iv.postloop, 1
; CHECK-NEXT: %loop_cond.postloop = icmp ult i32 %iv_next.postloop, 400
; CHECK-NEXT: br i1 %loop_cond.postloop, label %loop_header.postloop, label %exit.loopexit
entry:
br label %loop_header
loop_header: ; preds = %loop_latch, %entry
%iv = phi i32 [ 2, %entry ], [ %iv_next, %loop_latch ]
%iv.prev = phi i32 [ 1, %entry ], [ %iv, %loop_latch ]
%tmp2 = icmp sgt i32 %iv.prev, -1
br i1 %tmp2, label %loop_header.split.us, label %exit
loop_header.split.us: ; preds = %loop_header
br label %inner_loop
inner_loop: ; preds = %inner_loop, %loop_header.split.us
%inner_iv = phi i32 [ 1, %loop_header.split.us ], [ %inner_iv_next, %inner_loop ]
%inner_iv_next = add nuw nsw i32 %inner_iv, 1
%inner_cond = icmp ult i32 %inner_iv_next, 31
br i1 %inner_cond, label %inner_loop, label %range_check_block
exit: ; preds = %loop_latch, %loop_header
ret void
range_check_block: ; preds = %inner_loop
%range_check = icmp slt i32 %iv, 331
br i1 %range_check, label %loop_latch, label %deopt
loop_latch: ; preds = %range_check_block
%iv_next = add i32 %iv, 1
%loop_cond = icmp ult i32 %iv_next, 400
br i1 %loop_cond, label %loop_header, label %exit
deopt: ; preds = %range_check_block
ret void
}
; Similar to test_01, but here the range check is done against 450. No postloop
; is required.
define void @test_02() {
; CHECK-LABEL: test_02
; CHECK-NOT: preloop
; CHECK-NOT: postloop
; CHECK: range_check_block: ; preds = %inner_loop
; CHECK-NEXT: %range_check = icmp slt i32 %iv, 450
; CHECK-NEXT: br i1 true, label %loop_latch
; CHECK: loop_latch: ; preds = %range_check_block
; CHECK-NEXT: %iv_next = add i32 %iv, 1
; CHECK-NEXT: %loop_cond = icmp ult i32 %iv_next, 400
; CHECK-NEXT: br i1 %loop_cond, label %loop_header, label %exit
entry:
br label %loop_header
loop_header: ; preds = %loop_latch, %entry
%iv = phi i32 [ 2, %entry ], [ %iv_next, %loop_latch ]
%iv.prev = phi i32 [ 1, %entry ], [ %iv, %loop_latch ]
%tmp2 = icmp sgt i32 %iv.prev, -1
br i1 %tmp2, label %loop_header.split.us, label %exit
loop_header.split.us: ; preds = %loop_header
br label %inner_loop
inner_loop: ; preds = %inner_loop, %loop_header.split.us
%inner_iv = phi i32 [ 1, %loop_header.split.us ], [ %inner_iv_next, %inner_loop ]
%inner_iv_next = add nuw nsw i32 %inner_iv, 1
%inner_cond = icmp ult i32 %inner_iv_next, 31
br i1 %inner_cond, label %inner_loop, label %range_check_block
exit: ; preds = %loop_latch, %loop_header
ret void
range_check_block: ; preds = %inner_loop
%range_check = icmp slt i32 %iv, 450
br i1 %range_check, label %loop_latch, label %deopt
loop_latch: ; preds = %range_check_block
%iv_next = add i32 %iv, 1
%loop_cond = icmp ult i32 %iv_next, 400
br i1 %loop_cond, label %loop_header, label %exit
deopt: ; preds = %range_check_block
ret void
}
; Range check is made against 0, so the safe iteration range is empty. IRCE
; should not apply to the inner loop. The condition %tmp2 can be eliminated.
define void @test_03() {
; CHECK-LABEL: test_03
; CHECK-NOT: preloop
; CHECK-NOT: postloop
; CHECK: %tmp2 = icmp sgt i32 %iv.prev, -1
; CHECK-NEXT: br i1 true, label %loop_header.split.us, label %exit
; CHECK: range_check_block:
; CHECK-NEXT: %range_check = icmp slt i32 %iv, 0
; CHECK-NEXT: br i1 %range_check, label %loop_latch, label %deopt
entry:
br label %loop_header
loop_header: ; preds = %loop_latch, %entry
%iv = phi i32 [ 2, %entry ], [ %iv_next, %loop_latch ]
%iv.prev = phi i32 [ 1, %entry ], [ %iv, %loop_latch ]
%tmp2 = icmp sgt i32 %iv.prev, -1
br i1 %tmp2, label %loop_header.split.us, label %exit
loop_header.split.us: ; preds = %loop_header
br label %inner_loop
inner_loop: ; preds = %inner_loop, %loop_header.split.us
%inner_iv = phi i32 [ 1, %loop_header.split.us ], [ %inner_iv_next, %inner_loop ]
%inner_iv_next = add nuw nsw i32 %inner_iv, 1
%inner_cond = icmp ult i32 %inner_iv_next, 31
br i1 %inner_cond, label %inner_loop, label %range_check_block
exit: ; preds = %loop_latch, %loop_header
ret void
range_check_block: ; preds = %inner_loop
%range_check = icmp slt i32 %iv, 0
br i1 %range_check, label %loop_latch, label %deopt
loop_latch: ; preds = %range_check_block
%iv_next = add i32 %iv, 1
%loop_cond = icmp ult i32 %iv_next, 400
br i1 %loop_cond, label %loop_header, label %exit
deopt: ; preds = %range_check_block
ret void
}
; We do not know whether %n is positive or negative, so we prohibit IRCE in
; order to avoid incorrect intersection of signed and unsigned ranges.
; The condition %tmp2 can be eliminated.
define void @test_04(i32* %p) {
; CHECK-LABEL: test_04
; CHECK-NOT: preloop
; CHECK-NOT: postloop
; CHECK: %tmp2 = icmp sgt i32 %iv.prev, -1
; CHECK-NEXT: br i1 true, label %loop_header.split.us, label %exit
; CHECK: range_check_block:
; CHECK-NEXT: %range_check = icmp slt i32 %iv, %n
; CHECK-NEXT: br i1 %range_check, label %loop_latch, label %deopt
entry:
%n = load i32, i32* %p
br label %loop_header
loop_header: ; preds = %loop_latch, %entry
%iv = phi i32 [ 2, %entry ], [ %iv_next, %loop_latch ]
%iv.prev = phi i32 [ 1, %entry ], [ %iv, %loop_latch ]
%tmp2 = icmp sgt i32 %iv.prev, -1
br i1 %tmp2, label %loop_header.split.us, label %exit
loop_header.split.us: ; preds = %loop_header
br label %inner_loop
inner_loop: ; preds = %inner_loop, %loop_header.split.us
%inner_iv = phi i32 [ 1, %loop_header.split.us ], [ %inner_iv_next, %inner_loop ]
%inner_iv_next = add nuw nsw i32 %inner_iv, 1
%inner_cond = icmp ult i32 %inner_iv_next, 31
br i1 %inner_cond, label %inner_loop, label %range_check_block
exit: ; preds = %loop_latch, %loop_header
ret void
range_check_block: ; preds = %inner_loop
%range_check = icmp slt i32 %iv, %n
br i1 %range_check, label %loop_latch, label %deopt
loop_latch: ; preds = %range_check_block
%iv_next = add i32 %iv, 1
%loop_cond = icmp ult i32 %iv_next, 400
br i1 %loop_cond, label %loop_header, label %exit
deopt: ; preds = %range_check_block
ret void
}
; Same as test_04, but range guarantees that %n is positive. So we can safely
; intersect ranges (with insertion of postloop).
define void @test_05(i32* %p) {
; CHECK-LABEL: test_05
; CHECK-NOT: preloop
; CHECK: entry:
; CHECK-NEXT: %n = load i32, i32* %p, !range !6
; CHECK-NEXT: [[CMP_1:%[^ ]+]] = icmp ugt i32 %n, 2
; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP_1]], i32 %n, i32 2
; CHECK-NEXT: [[CMP_2:%[^ ]+]] = icmp ult i32 2, %exit.mainloop.at
; CHECK-NEXT: br i1 [[CMP_2]], label %loop_header.preheader, label %main.pseudo.exit
; CHECK: range_check_block: ; preds = %inner_loop
; CHECK-NEXT: %range_check = icmp slt i32 %iv, %n
; CHECK-NEXT: br i1 true, label %loop_latch, label %deopt.loopexit2
; CHECK: loop_latch: ; preds = %range_check_block
; CHECK-NEXT: %iv_next = add i32 %iv, 1
; CHECK-NEXT: %loop_cond = icmp ult i32 %iv_next, 400
; CHECK-NEXT: [[COND:%[^ ]+]] = icmp ult i32 %iv_next, %exit.mainloop.at
; CHECK-NEXT: br i1 [[COND]], label %loop_header, label %main.exit.selector
; CHECK: main.exit.selector: ; preds = %loop_latch
; CHECK-NEXT: %iv_next.lcssa = phi i32 [ %iv_next, %loop_latch ]
; CHECK-NEXT: %iv.lcssa = phi i32 [ %iv, %loop_latch ]
; CHECK-NEXT: [[MES_COND:%[^ ]+]] = icmp ult i32 %iv_next.lcssa, 400
; CHECK-NEXT: br i1 [[MES_COND]], label %main.pseudo.exit, label %exit
; CHECK: loop_latch.postloop: ; preds = %range_check_block.postloop
; CHECK-NEXT: %iv_next.postloop = add i32 %iv.postloop, 1
; CHECK-NEXT: %loop_cond.postloop = icmp ult i32 %iv_next.postloop, 400
; CHECK-NEXT: br i1 %loop_cond.postloop, label %loop_header.postloop, label %exit.loopexit
entry:
%n = load i32, i32* %p, !range !0
br label %loop_header
loop_header: ; preds = %loop_latch, %entry
%iv = phi i32 [ 2, %entry ], [ %iv_next, %loop_latch ]
%iv.prev = phi i32 [ 1, %entry ], [ %iv, %loop_latch ]
%tmp2 = icmp sgt i32 %iv.prev, -1
br i1 %tmp2, label %loop_header.split.us, label %exit
loop_header.split.us: ; preds = %loop_header
br label %inner_loop
inner_loop: ; preds = %inner_loop, %loop_header.split.us
%inner_iv = phi i32 [ 1, %loop_header.split.us ], [ %inner_iv_next, %inner_loop ]
%inner_iv_next = add nuw nsw i32 %inner_iv, 1
%inner_cond = icmp ult i32 %inner_iv_next, 31
br i1 %inner_cond, label %inner_loop, label %range_check_block
exit: ; preds = %loop_latch, %loop_header
ret void
range_check_block: ; preds = %inner_loop
%range_check = icmp slt i32 %iv, %n
br i1 %range_check, label %loop_latch, label %deopt
loop_latch: ; preds = %range_check_block
%iv_next = add i32 %iv, 1
%loop_cond = icmp ult i32 %iv_next, 400
br i1 %loop_cond, label %loop_header, label %exit
deopt: ; preds = %range_check_block
ret void
}
!0 = !{i32 0, i32 50}

View File

@ -1,427 +0,0 @@
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s
; Make sure we can eliminate range check with signed latch, unsigned IRC and
; positive offset. The safe iteration space is:
; No preloop,
; %exit.mainloop.at = smax (0, -1 - smax(12 - %len, -102)).
; Formula verification:
; %len = 10
; %exit.mainloop.at = 0
; %len = 50
; %exit.mainloop.at = 50 - 13 = 37.
; %len = 100
; %exit.mainloop.at = 100 - 13 = 87.
; %len = 150
; %exit.mainloop.at = 101.
; %len = SINT_MAX
; %exit.mainloop.at = 101
define void @test_01(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK-LABEL: test_01(
; CHECK-NOT: preloop
; CHECK: entry:
; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0
; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 12, %len
; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[SUB1]], -102
; CHECK-NEXT: [[SMAX:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 -102
; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, [[SMAX]]
; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SUB2]], 0
; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP2]], i32 [[SUB2]], i32 0
; CHECK-NEXT: [[GOTO_LOOP:%[^ ]+]] = icmp slt i32 0, %exit.mainloop.at
; CHECK-NEXT: br i1 [[GOTO_LOOP]], label %loop.preheader, label %main.pseudo.exit
; CHECK: loop
; CHECK: br i1 true, label %in.bounds
; CHECK: postloop:
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.offset = add i32 %idx, 13
%abc = icmp ult i32 %idx.offset, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, 101
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Make sure we can eliminate range check with signed latch, unsigned IRC and
; negative offset. The safe iteration space is:
; %exit.preloop.at = 13
; %exit.mainloop.at = smax(-1 - smax(smax(%len - SINT_MAX, -13) - 1 - %len, -102), 0)
; Formula verification:
; %len = 10
; %exit.mainloop.at = 0
; %len = 50
; %exit.mainloop.at = 63
; %len = 100
; %exit.mainloop.at = 101
; %len = 150
; %exit.mainloop.at = 101
; %len = SINT_MAX
; %exit.mainloop.at = 101
define void @test_02(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK-LABEL: test_02(
; CHECK: entry:
; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0
; CHECK-NEXT: [[LEN_MINUS_SMAX:%[^ ]+]] = add i32 %len, -2147483647
; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[LEN_MINUS_SMAX]], -13
; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[LEN_MINUS_SMAX]], i32 -13
; CHECK-NEXT: [[ADD1:%[^ ]+]] = add i32 [[SMAX1]], -1
; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 [[ADD1]], %len
; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SUB1]], -102
; CHECK-NEXT: [[SMAX2:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB1]], i32 -102
; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, [[SMAX2]]
; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp sgt i32 [[SUB2]], 0
; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP3]], i32 [[SUB2]], i32 0
; CHECK-NEXT: br i1 true, label %loop.preloop.preheader
; CHECK: loop.preloop:
; CHECK-NEXT: %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ 0, %loop.preloop.preheader ]
; CHECK-NEXT: %idx.next.preloop = add i32 %idx.preloop, 1
; CHECK-NEXT: %idx.offset.preloop = sub i32 %idx.preloop, 13
; CHECK-NEXT: %abc.preloop = icmp ult i32 %idx.offset.preloop, %len
; CHECK-NEXT: br i1 %abc.preloop, label %in.bounds.preloop, label %out.of.bounds.loopexit
; CHECK: in.bounds.preloop:
; CHECK-NEXT: %addr.preloop = getelementptr i32, i32* %arr, i32 %idx.preloop
; CHECK-NEXT: store i32 0, i32* %addr.preloop
; CHECK-NEXT: %next.preloop = icmp slt i32 %idx.next.preloop, 101
; CHECK-NEXT: [[PRELOOP_COND:%[^ ]+]] = icmp slt i32 %idx.next.preloop, 13
; CHECK-NEXT: br i1 [[PRELOOP_COND]], label %loop.preloop, label %preloop.exit.selector
; CHECK: postloop:
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.offset = sub i32 %idx, 13
%abc = icmp ult i32 %idx.offset, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, 101
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Make sure we can eliminate range check with unsigned latch, signed IRC and
; positive offset. The safe iteration space is:
; No preloop,
; %exit.mainloop.at = -1 - umax(-2 - %len - smax(-1 - %len, -14), -102)
; Formula verification:
; %len = 10
; %exit.mainloop.at = 0
; %len = 50
; %exit.mainloop.at = 37
; %len = 100
; %exit.mainloop.at = 87
; %len = 150
; %exit.mainloop.at = 101
; %len = SINT_MAX
; %exit.mainloop.at = 101
define void @test_03(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK-LABEL: test_03(
; CHECK-NOT: preloop
; CHECK: entry:
; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0
; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 -2, %len
; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, %len
; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[SUB2]], -14
; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB2]], i32 -14
; CHECK-NEXT: [[SUB3:%[^ ]+]] = sub i32 [[SUB1]], [[SMAX1]]
; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp ugt i32 [[SUB3]], -102
; CHECK-NEXT: [[UMAX1:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB3]], i32 -102
; CHECK-NEXT: %exit.mainloop.at = sub i32 -1, [[UMAX1]]
; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at
; CHECK-NEXT: br i1 [[CMP3]], label %loop.preheader, label %main.pseudo.exit
; CHECK: postloop:
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.offset = add i32 %idx, 13
%abc = icmp slt i32 %idx.offset, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp ult i32 %idx.next, 101
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Make sure we can eliminate range check with unsigned latch, signed IRC and
; positive offset. The safe iteration space is:
; %exit.preloop.at = 13
; %exit.mainloop.at = -1 - umax(-14 - %len, -102)
; Formula verification:
; %len = 10
; %exit.mainloop.at = 23
; %len = 50
; %exit.mainloop.at = 63
; %len = 100
; %exit.mainloop.at = 101
; %len = 150
; %exit.mainloop.at = 101
; %len = SINT_MAX
; %exit.mainloop.at = 101
define void @test_04(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK-LABEL: test_04(
; CHECK: entry:
; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0
; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 -14, %len
; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp ugt i32 [[SUB1]], -102
; CHECK-NEXT: [[UMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 -102
; CHECK-NEXT: %exit.mainloop.at = sub i32 -1, [[UMAX1]]
; CHECK-NEXT: br i1 true, label %loop.preloop.preheader
; CHECK: in.bounds.preloop:
; CHECK-NEXT: %addr.preloop = getelementptr i32, i32* %arr, i32 %idx.preloop
; CHECK-NEXT: store i32 0, i32* %addr.preloop
; CHECK-NEXT: %next.preloop = icmp ult i32 %idx.next.preloop, 101
; CHECK-NEXT: [[PRELOOP_COND:%[^ ]+]] = icmp ult i32 %idx.next.preloop, 13
; CHECK-NEXT: br i1 [[PRELOOP_COND]], label %loop.preloop, label %preloop.exit.selector
; CHECK: postloop:
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.offset = sub i32 %idx, 13
%abc = icmp slt i32 %idx.offset, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp ult i32 %idx.next, 101
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Signed latch, signed RC, positive offset. Same as test_01.
define void @test_05(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK-LABEL: test_05(
; CHECK-NOT: preloop
; CHECK: entry:
; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0
; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 12, %len
; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[SUB1]], -102
; CHECK-NEXT: [[SMAX:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 -102
; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, [[SMAX]]
; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SUB2]], 0
; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP2]], i32 [[SUB2]], i32 0
; CHECK-NEXT: [[GOTO_LOOP:%[^ ]+]] = icmp slt i32 0, %exit.mainloop.at
; CHECK-NEXT: br i1 [[GOTO_LOOP]], label %loop.preheader, label %main.pseudo.exit
; CHECK: loop
; CHECK: br i1 true, label %in.bounds
; CHECK: postloop:
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.offset = add i32 %idx, 13
%abc = icmp slt i32 %idx.offset, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, 101
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Signed latch, signed RC, negative offset. Same as test_02.
define void @test_06(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK-LABEL: test_06(
; CHECK: entry:
; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0
; CHECK-NEXT: [[LEN_MINUS_SMAX:%[^ ]+]] = add i32 %len, -2147483647
; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[LEN_MINUS_SMAX]], -13
; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[LEN_MINUS_SMAX]], i32 -13
; CHECK-NEXT: [[ADD1:%[^ ]+]] = add i32 [[SMAX1]], -1
; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 [[ADD1]], %len
; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SUB1]], -102
; CHECK-NEXT: [[SMAX2:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB1]], i32 -102
; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, [[SMAX2]]
; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp sgt i32 [[SUB2]], 0
; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP3]], i32 [[SUB2]], i32 0
; CHECK-NEXT: br i1 true, label %loop.preloop.preheader
; CHECK: in.bounds.preloop:
; CHECK-NEXT: %addr.preloop = getelementptr i32, i32* %arr, i32 %idx.preloop
; CHECK-NEXT: store i32 0, i32* %addr.preloop
; CHECK-NEXT: %next.preloop = icmp slt i32 %idx.next.preloop, 101
; CHECK-NEXT: [[PRELOOP_COND:%[^ ]+]] = icmp slt i32 %idx.next.preloop, 13
; CHECK-NEXT: br i1 [[PRELOOP_COND]], label %loop.preloop, label %preloop.exit.selector
; CHECK: postloop:
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.offset = sub i32 %idx, 13
%abc = icmp slt i32 %idx.offset, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, 101
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Unsigned latch, Unsigned RC, negative offset. Same as test_03.
define void @test_07(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK-LABEL: test_07(
; CHECK-NOT: preloop
; CHECK: entry:
; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0
; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 -2, %len
; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, %len
; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[SUB2]], -14
; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB2]], i32 -14
; CHECK-NEXT: [[SUB3:%[^ ]+]] = sub i32 [[SUB1]], [[SMAX1]]
; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp ugt i32 [[SUB3]], -102
; CHECK-NEXT: [[UMAX1:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB3]], i32 -102
; CHECK-NEXT: %exit.mainloop.at = sub i32 -1, [[UMAX1]]
; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at
; CHECK-NEXT: br i1 [[CMP3]], label %loop.preheader, label %main.pseudo.exit
; CHECK: loop
; CHECK: br i1 true, label %in.bounds
; CHECK: postloop:
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.offset = add i32 %idx, 13
%abc = icmp ult i32 %idx.offset, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp ult i32 %idx.next, 101
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; Unsigned latch, Unsigned RC, negative offset. Same as test_04.
define void @test_08(i32* %arr, i32* %a_len_ptr) #0 {
; CHECK-LABEL: test_08(
; CHECK: entry:
; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0
; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 -14, %len
; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp ugt i32 [[SUB1]], -102
; CHECK-NEXT: [[UMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 -102
; CHECK-NEXT: %exit.mainloop.at = sub i32 -1, [[UMAX1]]
; CHECK-NEXT: br i1 true, label %loop.preloop.preheader
; CHECK: in.bounds.preloop:
; CHECK-NEXT: %addr.preloop = getelementptr i32, i32* %arr, i32 %idx.preloop
; CHECK-NEXT: store i32 0, i32* %addr.preloop
; CHECK-NEXT: %next.preloop = icmp ult i32 %idx.next.preloop, 101
; CHECK-NEXT: [[PRELOOP_COND:%[^ ]+]] = icmp ult i32 %idx.next.preloop, 13
; CHECK-NEXT: br i1 [[PRELOOP_COND]], label %loop.preloop, label %preloop.exit.selector
; CHECK: postloop:
entry:
%len = load i32, i32* %a_len_ptr, !range !0
br label %loop
loop:
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.offset = sub i32 %idx, 13
%abc = icmp ult i32 %idx.offset, %len
br i1 %abc, label %in.bounds, label %out.of.bounds
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp ult i32 %idx.next, 101
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
!0 = !{i32 0, i32 2147483647}

View File

@ -1,183 +0,0 @@
; RUN: opt -verify-loop-info -irce -S < %s | FileCheck %s
define void @single_access_no_preloop_no_offset(i32 *%arr, i32 *%a_len_ptr, i32 %n) {
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, %len
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; CHECK-LABEL: @single_access_no_preloop_no_offset(
; CHECK: loop:
; CHECK: br i1 true, label %in.bounds, label %out.of.bounds
; CHECK: main.exit.selector:
; CHECK-NEXT: %idx.next.lcssa = phi i32 [ %idx.next, %in.bounds ]
; CHECK-NEXT: [[continue:%[^ ]+]] = icmp slt i32 %idx.next.lcssa, %n
; CHECK-NEXT: br i1 [[continue]], label %main.pseudo.exit, label %exit.loopexit
; CHECK: main.pseudo.exit:
; CHECK-NEXT: %idx.copy = phi i32 [ 0, %loop.preheader ], [ %idx.next.lcssa, %main.exit.selector ]
; CHECK-NEXT: %indvar.end = phi i32 [ 0, %loop.preheader ], [ %idx.next.lcssa, %main.exit.selector ]
; CHECK-NEXT: br label %postloop
; CHECK: postloop:
; CHECK-NEXT: br label %loop.postloop
; CHECK: loop.postloop:
; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.next.postloop, %in.bounds.postloop ], [ %idx.copy, %postloop ]
; CHECK-NEXT: %idx.next.postloop = add i32 %idx.postloop, 1
; CHECK-NEXT: %abc.postloop = icmp slt i32 %idx.postloop, %len
; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds
; CHECK: in.bounds.postloop:
; CHECK-NEXT: %addr.postloop = getelementptr i32, i32* %arr, i32 %idx.postloop
; CHECK-NEXT: store i32 0, i32* %addr.postloop
; CHECK-NEXT: %next.postloop = icmp slt i32 %idx.next.postloop, %n
; CHECK-NEXT: br i1 %next.postloop, label %loop.postloop, label %exit.loopexit
define void @single_access_no_preloop_with_offset(i32 *%arr, i32 *%a_len_ptr, i32 %n) {
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%idx.for.abc = add i32 %idx, 4
%abc = icmp slt i32 %idx.for.abc, %len
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx.for.abc
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; CHECK-LABEL: @single_access_no_preloop_with_offset(
; CHECK: loop.preheader:
; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n
; CHECK: [[not_safe_range_end:[^ ]+]] = sub i32 3, %len
; CHECK: [[not_exit_main_loop_at_hiclamp_cmp:[^ ]+]] = icmp sgt i32 [[not_n]], [[not_safe_range_end]]
; CHECK: [[not_exit_main_loop_at_hiclamp:[^ ]+]] = select i1 [[not_exit_main_loop_at_hiclamp_cmp]], i32 [[not_n]], i32 [[not_safe_range_end]]
; CHECK: [[exit_main_loop_at_hiclamp:[^ ]+]] = sub i32 -1, [[not_exit_main_loop_at_hiclamp]]
; CHECK: [[exit_main_loop_at_loclamp_cmp:[^ ]+]] = icmp sgt i32 [[exit_main_loop_at_hiclamp]], 0
; CHECK: [[exit_main_loop_at_loclamp:[^ ]+]] = select i1 [[exit_main_loop_at_loclamp_cmp]], i32 [[exit_main_loop_at_hiclamp]], i32 0
; CHECK: [[enter_main_loop:[^ ]+]] = icmp slt i32 0, [[exit_main_loop_at_loclamp]]
; CHECK: br i1 [[enter_main_loop]], label %loop.preheader2, label %main.pseudo.exit
; CHECK: loop:
; CHECK: br i1 true, label %in.bounds, label %out.of.bounds
; CHECK: in.bounds:
; CHECK: [[continue_main_loop:[^ ]+]] = icmp slt i32 %idx.next, [[exit_main_loop_at_loclamp]]
; CHECK: br i1 [[continue_main_loop]], label %loop, label %main.exit.selector
; CHECK: main.pseudo.exit:
; CHECK: %idx.copy = phi i32 [ 0, %loop.preheader ], [ %idx.next.lcssa, %main.exit.selector ]
; CHECK: br label %postloop
; CHECK: loop.postloop:
; CHECK: %idx.postloop = phi i32 [ %idx.next.postloop, %in.bounds.postloop ], [ %idx.copy, %postloop ]
; CHECK: in.bounds.postloop:
; CHECK: %next.postloop = icmp slt i32 %idx.next.postloop, %n
; CHECK: br i1 %next.postloop, label %loop.postloop, label %exit.loopexit
; Make sure that we do not do IRCE if we know that the safe iteration range of
; the main loop is empty.
define void @single_access_empty_range(i32 *%arr, i32 *%a_len_ptr, i32 %n) {
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, 0
br i1 %abc, label %in.bounds, label %out.of.bounds, !prof !1
in.bounds:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; CHECK-LABEL: @single_access_empty_range(
; CHECK-NOT: br i1 false
; CHECK-NOT: preloop
; CHECK-NOT: postloop
define void @single_access_empty_range_2(i32 *%arr, i32 *%a_len_ptr, i32 %n) {
entry:
%len = load i32, i32* %a_len_ptr, !range !0
%first.itr.check = icmp sgt i32 %n, 0
br i1 %first.itr.check, label %loop, label %exit
loop:
%idx = phi i32 [ 0, %entry ] , [ %idx.next, %in.bounds2 ]
%idx.next = add i32 %idx, 1
%abc = icmp slt i32 %idx, 60
br i1 %abc, label %in.bounds1, label %out.of.bounds, !prof !1
in.bounds1:
%def = icmp slt i32 %idx, 0
br i1 %def, label %in.bounds2, label %out.of.bounds, !prof !1
in.bounds2:
%addr = getelementptr i32, i32* %arr, i32 %idx
store i32 0, i32* %addr
%next = icmp slt i32 %idx.next, %n
br i1 %next, label %loop, label %exit
out.of.bounds:
ret void
exit:
ret void
}
; CHECK-LABEL: @single_access_empty_range_2(
; CHECK-NOT: br i1 false
; CHECK-NOT: preloop
!0 = !{i32 0, i32 2147483647}
!1 = !{!"branch_weights", i32 64, i32 4}

Some files were not shown because too many files have changed in this diff Show More