This reverts commit 354fa0b480.
Returning as is. The patch was reverted due to a miscompile, but
this patch is not causing it. This patch made it possible to infer
some nuw flags in code guarded by `false` condition, and then someone
else to managed to propagate the flag from dead code outside.
Returning the patch to be able to reproduce the issue.
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 }
|