[llvm] b4466bc - [Test] Add some tests showing missing opportunities in IndVars

Max Kazantsev via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 7 08:24:41 PDT 2022


Author: Max Kazantsev
Date: 2022-07-07T22:24:30+07:00
New Revision: b4466bcd68d6556906e8076a4a170f90bb6e238c

URL: https://github.com/llvm/llvm-project/commit/b4466bcd68d6556906e8076a4a170f90bb6e238c
DIFF: https://github.com/llvm/llvm-project/commit/b4466bcd68d6556906e8076a4a170f90bb6e238c.diff

LOG: [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.

Added: 
    llvm/test/Transforms/IndVarSimplify/cycled_phis.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/IndVarSimplify/cycled_phis.ll b/llvm/test/Transforms/IndVarSimplify/cycled_phis.ll
new file mode 100644
index 0000000000000..d6ea253f2a674
--- /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 }


        


More information about the llvm-commits mailing list