; 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 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 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 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. 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]], [[LEN]] ; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[IV_NEXT]] = add 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]], [[LEN]] ; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[IV_NEXT]] = add 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 }