[llvm] 2a26d47 - [LoopBoundSplit] Check the start value of split cond AddRec

Jingu Kang via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 13 02:33:31 PDT 2021


Author: Jingu Kang
Date: 2021-09-13T10:32:35+01:00
New Revision: 2a26d47a2d8295f4555f615feb86d599ae2c3af7

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

LOG: [LoopBoundSplit] Check the start value of split cond AddRec

After transformation, we assume the split condition of the pre-loop is always
true. In order to guarantee it, we need to check the start value of the split
cond AddRec satisfies the split condition.

Differential Revision: https://reviews.llvm.org/D109354

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
    llvm/test/Transforms/LoopBoundSplit/bug51766.ll
    llvm/test/Transforms/LoopBoundSplit/loop-bound-split.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
index a89f0aa9e9e7d..00973a99737e1 100644
--- a/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
@@ -265,6 +265,15 @@ static BranchInst *findSplitCandidate(const Loop &L, ScalarEvolution &SE,
         SplitCandidateCond.BoundSCEV->getType())
       continue;
 
+    // After transformation, we assume the split condition of the pre-loop is
+    // always true. In order to guarantee it, we need to check the start value
+    // of the split cond AddRec satisfies the split condition.
+    const SCEV *SplitAddRecStartSCEV =
+        cast<SCEVAddRecExpr>(SplitCandidateCond.AddRecSCEV)->getStart();
+    if (!SE.isKnownPredicate(SplitCandidateCond.Pred, SplitAddRecStartSCEV,
+                             SplitCandidateCond.BoundSCEV))
+      continue;
+
     SplitCandidateCond.BI = BI;
     return BI;
   }

diff  --git a/llvm/test/Transforms/LoopBoundSplit/bug51766.ll b/llvm/test/Transforms/LoopBoundSplit/bug51766.ll
index a243a3da42de7..e2218a5f7cff7 100644
--- a/llvm/test/Transforms/LoopBoundSplit/bug51766.ll
+++ b/llvm/test/Transforms/LoopBoundSplit/bug51766.ll
@@ -7,16 +7,13 @@
 define i16 @main(i16 %qqq) {
 ; CHECK-LABEL: @main(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br label [[ENTRY_SPLIT:%.*]]
-; CHECK:       entry.split:
-; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i16 @llvm.umin.i16(i16 [[QQQ:%.*]], i16 2)
 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T0:%.*]] = phi i16 [ 0, [[ENTRY_SPLIT]] ], [ [[T8:%.*]], [[CONT19:%.*]] ]
+; CHECK-NEXT:    [[T0:%.*]] = phi i16 [ 0, [[ENTRY:%.*]] ], [ [[T8:%.*]], [[CONT19:%.*]] ]
 ; CHECK-NEXT:    [[T1:%.*]] = shl nuw nsw i16 [[T0]], 1
-; CHECK-NEXT:    [[T2:%.*]] = add i16 [[T1]], [[QQQ]]
+; CHECK-NEXT:    [[T2:%.*]] = add i16 [[T1]], [[QQQ:%.*]]
 ; CHECK-NEXT:    [[DOTNOT9:%.*]] = icmp ult i16 [[T2]], [[QQQ]]
-; CHECK-NEXT:    br i1 true, label [[HANDLER_POINTER_OVERFLOW:%.*]], label [[CONT15_CRITEDGE:%.*]]
+; CHECK-NEXT:    br i1 [[DOTNOT9]], label [[HANDLER_POINTER_OVERFLOW:%.*]], label [[CONT15_CRITEDGE:%.*]]
 ; CHECK:       handler.pointer_overflow:
 ; CHECK-NEXT:    call void @__ubsan_handle_pointer_overflow()
 ; CHECK-NEXT:    br label [[CONT19]]
@@ -24,31 +21,8 @@ define i16 @main(i16 %qqq) {
 ; CHECK-NEXT:    br label [[CONT19]]
 ; CHECK:       cont19:
 ; CHECK-NEXT:    [[T8]] = add nuw nsw i16 [[T0]], 1
-; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i16 [[T8]], [[NEW_BOUND]]
-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label [[ENTRY_SPLIT_SPLIT:%.*]], label [[FOR_BODY]]
-; CHECK:       entry.split.split:
-; CHECK-NEXT:    [[T8_LCSSA:%.*]] = phi i16 [ [[T8]], [[CONT19]] ]
-; CHECK-NEXT:    [[TMP0:%.*]] = icmp ne i16 [[T8_LCSSA]], 3
-; CHECK-NEXT:    br i1 [[TMP0]], label [[FOR_BODY_SPLIT_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
-; CHECK:       for.body.split.preheader:
-; CHECK-NEXT:    br label [[FOR_BODY_SPLIT:%.*]]
-; CHECK:       for.body.split:
-; CHECK-NEXT:    [[T0_SPLIT:%.*]] = phi i16 [ [[T8_SPLIT:%.*]], [[CONT19_SPLIT:%.*]] ], [ [[NEW_BOUND]], [[FOR_BODY_SPLIT_PREHEADER]] ]
-; CHECK-NEXT:    [[T1_SPLIT:%.*]] = shl nuw nsw i16 [[T0_SPLIT]], 1
-; CHECK-NEXT:    [[T2_SPLIT:%.*]] = add i16 [[T1_SPLIT]], [[QQQ]]
-; CHECK-NEXT:    [[DOTNOT9_SPLIT:%.*]] = icmp ult i16 [[T2_SPLIT]], [[QQQ]]
-; CHECK-NEXT:    br i1 false, label [[HANDLER_POINTER_OVERFLOW_SPLIT:%.*]], label [[CONT15_CRITEDGE_SPLIT:%.*]]
-; CHECK:       cont15.critedge.split:
-; CHECK-NEXT:    br label [[CONT19_SPLIT]]
-; CHECK:       handler.pointer_overflow.split:
-; CHECK-NEXT:    call void @__ubsan_handle_pointer_overflow()
-; CHECK-NEXT:    br label [[CONT19_SPLIT]]
-; CHECK:       cont19.split:
-; CHECK-NEXT:    [[T8_SPLIT]] = add nuw nsw i16 [[T0_SPLIT]], 1
-; CHECK-NEXT:    [[EXITCOND_NOT_SPLIT:%.*]] = icmp eq i16 [[T8_SPLIT]], 3
-; CHECK-NEXT:    br i1 [[EXITCOND_NOT_SPLIT]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY_SPLIT]]
-; CHECK:       for.cond.cleanup.loopexit:
-; CHECK-NEXT:    br label [[FOR_COND_CLEANUP]]
+; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i16 [[T8]], 3
+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
 ; CHECK:       for.cond.cleanup:
 ; CHECK-NEXT:    ret i16 0
 ;

diff  --git a/llvm/test/Transforms/LoopBoundSplit/loop-bound-split.ll b/llvm/test/Transforms/LoopBoundSplit/loop-bound-split.ll
index 1ad93f550e13d..eb1e3270e7708 100644
--- a/llvm/test/Transforms/LoopBoundSplit/loop-bound-split.ll
+++ b/llvm/test/Transforms/LoopBoundSplit/loop-bound-split.ll
@@ -1,17 +1,153 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt  -passes=loop-bound-split -S < %s | FileCheck %s
 
-define void @split_loop_bound_inc_with_sgt(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
-; CHECK-LABEL: @split_loop_bound_inc_with_sgt(
+; The transformation is failed with this test because we can not guarantee the
+; split condition is always true in pre-loop after transformation.
+define void @variable_split_loop_bound_and_exit_cond_inc_with_sgt(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_sgt(
+; CHECK-NEXT:  loop.ph:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4
+; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]]
+; CHECK-NEXT:    store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       if.else:
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       for.inc:
+; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
+; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i64 [[INC]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+loop.ph:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
+  %cmp = icmp ult i64 %iv, %a
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+  %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv
+  %val = load i64, i64* %src.arrayidx
+  %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv
+  store i64 %val, i64* %dst.arrayidx
+  br label %for.inc
+
+if.else:
+  br label %for.inc
+
+for.inc:
+  %inc = add nuw nsw i64 %iv, 1
+  %cond = icmp sgt i64 %inc, %n
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+; The transformation works with this test because we can guarantee the split
+; condition is always true in pre-loop after transformation.
+define void @umax_variable_split_loop_bound_and_exit_cond_inc_with_sgt(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @umax_variable_split_loop_bound_and_exit_cond_inc_with_sgt(
+; CHECK-NEXT:  loop.ph:
+; CHECK-NEXT:    [[B:%.*]] = call i64 @llvm.umax.i64(i64 [[A:%.*]], i64 1)
+; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
+; CHECK:       loop.ph.split:
+; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 0)
+; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[SMAX]], i64 [[B]])
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[B]]
+; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4
+; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]]
+; CHECK-NEXT:    store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       if.else:
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       for.inc:
+; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
+; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i64 [[INC]], [[NEW_BOUND]]
+; CHECK-NEXT:    br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]]
+; CHECK:       loop.ph.split.split:
+; CHECK-NEXT:    [[INC_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ]
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp ne i64 [[INC_LCSSA]], [[N]]
+; CHECK-NEXT:    br i1 [[TMP0]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]]
+; CHECK:       loop.split.preheader:
+; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
+; CHECK:       loop.split:
+; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[NEW_BOUND]], [[LOOP_SPLIT_PREHEADER]] ]
+; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], [[B]]
+; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
+; CHECK:       if.else.split:
+; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
+; CHECK:       if.then.split:
+; CHECK-NEXT:    [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[SRC]], i64 [[IV_SPLIT]]
+; CHECK-NEXT:    [[VAL_SPLIT:%.*]] = load i64, i64* [[SRC_ARRAYIDX_SPLIT]], align 4
+; CHECK-NEXT:    [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, i64* [[DST]], i64 [[IV_SPLIT]]
+; CHECK-NEXT:    store i64 [[VAL_SPLIT]], i64* [[DST_ARRAYIDX_SPLIT]], align 4
+; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
+; CHECK:       for.inc.split:
+; CHECK-NEXT:    [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1
+; CHECK-NEXT:    [[COND_SPLIT:%.*]] = icmp sgt i64 [[INC_SPLIT]], [[N]]
+; CHECK-NEXT:    br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]]
+; CHECK:       exit.loopexit:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+loop.ph:
+  %b = call i64 @llvm.umax.i64(i64 %a, i64 1)
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
+  %cmp = icmp ult i64 %iv, %b
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+  %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv
+  %val = load i64, i64* %src.arrayidx
+  %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv
+  store i64 %val, i64* %dst.arrayidx
+  br label %for.inc
+
+if.else:
+  br label %for.inc
+
+for.inc:
+  %inc = add nuw nsw i64 %iv, 1
+  %cond = icmp sgt i64 %inc, %n
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+; The transformation works with this test because we can guarantee the split
+; condition is always true in pre-loop after transformation.
+define void @constant_split_loop_bound_and_exit_cond_inc_with_sgt(i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_sgt(
 ; CHECK-NEXT:  loop.ph:
 ; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
 ; CHECK:       loop.ph.split:
 ; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 0)
-; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[A:%.*]], i64 [[SMAX]])
+; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[SMAX]], i64 10)
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[IV]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
 ; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
@@ -33,7 +169,7 @@ define void @split_loop_bound_inc_with_sgt(i64 %a, i64* noalias %src, i64* noali
 ; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
 ; CHECK:       loop.split:
 ; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[NEW_BOUND]], [[LOOP_SPLIT_PREHEADER]] ]
-; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp slt i64 [[IV_SPLIT]], [[A]]
+; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
 ; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
 ; CHECK:       if.else.split:
 ; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
@@ -57,7 +193,7 @@ loop.ph:
 
 loop:
   %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
-  %cmp = icmp slt i64 %iv, %a
+  %cmp = icmp ult i64 %iv, 10
   br i1 %cmp, label %if.then, label %if.else
 
 if.then:
@@ -79,17 +215,67 @@ exit:
   ret void
 }
 
-define void @split_loop_bound_inc_with_eq(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
-; CHECK-LABEL: @split_loop_bound_inc_with_eq(
+define void @variable_split_loop_bound_and_exit_cond_inc_with_eq(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_eq(
+; CHECK-NEXT:  loop.ph:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4
+; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]]
+; CHECK-NEXT:    store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       if.else:
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       for.inc:
+; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[INC]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+loop.ph:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
+  %cmp = icmp ult i64 %iv, %a
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+  %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv
+  %val = load i64, i64* %src.arrayidx
+  %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv
+  store i64 %val, i64* %dst.arrayidx
+  br label %for.inc
+
+if.else:
+  br label %for.inc
+
+for.inc:
+  %inc = add nuw nsw i64 %iv, 1
+  %cond = icmp eq i64 %inc, %n
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @constant_split_loop_bound_and_exit_cond_inc_with_eq(i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_eq(
 ; CHECK-NEXT:  loop.ph:
 ; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
 ; CHECK:       loop.ph.split:
 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[N:%.*]], -1
-; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.umin.i64(i64 [[A:%.*]], i64 [[TMP0]])
+; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP0]], i64 10)
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[IV]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
 ; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
@@ -111,7 +297,7 @@ define void @split_loop_bound_inc_with_eq(i64 %a, i64* noalias %src, i64* noalia
 ; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
 ; CHECK:       loop.split:
 ; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[NEW_BOUND]], [[LOOP_SPLIT_PREHEADER]] ]
-; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp slt i64 [[IV_SPLIT]], [[A]]
+; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
 ; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
 ; CHECK:       if.else.split:
 ; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
@@ -135,7 +321,7 @@ loop.ph:
 
 loop:
   %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
-  %cmp = icmp slt i64 %iv, %a
+  %cmp = icmp ult i64 %iv, 10
   br i1 %cmp, label %if.then, label %if.else
 
 if.then:
@@ -157,18 +343,68 @@ exit:
   ret void
 }
 
-define void @split_loop_bound_inc_with_sge(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
-; CHECK-LABEL: @split_loop_bound_inc_with_sge(
+define void @variable_split_loop_bound_and_exit_cond_inc_with_sge(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_sge(
+; CHECK-NEXT:  loop.ph:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4
+; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]]
+; CHECK-NEXT:    store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       if.else:
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       for.inc:
+; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
+; CHECK-NEXT:    [[COND:%.*]] = icmp sge i64 [[INC]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+loop.ph:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
+  %cmp = icmp ult i64 %iv, %a
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+  %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv
+  %val = load i64, i64* %src.arrayidx
+  %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv
+  store i64 %val, i64* %dst.arrayidx
+  br label %for.inc
+
+if.else:
+  br label %for.inc
+
+for.inc:
+  %inc = add nuw nsw i64 %iv, 1
+  %cond = icmp sge i64 %inc, %n
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @constant_split_loop_bound_and_exit_cond_inc_with_sge(i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_sge(
 ; CHECK-NEXT:  loop.ph:
 ; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
 ; CHECK:       loop.ph.split:
 ; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 1)
 ; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i64 [[SMAX]], -1
-; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[A:%.*]], i64 [[TMP0]])
+; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[TMP0]], i64 10)
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[IV]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
 ; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
@@ -190,7 +426,7 @@ define void @split_loop_bound_inc_with_sge(i64 %a, i64* noalias %src, i64* noali
 ; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
 ; CHECK:       loop.split:
 ; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[NEW_BOUND]], [[LOOP_SPLIT_PREHEADER]] ]
-; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp slt i64 [[IV_SPLIT]], [[A]]
+; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
 ; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
 ; CHECK:       if.else.split:
 ; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
@@ -214,7 +450,7 @@ loop.ph:
 
 loop:
   %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
-  %cmp = icmp slt i64 %iv, %a
+  %cmp = icmp ult i64 %iv, 10
   br i1 %cmp, label %if.then, label %if.else
 
 if.then:
@@ -236,18 +472,68 @@ exit:
   ret void
 }
 
-define void @split_loop_bound_inc_with_step_is_not_one(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
-; CHECK-LABEL: @split_loop_bound_inc_with_step_is_not_one(
+define void @variable_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(
+; CHECK-NEXT:  loop.ph:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4
+; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]]
+; CHECK-NEXT:    store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       if.else:
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       for.inc:
+; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 2
+; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i64 [[INC]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+loop.ph:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
+  %cmp = icmp ult i64 %iv, %a
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+  %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv
+  %val = load i64, i64* %src.arrayidx
+  %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv
+  store i64 %val, i64* %dst.arrayidx
+  br label %for.inc
+
+if.else:
+  br label %for.inc
+
+for.inc:
+  %inc = add nuw nsw i64 %iv, 2
+  %cond = icmp sgt i64 %inc, %n
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @constant_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(
 ; CHECK-NEXT:  loop.ph:
 ; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
 ; CHECK:       loop.ph.split:
 ; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 1)
 ; CHECK-NEXT:    [[TMP0:%.*]] = lshr i64 [[SMAX]], 1
-; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[A:%.*]], i64 [[TMP0]])
+; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[TMP0]], i64 10)
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[IV]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
 ; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
@@ -269,7 +555,7 @@ define void @split_loop_bound_inc_with_step_is_not_one(i64 %a, i64* noalias %src
 ; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
 ; CHECK:       loop.split:
 ; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[NEW_BOUND]], [[LOOP_SPLIT_PREHEADER]] ]
-; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp slt i64 [[IV_SPLIT]], [[A]]
+; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
 ; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
 ; CHECK:       if.else.split:
 ; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
@@ -293,7 +579,7 @@ loop.ph:
 
 loop:
   %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
-  %cmp = icmp slt i64 %iv, %a
+  %cmp = icmp ult i64 %iv, 10
   br i1 %cmp, label %if.then, label %if.else
 
 if.then:
@@ -315,13 +601,13 @@ exit:
   ret void
 }
 
-define void @split_loop_bound_inc_with_ne(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
-; CHECK-LABEL: @split_loop_bound_inc_with_ne(
+define void @variable_split_loop_bound_and_exit_cond_inc_with_ne(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_ne(
 ; CHECK-NEXT:  loop.ph:
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[IV]], [[A:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_INC]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
@@ -341,7 +627,7 @@ loop.ph:
 
 loop:
   %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
-  %cmp = icmp slt i64 %iv, %a
+  %cmp = icmp ult i64 %iv, %a
   br i1 %cmp, label %if.then, label %for.inc
 
 if.then:
@@ -360,13 +646,103 @@ exit:
   ret void
 }
 
-define void @split_loop_bound_dec_with_slt(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
-; CHECK-LABEL: @split_loop_bound_dec_with_slt(
+define void @constant_split_loop_bound_and_exit_cond_inc_with_ne(i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_ne(
+; CHECK-NEXT:  loop.ph:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_INC]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4
+; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]]
+; CHECK-NEXT:    store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4
+; CHECK-NEXT:    br label [[FOR_INC]]
+; CHECK:       for.inc:
+; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
+; CHECK-NEXT:    [[COND:%.*]] = icmp ne i64 [[INC]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+loop.ph:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
+  %cmp = icmp ult i64 %iv, 10
+  br i1 %cmp, label %if.then, label %for.inc
+
+if.then:
+  %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv
+  %val = load i64, i64* %src.arrayidx
+  %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv
+  store i64 %val, i64* %dst.arrayidx
+  br label %for.inc
+
+for.inc:
+  %inc = add nuw nsw i64 %iv, 1
+  %cond = icmp ne i64 %inc, %n
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @varialbe_split_loop_bound_and_exit_cond_dec_with_slt(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @varialbe_split_loop_bound_and_exit_cond_dec_with_slt(
+; CHECK-NEXT:  loop.ph:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4
+; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]]
+; CHECK-NEXT:    store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4
+; CHECK-NEXT:    br label [[FOR_DEC]]
+; CHECK:       for.dec:
+; CHECK-NEXT:    [[DEC]] = sub nuw nsw i64 [[IV]], 1
+; CHECK-NEXT:    [[COND:%.*]] = icmp slt i64 [[DEC]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+loop.ph:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ]
+  %cmp = icmp ult i64 %iv, %a
+  br i1 %cmp, label %if.then, label %for.dec
+
+if.then:
+  %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv
+  %val = load i64, i64* %src.arrayidx
+  %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv
+  store i64 %val, i64* %dst.arrayidx
+  br label %for.dec
+
+for.dec:
+  %dec = sub nuw nsw i64 %iv, 1
+  %cond = icmp slt i64 %dec, %n
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @constant_split_loop_bound_and_exit_cond_dec_with_slt(i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_dec_with_slt(
 ; CHECK-NEXT:  loop.ph:
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[IV]], [[A:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
@@ -386,7 +762,7 @@ loop.ph:
 
 loop:
   %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ]
-  %cmp = icmp slt i64 %iv, %a
+  %cmp = icmp ult i64 %iv, 10
   br i1 %cmp, label %if.then, label %for.dec
 
 if.then:
@@ -405,13 +781,58 @@ exit:
   ret void
 }
 
-define void @split_loop_bound_dec_with_sle(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
-; CHECK-LABEL: @split_loop_bound_dec_with_sle(
+define void @variable_split_loop_bound_and_exit_cond_dec_with_sle(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_dec_with_sle(
+; CHECK-NEXT:  loop.ph:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, i64* [[SRC_ARRAYIDX]], align 4
+; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[DST:%.*]], i64 [[IV]]
+; CHECK-NEXT:    store i64 [[VAL]], i64* [[DST_ARRAYIDX]], align 4
+; CHECK-NEXT:    br label [[FOR_DEC]]
+; CHECK:       for.dec:
+; CHECK-NEXT:    [[DEC]] = sub nuw nsw i64 [[IV]], 1
+; CHECK-NEXT:    [[COND:%.*]] = icmp sle i64 [[DEC]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+loop.ph:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ]
+  %cmp = icmp ult i64 %iv, %a
+  br i1 %cmp, label %if.then, label %for.dec
+
+if.then:
+  %src.arrayidx = getelementptr inbounds i64, i64* %src, i64 %iv
+  %val = load i64, i64* %src.arrayidx
+  %dst.arrayidx = getelementptr inbounds i64, i64* %dst, i64 %iv
+  store i64 %val, i64* %dst.arrayidx
+  br label %for.dec
+
+for.dec:
+  %dec = sub nuw nsw i64 %iv, 1
+  %cond = icmp sle i64 %dec, %n
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @constant_split_loop_bound_and_exit_cond_dec_with_sle(i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_dec_with_sle(
 ; CHECK-NEXT:  loop.ph:
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[IV]], [[A:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
@@ -431,7 +852,7 @@ loop.ph:
 
 loop:
   %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ]
-  %cmp = icmp slt i64 %iv, %a
+  %cmp = icmp ult i64 %iv, 10
   br i1 %cmp, label %if.then, label %for.dec
 
 if.then:
@@ -451,18 +872,18 @@ exit:
 }
 
 ; LoopBoundSplit pass should ignore phi which is not scevable phi.
-define void @split_loop_bound_inc_with_sgt_and_is_not_scevable_phi(i64 %a, i64* noalias %src, i64* noalias %dst, i64 %n) {
-; CHECK-LABEL: @split_loop_bound_inc_with_sgt_and_is_not_scevable_phi(
+define void @constant_split_loop_bound_and_exit_cond_inc_with_sgt_and_is_not_scevable_phi(i64* noalias %src, i64* noalias %dst, i64 %n) {
+; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_sgt_and_is_not_scevable_phi(
 ; CHECK-NEXT:  loop.ph:
 ; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
 ; CHECK:       loop.ph.split:
 ; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 0)
-; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[A:%.*]], i64 [[SMAX]])
+; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[SMAX]], i64 10)
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IS_NOT_SCEVABLE_PHI:%.*]] = phi double [ 1.000000e+00, [[FOR_INC:%.*]] ], [ 2.000000e+00, [[LOOP_PH_SPLIT]] ]
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC]] ], [ 0, [[LOOP_PH_SPLIT]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[IV]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
 ; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[SRC:%.*]], i64 [[IV]]
@@ -485,7 +906,7 @@ define void @split_loop_bound_inc_with_sgt_and_is_not_scevable_phi(i64 %a, i64*
 ; CHECK:       loop.split:
 ; CHECK-NEXT:    [[IS_NOT_SCEVABLE_PHI_SPLIT:%.*]] = phi double [ 1.000000e+00, [[FOR_INC_SPLIT:%.*]] ], [ 2.000000e+00, [[LOOP_SPLIT_PREHEADER]] ]
 ; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT]] ], [ [[NEW_BOUND]], [[LOOP_SPLIT_PREHEADER]] ]
-; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp slt i64 [[IV_SPLIT]], [[A]]
+; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
 ; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
 ; CHECK:       if.else.split:
 ; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
@@ -510,7 +931,7 @@ loop.ph:
 loop:
   %is_not_scevable_phi = phi double [ 1.0, %for.inc ], [ 2.0, %loop.ph ]
   %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
-  %cmp = icmp slt i64 %iv, %a
+  %cmp = icmp ult i64 %iv, 10
   br i1 %cmp, label %if.then, label %if.else
 
 if.then:
@@ -532,3 +953,4 @@ exit:
   ret void
 }
 
+declare i64 @llvm.umax.i64(i64, i64)


        


More information about the llvm-commits mailing list