From: Max Kazantsev Date: Thu, 7 Jul 2022 15:23:14 +0000 (+0700) Subject: [Test] Add some tests showing missing opportunities in IndVars X-Git-Tag: upstream/15.0.7~2434 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b4466bcd68d6556906e8076a4a170f90bb6e238c;p=platform%2Fupstream%2Fllvm.git [Test] Add some tests showing missing opportunities in IndVars The general idea of these tests is elimination of signed and unsigned comparison of the same values through proving non-negativity of them. Here are some examples where SCEV is not smart enough to prove it. --- diff --git a/llvm/test/Transforms/IndVarSimplify/cycled_phis.ll b/llvm/test/Transforms/IndVarSimplify/cycled_phis.ll new file mode 100644 index 0000000..d6ea253 --- /dev/null +++ b/llvm/test/Transforms/IndVarSimplify/cycled_phis.ll @@ -0,0 +1,525 @@ +; 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_SIGNED]] +; 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_LCSSA1:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ] +; CHECK-NEXT: ret i32 [[IV_LCSSA1]] +; +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.signed + +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_SIGNED]] +; 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_LCSSA1:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ] +; CHECK-NEXT: ret i32 [[IV_LCSSA1]] +; +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.signed + +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_SIGNED]] +; 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_LCSSA1:%.*]] = phi i32 [ [[IV]], [[BACKEDGE]] ] +; CHECK-NEXT: ret i32 [[IV_LCSSA1]] +; +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.signed + +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_SIGNED]] +; 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_LCSSA1:%.*]] = 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_LCSSA1_LCSSA:%.*]] = phi i32 [ [[IV_LCSSA1]], [[OUTER_LOOP_BACKEDGE]] ] +; CHECK-NEXT: ret i32 [[IV_LCSSA1_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.signed + +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_SIGNED]] +; 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_LCSSA1:%.*]] = 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_LCSSA1_LCSSA:%.*]] = phi i32 [ [[IV_LCSSA1]], [[OUTER_LOOP_BACKEDGE]] ] +; CHECK-NEXT: ret i32 [[IV_LCSSA1_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.signed + +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 }