593 lines
22 KiB
LLVM
593 lines
22 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=indvars -S | FileCheck %s
|
|
|
|
declare void @fail(i32)
|
|
declare i1 @cond()
|
|
declare i32 @switch.cond()
|
|
declare i32 @llvm.smax.i32(i32 %a, i32 %b)
|
|
|
|
; Unsigned comparison here is redundant and can be safely deleted.
|
|
define i32 @trivial.case(i32* %len.ptr) {
|
|
; CHECK-LABEL: @trivial.case(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, !range [[RNG0:![0-9]+]]
|
|
; CHECK-NEXT: br label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]]
|
|
; CHECK: signed.passed:
|
|
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]]
|
|
; CHECK: failed.signed:
|
|
; CHECK-NEXT: call void @fail(i32 1)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.unsigned:
|
|
; CHECK-NEXT: call void @fail(i32 2)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: done:
|
|
; CHECK-NEXT: [[IV_LCSSA2:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ]
|
|
; CHECK-NEXT: ret i32 [[IV_LCSSA2]]
|
|
;
|
|
entry:
|
|
%len = load i32, i32* %len.ptr, !range !0
|
|
br label %preheader
|
|
|
|
preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [0, %preheader], [%iv.next, %backedge]
|
|
%signed.cmp = icmp slt i32 %iv, %len
|
|
br i1 %signed.cmp, label %signed.passed, label %failed.signed
|
|
|
|
signed.passed:
|
|
%unsigned.cmp = icmp ult i32 %iv, %len
|
|
br i1 %unsigned.cmp, label %backedge, label %failed.unsigned
|
|
|
|
backedge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = call i1 @cond()
|
|
br i1 %cond, label %loop, label %done
|
|
|
|
failed.signed:
|
|
call void @fail(i32 1)
|
|
unreachable
|
|
|
|
failed.unsigned:
|
|
call void @fail(i32 2)
|
|
unreachable
|
|
|
|
done:
|
|
ret i32 %iv
|
|
}
|
|
|
|
; TODO: The 2nd check can be made invariant.
|
|
; slt and ult checks are equivalent. When IV is negative, slt check will pass and ult will
|
|
; fail. Because IV is incrementing, this will fail on 1st iteration or never.
|
|
define i32 @unknown.start(i32 %start, i32* %len.ptr) {
|
|
; CHECK-LABEL: @unknown.start(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: br label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[PREHEADER]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp slt i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]]
|
|
; CHECK: signed.passed:
|
|
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]]
|
|
; CHECK: failed.signed:
|
|
; CHECK-NEXT: call void @fail(i32 1)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.unsigned:
|
|
; CHECK-NEXT: call void @fail(i32 2)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: done:
|
|
; CHECK-NEXT: [[IV_LCSSA2:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ]
|
|
; CHECK-NEXT: ret i32 [[IV_LCSSA2]]
|
|
;
|
|
entry:
|
|
%len = load i32, i32* %len.ptr, !range !0
|
|
br label %preheader
|
|
|
|
preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [%start, %preheader], [%iv.next, %backedge]
|
|
%signed.cmp = icmp slt i32 %iv, %len
|
|
br i1 %signed.cmp, label %signed.passed, label %failed.signed
|
|
|
|
signed.passed:
|
|
%unsigned.cmp = icmp ult i32 %iv, %len
|
|
br i1 %unsigned.cmp, label %backedge, label %failed.unsigned
|
|
|
|
backedge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = call i1 @cond()
|
|
br i1 %cond, label %loop, label %done
|
|
|
|
failed.signed:
|
|
call void @fail(i32 1)
|
|
unreachable
|
|
|
|
failed.unsigned:
|
|
call void @fail(i32 2)
|
|
unreachable
|
|
|
|
done:
|
|
ret i32 %iv
|
|
}
|
|
|
|
|
|
; TODO: We should be able to prove that:
|
|
; - %sibling.iv.next is non-negative;
|
|
; - therefore, %iv is non-negative;
|
|
; - therefore, unsigned check can be removed.
|
|
define i32 @start.from.sibling.iv(i32* %len.ptr, i32* %sibling.len.ptr) {
|
|
; CHECK-LABEL: @start.from.sibling.iv(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[SIBLING_LEN:%.*]] = load i32, i32* [[SIBLING_LEN_PTR:%.*]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: br label [[SIBLING_LOOP:%.*]]
|
|
; CHECK: sibling.loop:
|
|
; CHECK-NEXT: [[SIBLING_IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[SIBLING_IV_NEXT:%.*]], [[SIBLING_BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIBLING_RC:%.*]] = icmp ult i32 [[SIBLING_IV]], [[SIBLING_LEN]]
|
|
; CHECK-NEXT: br i1 [[SIBLING_RC]], label [[SIBLING_BACKEDGE]], label [[FAILED_SIBLING:%.*]]
|
|
; CHECK: sibling.backedge:
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT]] = add nuw nsw i32 [[SIBLING_IV]], 1
|
|
; CHECK-NEXT: [[SIBLING_COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[SIBLING_COND]], label [[SIBLING_LOOP]], label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT_LCSSA:%.*]] = phi i32 [ [[SIBLING_IV_NEXT]], [[SIBLING_BACKEDGE]] ]
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[SIBLING_IV_NEXT_LCSSA]], [[PREHEADER]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp slt i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]]
|
|
; CHECK: signed.passed:
|
|
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]]
|
|
; CHECK: failed.signed:
|
|
; CHECK-NEXT: call void @fail(i32 1)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.unsigned:
|
|
; CHECK-NEXT: call void @fail(i32 2)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.sibling:
|
|
; CHECK-NEXT: call void @fail(i32 3)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: done:
|
|
; CHECK-NEXT: [[IV_LCSSA2:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ]
|
|
; CHECK-NEXT: ret i32 [[IV_LCSSA2]]
|
|
;
|
|
entry:
|
|
%len = load i32, i32* %len.ptr, !range !0
|
|
%sibling.len = load i32, i32* %sibling.len.ptr, !range !0
|
|
br label %sibling.loop
|
|
|
|
sibling.loop:
|
|
%sibling.iv = phi i32 [0, %entry], [%sibling.iv.next, %sibling.backedge]
|
|
%sibling.rc = icmp ult i32 %sibling.iv, %sibling.len
|
|
br i1 %sibling.rc, label %sibling.backedge, label %failed.sibling
|
|
|
|
sibling.backedge:
|
|
%sibling.iv.next = add nuw nsw i32 %sibling.iv, 1
|
|
%sibling.cond = call i1 @cond()
|
|
br i1 %sibling.cond, label %sibling.loop, label %preheader
|
|
|
|
preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [%sibling.iv.next, %preheader], [%iv.next, %backedge]
|
|
%signed.cmp = icmp slt i32 %iv, %len
|
|
br i1 %signed.cmp, label %signed.passed, label %failed.signed
|
|
|
|
signed.passed:
|
|
%unsigned.cmp = icmp ult i32 %iv, %len
|
|
br i1 %unsigned.cmp, label %backedge, label %failed.unsigned
|
|
|
|
backedge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = call i1 @cond()
|
|
br i1 %cond, label %loop, label %done
|
|
|
|
failed.signed:
|
|
call void @fail(i32 1)
|
|
unreachable
|
|
|
|
failed.unsigned:
|
|
call void @fail(i32 2)
|
|
unreachable
|
|
|
|
failed.sibling:
|
|
call void @fail(i32 3)
|
|
unreachable
|
|
|
|
done:
|
|
ret i32 %iv
|
|
}
|
|
|
|
; Same as above, but the sibling loop is now wide. We can eliminate the unsigned comparison here.
|
|
define i32 @start.from.sibling.iv.wide(i32* %len.ptr, i32* %sibling.len.ptr) {
|
|
; CHECK-LABEL: @start.from.sibling.iv.wide(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[SIBLING_LEN:%.*]] = load i32, i32* [[SIBLING_LEN_PTR:%.*]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[SIBLING_LEN_WIDE:%.*]] = zext i32 [[SIBLING_LEN]] to i64
|
|
; CHECK-NEXT: br label [[SIBLING_LOOP:%.*]]
|
|
; CHECK: sibling.loop:
|
|
; CHECK-NEXT: [[SIBLING_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[SIBLING_IV_NEXT:%.*]], [[SIBLING_BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIBLING_RC:%.*]] = icmp ult i64 [[SIBLING_IV]], [[SIBLING_LEN_WIDE]]
|
|
; CHECK-NEXT: br i1 [[SIBLING_RC]], label [[SIBLING_BACKEDGE]], label [[FAILED_SIBLING:%.*]]
|
|
; CHECK: sibling.backedge:
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT]] = add nuw nsw i64 [[SIBLING_IV]], 1
|
|
; CHECK-NEXT: [[SIBLING_COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[SIBLING_COND]], label [[SIBLING_LOOP]], label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT_LCSSA:%.*]] = phi i64 [ [[SIBLING_IV_NEXT]], [[SIBLING_BACKEDGE]] ]
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT_TRUNC:%.*]] = trunc i64 [[SIBLING_IV_NEXT_LCSSA]] to i32
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[SIBLING_IV_NEXT_TRUNC]], [[PREHEADER]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]]
|
|
; CHECK: signed.passed:
|
|
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]]
|
|
; CHECK: failed.signed:
|
|
; CHECK-NEXT: call void @fail(i32 1)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.unsigned:
|
|
; CHECK-NEXT: call void @fail(i32 2)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.sibling:
|
|
; CHECK-NEXT: call void @fail(i32 3)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: done:
|
|
; CHECK-NEXT: [[IV_LCSSA2:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ]
|
|
; CHECK-NEXT: ret i32 [[IV_LCSSA2]]
|
|
;
|
|
entry:
|
|
%len = load i32, i32* %len.ptr, !range !0
|
|
%sibling.len = load i32, i32* %sibling.len.ptr, !range !0
|
|
%sibling.len.wide = zext i32 %sibling.len to i64
|
|
br label %sibling.loop
|
|
|
|
sibling.loop:
|
|
%sibling.iv = phi i64 [0, %entry], [%sibling.iv.next, %sibling.backedge]
|
|
%sibling.rc = icmp ult i64 %sibling.iv, %sibling.len.wide
|
|
br i1 %sibling.rc, label %sibling.backedge, label %failed.sibling
|
|
|
|
sibling.backedge:
|
|
%sibling.iv.next = add nuw nsw i64 %sibling.iv, 1
|
|
%sibling.cond = call i1 @cond()
|
|
br i1 %sibling.cond, label %sibling.loop, label %preheader
|
|
|
|
preheader:
|
|
%sibling.iv.next.trunc = trunc i64 %sibling.iv.next to i32
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [%sibling.iv.next.trunc, %preheader], [%iv.next, %backedge]
|
|
%signed.cmp = icmp slt i32 %iv, %len
|
|
br i1 %signed.cmp, label %signed.passed, label %failed.signed
|
|
|
|
signed.passed:
|
|
%unsigned.cmp = icmp ult i32 %iv, %len
|
|
br i1 %unsigned.cmp, label %backedge, label %failed.unsigned
|
|
|
|
backedge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = call i1 @cond()
|
|
br i1 %cond, label %loop, label %done
|
|
|
|
failed.signed:
|
|
call void @fail(i32 1)
|
|
unreachable
|
|
|
|
failed.unsigned:
|
|
call void @fail(i32 2)
|
|
unreachable
|
|
|
|
failed.sibling:
|
|
call void @fail(i32 3)
|
|
unreachable
|
|
|
|
done:
|
|
ret i32 %iv
|
|
}
|
|
|
|
; Slightly more complex version of previous one (cycled phis).
|
|
; TODO: remove unsigned comparison by proving non-negativity of iv.start.
|
|
; TODO: When we check against IV_START, for some reason we then cannot infer nuw for IV.next.
|
|
; It was possible while checking against IV. Missing inference logic somewhere.
|
|
define i32 @start.from.sibling.iv.wide.cycled.phis(i32* %len.ptr, i32* %sibling.len.ptr) {
|
|
; CHECK-LABEL: @start.from.sibling.iv.wide.cycled.phis(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[SIBLING_LEN:%.*]] = load i32, i32* [[SIBLING_LEN_PTR:%.*]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[SIBLING_LEN_WIDE:%.*]] = zext i32 [[SIBLING_LEN]] to i64
|
|
; CHECK-NEXT: br label [[SIBLING_LOOP:%.*]]
|
|
; CHECK: sibling.loop:
|
|
; CHECK-NEXT: [[SIBLING_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[SIBLING_IV_NEXT:%.*]], [[SIBLING_BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIBLING_RC:%.*]] = icmp ult i64 [[SIBLING_IV]], [[SIBLING_LEN_WIDE]]
|
|
; CHECK-NEXT: br i1 [[SIBLING_RC]], label [[SIBLING_BACKEDGE]], label [[FAILED_SIBLING:%.*]]
|
|
; CHECK: sibling.backedge:
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT]] = add nuw nsw i64 [[SIBLING_IV]], 1
|
|
; CHECK-NEXT: [[SIBLING_COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[SIBLING_COND]], label [[SIBLING_LOOP]], label [[OUTER_LOOP_PREHEADER:%.*]]
|
|
; CHECK: outer.loop.preheader:
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT_LCSSA:%.*]] = phi i64 [ [[SIBLING_IV_NEXT]], [[SIBLING_BACKEDGE]] ]
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT_TRUNC:%.*]] = trunc i64 [[SIBLING_IV_NEXT_LCSSA]] to i32
|
|
; CHECK-NEXT: br label [[OUTER_LOOP:%.*]]
|
|
; CHECK: outer.loop:
|
|
; CHECK-NEXT: [[IV_START:%.*]] = phi i32 [ [[SIBLING_IV_NEXT_TRUNC]], [[OUTER_LOOP_PREHEADER]] ], [ [[IV_NEXT_LCSSA:%.*]], [[OUTER_LOOP_BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: br label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_START]], [[PREHEADER]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp slt i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]]
|
|
; CHECK: signed.passed:
|
|
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV_START]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[OUTER_LOOP_BACKEDGE]]
|
|
; CHECK: outer.loop.backedge:
|
|
; CHECK-NEXT: [[IV_NEXT_LCSSA]] = phi i32 [ [[IV_NEXT]], [[BACKEDGE]] ]
|
|
; CHECK-NEXT: [[IV_LCSSA2:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ]
|
|
; CHECK-NEXT: [[OUTER_COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[OUTER_COND]], label [[OUTER_LOOP]], label [[DONE:%.*]]
|
|
; CHECK: failed.signed:
|
|
; CHECK-NEXT: call void @fail(i32 1)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.unsigned:
|
|
; CHECK-NEXT: call void @fail(i32 2)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.sibling:
|
|
; CHECK-NEXT: call void @fail(i32 3)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: done:
|
|
; CHECK-NEXT: [[IV_LCSSA2_LCSSA:%.*]] = phi i32 [ [[IV_LCSSA2]], [[OUTER_LOOP_BACKEDGE]] ]
|
|
; CHECK-NEXT: ret i32 [[IV_LCSSA2_LCSSA]]
|
|
;
|
|
entry:
|
|
%len = load i32, i32* %len.ptr, !range !0
|
|
%sibling.len = load i32, i32* %sibling.len.ptr, !range !0
|
|
%sibling.len.wide = zext i32 %sibling.len to i64
|
|
br label %sibling.loop
|
|
|
|
sibling.loop:
|
|
%sibling.iv = phi i64 [0, %entry], [%sibling.iv.next, %sibling.backedge]
|
|
%sibling.rc = icmp ult i64 %sibling.iv, %sibling.len.wide
|
|
br i1 %sibling.rc, label %sibling.backedge, label %failed.sibling
|
|
|
|
sibling.backedge:
|
|
%sibling.iv.next = add nuw nsw i64 %sibling.iv, 1
|
|
%sibling.cond = call i1 @cond()
|
|
br i1 %sibling.cond, label %sibling.loop, label %outer.loop.preheader
|
|
|
|
outer.loop.preheader:
|
|
%sibling.iv.next.trunc = trunc i64 %sibling.iv.next to i32
|
|
br label %outer.loop
|
|
|
|
outer.loop:
|
|
%iv.start = phi i32 [%sibling.iv.next.trunc, %outer.loop.preheader], [%iv.next, %outer.loop.backedge]
|
|
br label %preheader
|
|
|
|
preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [%iv.start, %preheader], [%iv.next, %backedge]
|
|
%signed.cmp = icmp slt i32 %iv, %len
|
|
br i1 %signed.cmp, label %signed.passed, label %failed.signed
|
|
|
|
signed.passed:
|
|
%unsigned.cmp = icmp ult i32 %iv, %len
|
|
br i1 %unsigned.cmp, label %backedge, label %failed.unsigned
|
|
|
|
backedge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = call i1 @cond()
|
|
br i1 %cond, label %loop, label %outer.loop.backedge
|
|
|
|
|
|
outer.loop.backedge:
|
|
%outer.cond = call i1 @cond()
|
|
br i1 %outer.cond, label %outer.loop, label %done
|
|
|
|
failed.signed:
|
|
call void @fail(i32 1)
|
|
unreachable
|
|
|
|
failed.unsigned:
|
|
call void @fail(i32 2)
|
|
unreachable
|
|
|
|
failed.sibling:
|
|
call void @fail(i32 3)
|
|
unreachable
|
|
|
|
done:
|
|
ret i32 %iv
|
|
}
|
|
|
|
|
|
; Even more complex version of previous one (more sophisticated cycled phis).
|
|
; TODO: remove unsigned comparison by proving non-negativity of iv.start.
|
|
define i32 @start.from.sibling.iv.wide.cycled.phis.complex.phis(i32* %len.ptr, i32* %sibling.len.ptr, i32 %some.random.value) {
|
|
; CHECK-LABEL: @start.from.sibling.iv.wide.cycled.phis.complex.phis(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LEN_PTR:%.*]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[SIBLING_LEN:%.*]] = load i32, i32* [[SIBLING_LEN_PTR:%.*]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[SIBLING_LEN_WIDE:%.*]] = zext i32 [[SIBLING_LEN]] to i64
|
|
; CHECK-NEXT: br label [[SIBLING_LOOP:%.*]]
|
|
; CHECK: sibling.loop:
|
|
; CHECK-NEXT: [[SIBLING_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[SIBLING_IV_NEXT:%.*]], [[SIBLING_BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIBLING_RC:%.*]] = icmp ult i64 [[SIBLING_IV]], [[SIBLING_LEN_WIDE]]
|
|
; CHECK-NEXT: br i1 [[SIBLING_RC]], label [[SIBLING_BACKEDGE]], label [[FAILED_SIBLING:%.*]]
|
|
; CHECK: sibling.backedge:
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT]] = add nuw nsw i64 [[SIBLING_IV]], 1
|
|
; CHECK-NEXT: [[SIBLING_COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[SIBLING_COND]], label [[SIBLING_LOOP]], label [[OUTER_LOOP_PREHEADER:%.*]]
|
|
; CHECK: outer.loop.preheader:
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT_LCSSA:%.*]] = phi i64 [ [[SIBLING_IV_NEXT]], [[SIBLING_BACKEDGE]] ]
|
|
; CHECK-NEXT: [[SIBLING_IV_NEXT_TRUNC:%.*]] = trunc i64 [[SIBLING_IV_NEXT_LCSSA]] to i32
|
|
; CHECK-NEXT: br label [[OUTER_LOOP:%.*]]
|
|
; CHECK: outer.loop:
|
|
; CHECK-NEXT: [[IV_START:%.*]] = phi i32 [ [[SIBLING_IV_NEXT_TRUNC]], [[OUTER_LOOP_PREHEADER]] ], [ [[IV_START_UPDATED:%.*]], [[OUTER_LOOP_BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: br label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_START]], [[PREHEADER]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[SIGNED_CMP:%.*]] = icmp slt i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[SIGNED_CMP]], label [[SIGNED_PASSED:%.*]], label [[FAILED_SIGNED:%.*]]
|
|
; CHECK: signed.passed:
|
|
; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV_START]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[OUTER_LOOP_SELECTION:%.*]]
|
|
; CHECK: outer.loop.selection:
|
|
; CHECK-NEXT: [[IV_NEXT_LCSSA:%.*]] = phi i32 [ [[IV_NEXT]], [[BACKEDGE]] ]
|
|
; CHECK-NEXT: [[IV_LCSSA2:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ]
|
|
; CHECK-NEXT: [[SWITCH_COND:%.*]] = call i32 @switch.cond()
|
|
; CHECK-NEXT: switch i32 [[SWITCH_COND]], label [[TAKE_SAME:%.*]] [
|
|
; CHECK-NEXT: i32 1, label [[TAKE_INCREMENT:%.*]]
|
|
; CHECK-NEXT: i32 2, label [[TAKE_SMAX:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: take.same:
|
|
; CHECK-NEXT: br label [[OUTER_LOOP_BACKEDGE]]
|
|
; CHECK: take.increment:
|
|
; CHECK-NEXT: br label [[OUTER_LOOP_BACKEDGE]]
|
|
; CHECK: take.smax:
|
|
; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[IV_START]], i32 [[SOME_RANDOM_VALUE:%.*]])
|
|
; CHECK-NEXT: br label [[OUTER_LOOP_BACKEDGE]]
|
|
; CHECK: outer.loop.backedge:
|
|
; CHECK-NEXT: [[IV_START_UPDATED]] = phi i32 [ [[IV_START]], [[TAKE_SAME]] ], [ [[IV_NEXT_LCSSA]], [[TAKE_INCREMENT]] ], [ [[SMAX]], [[TAKE_SMAX]] ]
|
|
; CHECK-NEXT: [[OUTER_COND:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[OUTER_COND]], label [[OUTER_LOOP]], label [[DONE:%.*]]
|
|
; CHECK: failed.signed:
|
|
; CHECK-NEXT: call void @fail(i32 1)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.unsigned:
|
|
; CHECK-NEXT: call void @fail(i32 2)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: failed.sibling:
|
|
; CHECK-NEXT: call void @fail(i32 3)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: done:
|
|
; CHECK-NEXT: [[IV_LCSSA2_LCSSA:%.*]] = phi i32 [ [[IV_LCSSA2]], [[OUTER_LOOP_BACKEDGE]] ]
|
|
; CHECK-NEXT: ret i32 [[IV_LCSSA2_LCSSA]]
|
|
;
|
|
entry:
|
|
%len = load i32, i32* %len.ptr, !range !0
|
|
%sibling.len = load i32, i32* %sibling.len.ptr, !range !0
|
|
%sibling.len.wide = zext i32 %sibling.len to i64
|
|
br label %sibling.loop
|
|
|
|
sibling.loop:
|
|
%sibling.iv = phi i64 [0, %entry], [%sibling.iv.next, %sibling.backedge]
|
|
%sibling.rc = icmp ult i64 %sibling.iv, %sibling.len.wide
|
|
br i1 %sibling.rc, label %sibling.backedge, label %failed.sibling
|
|
|
|
sibling.backedge:
|
|
%sibling.iv.next = add nuw nsw i64 %sibling.iv, 1
|
|
%sibling.cond = call i1 @cond()
|
|
br i1 %sibling.cond, label %sibling.loop, label %outer.loop.preheader
|
|
|
|
outer.loop.preheader:
|
|
%sibling.iv.next.trunc = trunc i64 %sibling.iv.next to i32
|
|
br label %outer.loop
|
|
|
|
outer.loop:
|
|
%iv.start = phi i32 [%sibling.iv.next.trunc, %outer.loop.preheader], [%iv.start.updated, %outer.loop.backedge]
|
|
br label %preheader
|
|
|
|
preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [%iv.start, %preheader], [%iv.next, %backedge]
|
|
%signed.cmp = icmp slt i32 %iv, %len
|
|
br i1 %signed.cmp, label %signed.passed, label %failed.signed
|
|
|
|
signed.passed:
|
|
%unsigned.cmp = icmp ult i32 %iv, %len
|
|
br i1 %unsigned.cmp, label %backedge, label %failed.unsigned
|
|
|
|
backedge:
|
|
%iv.next = add i32 %iv, 1
|
|
%cond = call i1 @cond()
|
|
br i1 %cond, label %loop, label %outer.loop.selection
|
|
|
|
outer.loop.selection:
|
|
%switch.cond = call i32 @switch.cond()
|
|
switch i32 %switch.cond, label %take.same
|
|
[
|
|
i32 1, label %take.increment
|
|
i32 2, label %take.smax
|
|
]
|
|
|
|
take.same:
|
|
br label %outer.loop.backedge
|
|
|
|
take.increment:
|
|
br label %outer.loop.backedge
|
|
|
|
take.smax:
|
|
%smax = call i32 @llvm.smax.i32(i32 %iv.start, i32 %some.random.value)
|
|
br label %outer.loop.backedge
|
|
|
|
outer.loop.backedge:
|
|
%iv.start.updated = phi i32 [%iv.start, %take.same],
|
|
[%iv.next, %take.increment],
|
|
[%smax, %take.smax]
|
|
%outer.cond = call i1 @cond()
|
|
br i1 %outer.cond, label %outer.loop, label %done
|
|
|
|
failed.signed:
|
|
call void @fail(i32 1)
|
|
unreachable
|
|
|
|
failed.unsigned:
|
|
call void @fail(i32 2)
|
|
unreachable
|
|
|
|
failed.sibling:
|
|
call void @fail(i32 3)
|
|
unreachable
|
|
|
|
done:
|
|
ret i32 %iv
|
|
}
|
|
|
|
!0 = !{ i32 0, i32 2147483646 }
|