[llvm] 6162f6e - [ConstraintElim] Add additional monotonic phi tests.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 10 13:43:52 PDT 2023


Author: Florian Hahn
Date: 2023-06-10T21:43:06+01:00
New Revision: 6162f6e9ff64b911fc4957430290a50fded11270

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

LOG: [ConstraintElim] Add additional monotonic phi tests.

Add extra test coverage with cases that showed mis-compiles in earlier
versions of an upcoming patch. Also add tests for integer phis

Added: 
    llvm/test/Transforms/ConstraintElimination/monotonic-int-phis.ll
    llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
    llvm/test/Transforms/PhaseOrdering/runtime-check-removal.ll

Modified: 
    

Removed: 
    llvm/test/Transforms/ConstraintElimination/monotonic-phis.ll


################################################################################
diff  --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis.ll
new file mode 100644
index 0000000000000..5c27cde68b950
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis.ll
@@ -0,0 +1,210 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+
+declare void @use(i16)
+declare void @llvm.assume(i1)
+
+define void @test_monotonic_ptr_iv_inc_1_eq_to_uge(i8 %len.n, i16 %a) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_inc_1_eq_to_uge(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN:%.*]] = zext i8 [[LEN_N:%.*]] to i16
+; CHECK-NEXT:    [[LEN_NEG:%.*]] = icmp uge i16 [[LEN]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 0, [[LOOP_PH]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i16 [[IV]], [[LEN]]
+; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i16 [[IV]], 0
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ult i16 [[IV]], [[A]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(i16 [[IV]])
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i16 [[IV]], 1
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %len = zext i8 %len.n to i16
+  %len.neg = icmp uge i16 %len, %a
+  br i1 %len.neg, label %exit, label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i16 [ 0, %loop.ph ], [ %iv.next, %loop.latch ]
+  %c = icmp eq i16 %iv, %len
+  br i1 %c, label %exit, label %for.body
+
+for.body:
+  %t.1 = icmp uge i16 %iv, 0
+  %t.2 = icmp ult i16 %iv, %a
+  %and = and i1 %t.1, %t.2
+  br i1 %and, label %loop.latch, label %exit
+
+loop.latch:
+  call void @use(i16 %iv)
+  %iv.next = add nuw nsw i16 %iv, 1
+  br label %loop.header
+
+exit:
+  ret void
+}
+
+define void @test_remove_check_with_incrementing_integer_induction(i8 %len.n, i16 %a) {
+; CHECK-LABEL: @test_remove_check_with_incrementing_integer_induction(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN:%.*]] = zext i8 [[LEN_N:%.*]] to i16
+; CHECK-NEXT:    [[LEN_NEG_NOT:%.*]] = icmp ult i16 [[LEN]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[LEN_NEG_NOT]], label [[LOOP_HEADER:%.*]], label [[EXIT:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i16 [[IV]], [[LEN]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ult i16 [[IV]], [[A]]
+; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[C]], [[T_2]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[LOOP_LATCH]], label [[EXIT]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(i16 [[IV]])
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i16 [[IV]], 1
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %len = zext i8 %len.n to i16
+  %len.neg.not = icmp ult i16 %len, %a
+  br i1 %len.neg.not, label %loop.header, label %exit
+
+loop.header:                                      ; preds = %entry, %loop.latch
+  %iv = phi i16 [ %iv.next, %loop.latch ], [ 0, %entry ]
+  %c = icmp ne i16 %iv, %len
+  %t.2 = icmp ult i16 %iv, %a
+  %or.cond = and i1 %c, %t.2
+  br i1 %or.cond, label %loop.latch, label %exit
+
+loop.latch:                                       ; preds = %loop.header
+  call void @use(i16 %iv)
+  %iv.next = add nuw nsw i16 %iv, 1
+  br label %loop.header
+
+exit:                                             ; preds = %loop.header, %entry
+  ret void
+}
+
+define void @test_monotonic_ptr_iv_inc_2_eq_to_uge(i8 %len.n, i16 %a) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_inc_2_eq_to_uge(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN:%.*]] = zext i8 [[LEN_N:%.*]] to i16
+; CHECK-NEXT:    [[LEN_LT:%.*]] = icmp ult i16 [[LEN]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[LEN_LT]], label [[LOOP_PH:%.*]], label [[EXIT:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 0, [[LOOP_PH]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i16 [[IV]], [[LEN]]
+; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i16 [[IV]], 0
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ult i16 [[IV]], [[A]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(i16 [[IV]])
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw i16 [[IV]], 2
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %len = zext i8 %len.n to i16
+  %len.lt = icmp ult i16 %len, %a
+  br i1 %len.lt, label %loop.ph, label %exit
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i16 [ 0, %loop.ph ], [ %iv.next, %loop.latch ]
+  %c = icmp eq i16 %iv, %len
+  br i1 %c, label %exit, label %for.body
+
+for.body:
+  %t.1 = icmp uge i16 %iv, 0
+  %t.2 = icmp ult i16 %iv, %a
+  %and = and i1 %t.1, %t.2
+  br i1 %and, label %loop.latch, label %exit
+
+loop.latch:
+  call void @use(i16 %iv)
+  %iv.next = add nuw i16 %iv, 2
+  br label %loop.header
+
+exit:
+  ret void
+}
+
+define void @test_monotonic_ptr_iv_inc_2_eq_to_uge_variable_start(i16 %start, i8 %len.n, i16 %a) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_inc_2_eq_to_uge_variable_start(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN:%.*]] = zext i8 [[LEN_N:%.*]] to i16
+; CHECK-NEXT:    [[LEN_LT:%.*]] = icmp ult i16 [[LEN]], [[A:%.*]]
+; CHECK-NEXT:    [[START_LT:%.*]] = icmp ult i16 [[START:%.*]], [[LEN]]
+; CHECK-NEXT:    [[AND_0:%.*]] = and i1 [[LEN_LT]], [[START_LT]]
+; CHECK-NEXT:    br i1 [[AND_0]], label [[LOOP_PH:%.*]], label [[EXIT:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ [[START]], [[LOOP_PH]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i16 [[IV]], [[LEN]]
+; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i16 [[IV]], 0
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ult i16 [[IV]], [[A]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(i16 [[IV]])
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw i16 [[IV]], 2
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %len = zext i8 %len.n to i16
+  %len.lt = icmp ult i16 %len, %a
+  %start.lt = icmp ult i16 %start, %len
+  %and.0 = and i1 %len.lt, %start.lt
+  br i1 %and.0, label %loop.ph, label %exit
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i16 [ %start, %loop.ph ], [ %iv.next, %loop.latch ]
+  %c = icmp eq i16 %iv, %len
+  br i1 %c, label %exit, label %for.body
+
+for.body:
+  %t.1 = icmp uge i16 %iv, 0
+  %t.2 = icmp ult i16 %iv, %a
+  %and = and i1 %t.1, %t.2
+  br i1 %and, label %loop.latch, label %exit
+
+loop.latch:
+  call void @use(i16 %iv)
+  %iv.next = add nuw i16 %iv, 2
+  br label %loop.header
+
+exit:
+  ret void
+}
+
+

diff  --git a/llvm/test/Transforms/ConstraintElimination/monotonic-phis.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
similarity index 54%
rename from llvm/test/Transforms/ConstraintElimination/monotonic-phis.ll
rename to llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
index cc76bb9897fa4..12fba6b15ea8b 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-phis.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
@@ -5,7 +5,9 @@ target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16
 
 
 declare void @use(ptr)
+declare void @use.i1(i1)
 declare void @llvm.assume(i1)
+declare i1 @cond()
 
 define void @test_monotonic_ptr_iv_inc_1_eq_to_uge(ptr %start, i16 %len) {
 ; CHECK-LABEL: @test_monotonic_ptr_iv_inc_1_eq_to_uge(
@@ -168,9 +170,9 @@ define void @test_ptr_iv_upper_may_be_less_than_start(ptr %start, i16 %len) {
 ; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C]], label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
-; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -189,9 +191,9 @@ loop.header:
   br i1 %c, label %exit, label %for.body
 
 for.body:
-  %t.1 = icmp uge ptr %ptr.iv, %start
-  %t.2 = icmp ult ptr %ptr.iv, %upper
-  %and = and i1 %t.1, %t.2
+  %c.1 = icmp uge ptr %ptr.iv, %start
+  %c.2 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.1, %c.2
   br i1 %and, label %loop.latch, label %exit
 
 loop.latch:
@@ -268,9 +270,9 @@ define void @test_no_ptr_iv_
diff erent_start(ptr %start, ptr %p, i16 %len) {
 ; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
-; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -293,9 +295,9 @@ loop.header:
   br i1 %c, label %exit, label %for.body
 
 for.body:
-  %t.1 = icmp uge ptr %ptr.iv, %start
-  %t.2 = icmp ult ptr %ptr.iv, %upper
-  %and = and i1 %t.1, %t.2
+  %c.1 = icmp uge ptr %ptr.iv, %start
+  %c.2 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.1, %c.2
   br i1 %and, label %loop.latch, label %exit
 
 loop.latch:
@@ -320,9 +322,9 @@ define void @test_ptr_iv_not_inbounds(ptr %start, i16 %len) {
 ; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
-; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -345,9 +347,9 @@ loop.header:
   br i1 %c, label %exit, label %for.body
 
 for.body:
-  %t.1 = icmp uge ptr %ptr.iv, %start
-  %t.2 = icmp ult ptr %ptr.iv, %upper
-  %and = and i1 %t.1, %t.2
+  %c.1 = icmp uge ptr %ptr.iv, %start
+  %c.2 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.1, %c.2
   br i1 %and, label %loop.latch, label %exit
 
 loop.latch:
@@ -372,9 +374,9 @@ define void @test_var_step_not_monotonic(ptr %start, i16 %len, i16 %step) {
 ; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
-; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -397,9 +399,9 @@ loop.header:
   br i1 %c, label %exit, label %for.body
 
 for.body:
-  %t.1 = icmp uge ptr %ptr.iv, %start
-  %t.2 = icmp ult ptr %ptr.iv, %upper
-  %and = and i1 %t.1, %t.2
+  %c.1 = icmp uge ptr %ptr.iv, %start
+  %c.2 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.1, %c.2
   br i1 %and, label %loop.latch, label %exit
 
 loop.latch:
@@ -424,9 +426,9 @@ define void @test_monotonic_ptr_iv_step_neg_1(ptr %start, i16 %len) {
 ; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
-; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -449,9 +451,9 @@ loop.header:
   br i1 %c, label %exit, label %for.body
 
 for.body:
-  %t.1 = icmp uge ptr %ptr.iv, %start
-  %t.2 = icmp ult ptr %ptr.iv, %upper
-  %and = and i1 %t.1, %t.2
+  %c.1 = icmp uge ptr %ptr.iv, %start
+  %c.2 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.1, %c.2
   br i1 %and, label %loop.latch, label %exit
 
 loop.latch:
@@ -476,9 +478,9 @@ define void @test_monotonic_ptr_iv_step_sign_unknown(ptr %start, i16 %len, i16 %
 ; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
-; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -501,9 +503,9 @@ loop.header:
   br i1 %c, label %exit, label %for.body
 
 for.body:
-  %t.1 = icmp uge ptr %ptr.iv, %start
-  %t.2 = icmp ult ptr %ptr.iv, %upper
-  %and = and i1 %t.1, %t.2
+  %c.1 = icmp uge ptr %ptr.iv, %start
+  %c.2 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.1, %c.2
   br i1 %and, label %loop.latch, label %exit
 
 loop.latch:
@@ -571,6 +573,69 @@ exit:
   ret void
 }
 
+define void @test_monotonic_ptr_iv_step_sign_positive_through_assume_multi_exit(ptr %start, i16 %len, i16 %step) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_step_sign_positive_through_assume_multi_exit(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[STEP_POS:%.*]] = icmp sge i16 [[STEP:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[STEP_POS]])
+; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]]
+; CHECK-NEXT:    [[LEN_NEG:%.*]] = icmp slt i16 [[LEN]], 0
+; CHECK-NEXT:    br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[C_1:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[EXIT]]
+; CHECK:       then:
+; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
+; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 [[STEP]]
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %step.pos = icmp sge i16 %step, 0
+  call void @llvm.assume(i1 %step.pos)
+  %upper = getelementptr inbounds i32, ptr %start, i16 %len
+  %len.neg = icmp slt i16 %len, 0
+  br i1 %len.neg, label %exit, label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ]
+  %c = icmp eq ptr %ptr.iv, %upper
+  br i1 %c, label %exit, label %for.body
+
+for.body:
+  %c.1 = call i1 @cond()
+  br i1 %c.1, label %then, label %exit
+
+then:
+  %c.2 = icmp uge ptr %ptr.iv, %start
+  %c.3 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.2, %c.3
+  br i1 %and, label %loop.latch, label %exit
+
+loop.latch:
+  call void @use(ptr %ptr.iv)
+  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 %step
+  br label %loop.header
+
+exit:
+  ret void
+}
+
 define void @test_monotonic_ptr_iv_step_sign_negative_through_assume(ptr %start, i16 %len, i16 %step) {
 ; CHECK-LABEL: @test_monotonic_ptr_iv_step_sign_negative_through_assume(
 ; CHECK-NEXT:  entry:
@@ -586,9 +651,9 @@ define void @test_monotonic_ptr_iv_step_sign_negative_through_assume(ptr %start,
 ; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
-; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -612,6 +677,181 @@ loop.header:
   %c = icmp eq ptr %ptr.iv, %upper
   br i1 %c, label %exit, label %for.body
 
+for.body:
+  %c.1 = icmp uge ptr %ptr.iv, %start
+  %c.2 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.1, %c.2
+  br i1 %and, label %loop.latch, label %exit
+
+loop.latch:
+  call void @use(ptr %ptr.iv)
+  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 %step
+  br label %loop.header
+
+exit:
+  ret void
+}
+
+define void @test_monotonic_ptr_iv_cond_doesnt_control_exit(ptr %start, i16 %len) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_cond_doesnt_control_exit(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]]
+; CHECK-NEXT:    [[LEN_NEG:%.*]] = icmp slt i16 [[LEN]], 0
+; CHECK-NEXT:    br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[C_0]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
+; CHECK:       then:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
+; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 1
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %upper = getelementptr inbounds i32, ptr %start, i16 %len
+  %len.neg = icmp slt i16 %len, 0
+  br i1 %len.neg, label %exit, label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ]
+  %c.0 = call i1 @cond()
+  br i1 %c.0, label %exit, label %for.body
+
+for.body:
+  %c.1 = icmp ne ptr %ptr.iv, %upper
+  br i1 %c.1, label %then, label %loop.latch
+
+then:
+  %t.1 = icmp uge ptr %ptr.iv, %start
+  %t.2 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %t.1, %t.2
+  call void @use.i1(i1 %and)
+  br label %loop.latch
+
+loop.latch:
+  call void @use(ptr %ptr.iv)
+  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 1
+  br label %loop.header
+
+exit:
+  ret void
+}
+
+
+define void @test_monotonic_ptr_iv_cond_doesnt_dominate_checks(ptr %start, i16 %len) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_cond_doesnt_dominate_checks(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]]
+; CHECK-NEXT:    [[LEN_NEG:%.*]] = icmp slt i16 [[LEN]], 0
+; CHECK-NEXT:    br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[C_0]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
+; CHECK:       then:
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
+; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
+; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 1
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %upper = getelementptr inbounds i32, ptr %start, i16 %len
+  %len.neg = icmp slt i16 %len, 0
+  br i1 %len.neg, label %exit, label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ]
+  %c.0 = call i1 @cond()
+  br i1 %c.0, label %exit, label %for.body
+
+for.body:
+  %c.1 = icmp ne ptr %ptr.iv, %upper
+  br i1 %c.1, label %then, label %loop.latch
+
+then:
+  br label %loop.latch
+
+loop.latch:
+  %c.2 = icmp uge ptr %ptr.iv, %start
+  %c.3 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.2, %c.3
+  call void @use.i1(i1 %and)
+  call void @use(ptr %ptr.iv)
+  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 1
+  br label %loop.header
+
+exit:
+  ret void
+}
+
+define void @test_monotonic_ptr_iv_inc_2(ptr %start, i16 %len) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_inc_2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]]
+; CHECK-NEXT:    [[LEN_NEG:%.*]] = icmp slt i16 [[LEN]], 0
+; CHECK-NEXT:    br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    br i1 [[C]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
+; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 2
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %upper = getelementptr inbounds i32, ptr %start, i16 %len
+  %len.neg = icmp slt i16 %len, 0
+  br i1 %len.neg, label %exit, label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ]
+  %c = icmp eq ptr %ptr.iv, %upper
+  br i1 %c, label %exit, label %for.body
+
 for.body:
   %t.1 = icmp uge ptr %ptr.iv, %start
   %t.2 = icmp ult ptr %ptr.iv, %upper
@@ -620,9 +860,249 @@ for.body:
 
 loop.latch:
   call void @use(ptr %ptr.iv)
-  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 %step
+  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 2
   br label %loop.header
 
 exit:
   ret void
 }
+
+define void @test_monotonic_ptr_iv_step_2_multi_exit(ptr %start, i16 %len) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_step_2_multi_exit(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]]
+; CHECK-NEXT:    [[LEN_NEG:%.*]] = icmp slt i16 [[LEN]], 0
+; CHECK-NEXT:    br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    br i1 [[C_1]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[C_0:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[C_0]], label [[EXIT]], label [[THEN:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
+; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 2
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %upper = getelementptr inbounds i32, ptr %start, i16 %len
+  %len.neg = icmp slt i16 %len, 0
+  br i1 %len.neg, label %exit, label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ]
+  %c.1 = icmp eq ptr %ptr.iv, %upper
+  br i1 %c.1, label %exit, label %for.body
+
+for.body:
+  %c.0 = call i1 @cond()
+  br i1 %c.0, label %exit, label %then
+
+then:
+  %c.2 = icmp uge ptr %ptr.iv, %start
+  %c.3 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.2, %c.3
+  call void @use.i1(i1 %and)
+  br label %loop.latch
+
+loop.latch:
+  call void @use(ptr %ptr.iv)
+  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 2
+  br label %loop.header
+
+exit:
+  ret void
+}
+
+define void @test_monotonic_ptr_iv_step_2_cond_controls_single_exit(ptr %start, i16 %len) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_step_2_cond_controls_single_exit(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]]
+; CHECK-NEXT:    [[LEN_NEG:%.*]] = icmp slt i16 [[LEN]], 0
+; CHECK-NEXT:    br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    br i1 [[C_1]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
+; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 2
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %upper = getelementptr inbounds i32, ptr %start, i16 %len
+  %len.neg = icmp slt i16 %len, 0
+  br i1 %len.neg, label %exit, label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ]
+  %c.1 = icmp eq ptr %ptr.iv, %upper
+  br i1 %c.1, label %exit, label %for.body
+
+for.body:
+  %t.1 = icmp uge ptr %ptr.iv, %start
+  %t.2 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %t.1, %t.2
+  call void @use.i1(i1 %and)
+  br label %loop.latch
+
+loop.latch:
+  call void @use(ptr %ptr.iv)
+  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 2
+  br label %loop.header
+
+exit:
+  ret void
+}
+
+define void @test_monotonic_ptr_iv_step_2_cond_doesnt_control_exit(ptr %start, i16 %len) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_step_2_cond_doesnt_control_exit(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]]
+; CHECK-NEXT:    [[LEN_NEG:%.*]] = icmp slt i16 [[LEN]], 0
+; CHECK-NEXT:    br i1 [[LEN_NEG]], label [[EXIT:%.*]], label [[LOOP_PH:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[C_0]], label [[EXIT]], label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
+; CHECK:       then:
+; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
+; CHECK-NEXT:    br label [[LOOP_LATCH]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
+; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 2
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %upper = getelementptr inbounds i32, ptr %start, i16 %len
+  %len.neg = icmp slt i16 %len, 0
+  br i1 %len.neg, label %exit, label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ]
+  %c.0 = call i1 @cond()
+  br i1 %c.0, label %exit, label %for.body
+
+for.body:
+  %c.1 = icmp ne ptr %ptr.iv, %upper
+  br i1 %c.1, label %then, label %loop.latch
+
+then:
+  %c.2 = icmp uge ptr %ptr.iv, %start
+  %c.3 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.2, %c.3
+  call void @use.i1(i1 %and)
+  br label %loop.latch
+
+loop.latch:
+  call void @use(ptr %ptr.iv)
+  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 2
+  br label %loop.header
+
+exit:
+  ret void
+}
+
+
+define void @test_monotonic_ptr_iv_inc_1_check_outside_loop(ptr %start, i16 %len) {
+; CHECK-LABEL: @test_monotonic_ptr_iv_inc_1_check_outside_loop(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, ptr [[START:%.*]], i16 [[LEN:%.*]]
+; CHECK-NEXT:    [[LEN_NEG:%.*]] = icmp sge i16 [[LEN]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[LEN_NEG]])
+; CHECK-NEXT:    br label [[LOOP_PH:%.*]]
+; CHECK:       loop.ph:
+; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
+; CHECK:       loop.header:
+; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[START]], [[LOOP_PH]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[C_0]], label [[EXIT:%.*]], label [[LOOP_LATCH]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
+; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 1
+; CHECK-NEXT:    br label [[LOOP_HEADER]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[EXIT_2:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
+; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
+; CHECK-NEXT:    br label [[EXIT_2]]
+; CHECK:       exit.2:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %upper = getelementptr inbounds i32, ptr %start, i16 %len
+  %len.neg = icmp sge i16 %len, 0
+  call void @llvm.assume(i1 %len.neg)
+  br label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %ptr.iv = phi ptr [ %start, %loop.ph ], [ %ptr.iv.next, %loop.latch ]
+  %c.0 = call i1 @cond()
+  br i1 %c.0, label %exit, label %loop.latch
+
+loop.latch:
+  call void @use(ptr %ptr.iv)
+  %ptr.iv.next = getelementptr inbounds i32, ptr %ptr.iv, i16 1
+  br label %loop.header
+
+exit:
+  %c.1 = icmp ne ptr %ptr.iv, %upper
+  br i1 %c.1, label %then, label %exit.2
+
+then:
+  %c.2 = icmp uge ptr %ptr.iv, %start
+  %c.3 = icmp ult ptr %ptr.iv, %upper
+  %and = and i1 %c.2, %c.3
+  call void @use.i1(i1 %and)
+  br label %exit.2
+
+exit.2:
+  ret void
+}

diff  --git a/llvm/test/Transforms/PhaseOrdering/runtime-check-removal.ll b/llvm/test/Transforms/PhaseOrdering/runtime-check-removal.ll
new file mode 100644
index 0000000000000..c159d1b686787
--- /dev/null
+++ b/llvm/test/Transforms/PhaseOrdering/runtime-check-removal.ll
@@ -0,0 +1,58 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes='default<Os>' -S %s | FileCheck %s
+
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+
+declare void @use(i16)
+
+define void @test_remove_check_with_incrementing_integer_induction(i16 %start, i8 %len.n, i16 %a) {
+; CHECK-LABEL: @test_remove_check_with_incrementing_integer_induction(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN:%.*]] = zext i8 [[LEN_N:%.*]] to i16
+; CHECK-NEXT:    [[LEN_NEG_NOT:%.*]] = icmp ult i16 [[LEN]], [[A:%.*]]
+; CHECK-NEXT:    [[C1:%.*]] = icmp ne i8 [[LEN_N]], 0
+; CHECK-NEXT:    [[OR_COND3:%.*]] = and i1 [[LEN_NEG_NOT]], [[C1]]
+; CHECK-NEXT:    br i1 [[OR_COND3]], label [[LOOP_LATCH_PREHEADER:%.*]], label [[EXIT:%.*]]
+; CHECK:       loop.latch.preheader:
+; CHECK-NEXT:    [[TMP0:%.*]] = add i16 [[A]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i16 [[LEN]], -1
+; CHECK-NEXT:    [[UMIN:%.*]] = tail call i16 @llvm.umin.i16(i16 [[TMP0]], i16 [[TMP1]])
+; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
+; CHECK:       loop.latch:
+; CHECK-NEXT:    [[IV2:%.*]] = phi i16 [ [[IV_NEXT:%.*]], [[LOOP_LATCH]] ], [ 0, [[LOOP_LATCH_PREHEADER]] ]
+; CHECK-NEXT:    tail call void @use(i16 [[IV2]])
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i16 [[IV2]], 1
+; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i16 [[IV2]], [[UMIN]]
+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label [[EXIT]], label [[LOOP_LATCH]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %len = zext i8 %len.n to i16
+  %upper = add nuw nsw i16 %start, %len
+  %len.neg = icmp uge i16 %len, %a
+  br i1 %len.neg, label %exit, label %loop.ph
+
+loop.ph:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i16 [ 0, %loop.ph ], [ %iv.next, %loop.latch ]
+  %c = icmp eq i16 %iv, %len
+  br i1 %c, label %exit, label %for.body
+
+for.body:
+  %t.1 = icmp uge i16 %iv, 0
+  %t.2 = icmp ult i16 %iv, %a
+  %and = and i1 %t.1, %t.2
+  br i1 %and, label %loop.latch, label %exit
+
+loop.latch:
+  call void @use(i16 %iv)
+  %iv.next = add nuw nsw i16 %iv, 1
+  br label %loop.header
+
+exit:
+  ret void
+}


        


More information about the llvm-commits mailing list