[llvm] [IndVars] Use context for proving same sign (PR #181093)

via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 11 22:53:25 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: Max Kazantsev (xortator)

<details>
<summary>Changes</summary>

IndVars already uses context to prove other facts around this place.
This patch takes its advantage to prove same sign of comparison
operands and infer unsigned predicate/samesign flag.

---

Patch is 24.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/181093.diff


13 Files Affected:

- (modified) llvm/include/llvm/Analysis/ScalarEvolution.h (+5) 
- (modified) llvm/lib/Analysis/ScalarEvolution.cpp (+14) 
- (modified) llvm/lib/Transforms/Utils/SimplifyIndVar.cpp (+1-1) 
- (modified) llvm/test/Transforms/IndVarSimplify/canonicalize-cmp.ll (+2-2) 
- (modified) llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll (+4-2) 
- (modified) llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll (+1-1) 
- (modified) llvm/test/Transforms/IndVarSimplify/eliminate-overflow-modified.ll (+17-1) 
- (modified) llvm/test/Transforms/IndVarSimplify/guards.ll (+2-2) 
- (modified) llvm/test/Transforms/IndVarSimplify/lftr-promote.ll (+1-1) 
- (modified) llvm/test/Transforms/IndVarSimplify/lrev-existing-umin.ll (+1-1) 
- (modified) llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll (+5-5) 
- (modified) llvm/test/Transforms/IndVarSimplify/rewrite-loop-exit-value.ll (+2-2) 
- (added) llvm/test/Transforms/IndVarSimplify/samesign-signed-comparison.ll (+209) 


``````````diff
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index 6aff53a1e7b70..4a5d53008abfd 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -1091,6 +1091,11 @@ class ScalarEvolution {
   /// Return true if we know that S1 and S2 must have the same sign.
   LLVM_ABI bool haveSameSign(const SCEV *S1, const SCEV *S2);
 
+  /// Return true if we know that \p S1 and \p S2 must have the same sign in the
+  /// context of \p CtxI.
+  LLVM_ABI bool haveSameSignAt(const SCEV *S1, const SCEV *S2,
+                               const Instruction *CtxI);
+
   /// Splits SCEV expression \p S into two SCEVs. One of them is obtained from
   /// \p S by substitution of all AddRec sub-expression related to loop \p L
   /// with initial value of that SCEV. The second is obtained from \p S by
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 45f1b543b8fc7..75fd0e8568189 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -11185,6 +11185,20 @@ bool ScalarEvolution::haveSameSign(const SCEV *S1, const SCEV *S2) {
           (isKnownNegative(S1) && isKnownNegative(S2)));
 }
 
+bool ScalarEvolution::haveSameSignAt(const SCEV *S1, const SCEV *S2,
+                                     const Instruction *CtxI) {
+  auto IsKnownNonNegative = [this, CtxI](const SCEV *S) {
+    return isKnownPredicateAt(ICmpInst::ICMP_SGE, S, getZero(S->getType()),
+                              CtxI);
+  };
+  auto IsKnownNegative = [this, CtxI](const SCEV *S) {
+    return isKnownPredicateAt(ICmpInst::ICMP_SLT, S, getZero(S->getType()),
+                              CtxI);
+  };
+  return ((IsKnownNonNegative(S1) && IsKnownNonNegative(S2)) ||
+          (IsKnownNegative(S1) && IsKnownNegative(S2)));
+}
+
 std::pair<const SCEV *, const SCEV *>
 ScalarEvolution::SplitIntoInitAndPostInc(const Loop *L, const SCEV *S) {
   // Compute SCEV on entry of loop L.
diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
index 792c1ac31c2ba..fc60886d0615a 100644
--- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
@@ -290,7 +290,7 @@ void SimplifyIndvar::eliminateIVComparison(ICmpInst *ICmp,
 
   if ((ICmpInst::isSigned(OriginalPred) ||
        (ICmpInst::isUnsigned(OriginalPred) && !ICmp->hasSameSign())) &&
-      SE->haveSameSign(S, X)) {
+      SE->haveSameSignAt(S, X, CtxI)) {
     // Set the samesign flag on the compare if legal, and canonicalize to
     // the unsigned variant (for signed compares) hoping that it will open
     // the doors for other optimizations.  Note that we cannot rely on Pred
diff --git a/llvm/test/Transforms/IndVarSimplify/canonicalize-cmp.ll b/llvm/test/Transforms/IndVarSimplify/canonicalize-cmp.ll
index 6ac09fafcb7a4..d9114a5e31c7d 100644
--- a/llvm/test/Transforms/IndVarSimplify/canonicalize-cmp.ll
+++ b/llvm/test/Transforms/IndVarSimplify/canonicalize-cmp.ll
@@ -151,7 +151,7 @@ define i32 @test_03(ptr %p, ptr %capacity_p, ptr %num_elements_p) {
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
 ; CHECK-NEXT:    [[BYTES_TO_WRITE:%.*]] = sub nuw nsw i32 [[CAPACITY]], [[IV]]
-; CHECK-NEXT:    [[CAPACITY_CHECK:%.*]] = icmp slt i32 [[BYTES_TO_WRITE]], 4
+; CHECK-NEXT:    [[CAPACITY_CHECK:%.*]] = icmp samesign ult i32 [[BYTES_TO_WRITE]], 4
 ; CHECK-NEXT:    br i1 [[CAPACITY_CHECK]], label [[OUT_OF_BOUNDS:%.*]], label [[BACKEDGE]]
 ; CHECK:       backedge:
 ; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
@@ -199,7 +199,7 @@ define i32 @test_04(ptr %p, ptr %capacity_p, ptr %num_elements_p) {
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
 ; CHECK-NEXT:    [[BYTES_TO_WRITE:%.*]] = sub nuw nsw i32 [[CAPACITY]], [[IV]]
-; CHECK-NEXT:    [[CAPACITY_CHECK:%.*]] = icmp sle i32 [[BYTES_TO_WRITE]], 3
+; CHECK-NEXT:    [[CAPACITY_CHECK:%.*]] = icmp samesign ule i32 [[BYTES_TO_WRITE]], 3
 ; CHECK-NEXT:    br i1 [[CAPACITY_CHECK]], label [[OUT_OF_BOUNDS:%.*]], label [[BACKEDGE]]
 ; CHECK:       backedge:
 ; CHECK-NEXT:    [[EL_PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[IV]]
diff --git a/llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll b/llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll
index 08f9856ac603d..31f01c0eb3a9d 100644
--- a/llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll
+++ b/llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll
@@ -827,11 +827,13 @@ define void @func_22(ptr %length.ptr) {
 ; CHECK-NEXT:    [[ENTRY_COND:%.*]] = icmp sgt i32 [[LENGTH]], 1
 ; CHECK-NEXT:    br i1 [[ENTRY_COND]], label [[LOOP_PREHEADER:%.*]], label [[LEAVE:%.*]]
 ; CHECK:       loop.preheader:
+; CHECK-NEXT:    [[TMP0:%.*]] = add nuw nsw i32 [[LENGTH]], 1
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[IV_INC:%.*]], [[BE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
 ; CHECK-NEXT:    [[IV_INC]] = add nuw nsw i32 [[IV]], 1
-; CHECK-NEXT:    br i1 true, label [[BE]], label [[LEAVE_LOOPEXIT:%.*]]
+; CHECK-NEXT:    [[EXITCOND1:%.*]] = icmp ne i32 [[IV]], [[TMP0]]
+; CHECK-NEXT:    br i1 [[EXITCOND1]], label [[BE]], label [[LEAVE_LOOPEXIT:%.*]]
 ; CHECK:       be:
 ; CHECK-NEXT:    call void @side_effect()
 ; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV_INC]], [[LENGTH]]
@@ -917,7 +919,7 @@ define void @func_24(ptr %init.ptr) {
 ; CHECK-NEXT:    br i1 true, label [[BE]], label [[LEAVE_LOOPEXIT:%.*]]
 ; CHECK:       be:
 ; CHECK-NEXT:    call void @side_effect()
-; CHECK-NEXT:    [[BE_COND:%.*]] = icmp sgt i32 [[IV_DEC]], 4
+; CHECK-NEXT:    [[BE_COND:%.*]] = icmp samesign ugt i32 [[IV_DEC]], 4
 ; CHECK-NEXT:    br i1 [[BE_COND]], label [[LOOP]], label [[LEAVE_LOOPEXIT]]
 ; CHECK:       leave.loopexit:
 ; CHECK-NEXT:    br label [[LEAVE]]
diff --git a/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll b/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll
index b20891d2f9ed8..b3cbee8475344 100644
--- a/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll
+++ b/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll
@@ -161,7 +161,7 @@ define void @ult_const_max(i64 %n) {
 ; CHECK-NEXT:    br i1 true, label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
 ; CHECK:       latch:
 ; CHECK-NEXT:    call void @side_effect()
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i64 [[IV]], [[N]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp samesign ult i64 [[IV]], [[N]]
 ; CHECK-NEXT:    br i1 [[CMP2]], label [[LOOP]], label [[EXIT_LOOPEXIT]]
 ; CHECK:       exit.loopexit:
 ; CHECK-NEXT:    br label [[EXIT]]
diff --git a/llvm/test/Transforms/IndVarSimplify/eliminate-overflow-modified.ll b/llvm/test/Transforms/IndVarSimplify/eliminate-overflow-modified.ll
index b91c1aeaa7128..15990b4a29b90 100644
--- a/llvm/test/Transforms/IndVarSimplify/eliminate-overflow-modified.ll
+++ b/llvm/test/Transforms/IndVarSimplify/eliminate-overflow-modified.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt < %s -passes=indvars -S -o - | FileCheck %s
 
 ; When eliminating the overflow intrinsic the indvars pass would incorrectly
@@ -8,10 +9,25 @@
 ; CHECK-NEXT: %0 = phi i16 [ %1, %for.body ], [ undef, %for.body.preheader ]
 ; CHECK-NEXT: %1 = add nsw i16 %0, -1
 ; CHECK-NEXT: %cmp = icmp sgt i16 %1, 0
-; CHECK-NEXT:  call void @llvm.assume(i1 %cmp)
 
 ; Function Attrs: nounwind
 define void @foo() #0 {
+; CHECK-LABEL: define void @foo(
+; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i16 undef, 0
+; CHECK-NEXT:    br i1 [[CMP1]], label %[[FOR_BODY_PREHEADER:.*]], label %[[FOR_END:.*]]
+; CHECK:       [[FOR_BODY_PREHEADER]]:
+; CHECK-NEXT:    br label %[[FOR_BODY:.*]]
+; CHECK:       [[FOR_BODY]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = phi i16 [ [[TMP1:%.*]], %[[FOR_BODY]] ], [ undef, %[[FOR_BODY_PREHEADER]] ]
+; CHECK-NEXT:    [[TMP1]] = add nsw i16 [[TMP0]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i16 [[TMP1]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    br label %[[FOR_BODY]]
+; CHECK:       [[FOR_END]]:
+; CHECK-NEXT:    ret void
+;
 entry:
   %cmp1 = icmp sgt i16 undef, 0
   br i1 %cmp1, label %for.body.preheader, label %for.end
diff --git a/llvm/test/Transforms/IndVarSimplify/guards.ll b/llvm/test/Transforms/IndVarSimplify/guards.ll
index 431b4b189ca60..07726cb75bb6d 100644
--- a/llvm/test/Transforms/IndVarSimplify/guards.ll
+++ b/llvm/test/Transforms/IndVarSimplify/guards.ll
@@ -106,7 +106,7 @@ define void @test_3(ptr %cond_buf, ptr %len_buf) {
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[LOOP]] ]
 ; CHECK-NEXT:    [[IV_INC]] = add nsw i32 [[IV]], 1
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
-; CHECK-NEXT:    [[IV_INC_CMP:%.*]] = icmp slt i32 [[IV_INC]], [[LEN]]
+; CHECK-NEXT:    [[IV_INC_CMP:%.*]] = icmp samesign ult i32 [[IV_INC]], [[LEN]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[IV_INC_CMP]]) [ "deopt"() ]
 ; CHECK-NEXT:    [[BECOND:%.*]] = load volatile i1, ptr [[COND_BUF]], align 1
 ; CHECK-NEXT:    br i1 [[BECOND]], label [[LOOP]], label [[LEAVE:%.*]]
@@ -155,7 +155,7 @@ define void @test_4(ptr %cond_buf, ptr %len_buf) {
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[IV_INC_CMP]]) [ "deopt"() ]
 ; CHECK-NEXT:    br label [[BE]]
 ; CHECK:       be:
-; CHECK-NEXT:    [[IV_CMP:%.*]] = icmp slt i32 [[IV]], [[LEN]]
+; CHECK-NEXT:    [[IV_CMP:%.*]] = icmp samesign ult i32 [[IV]], [[LEN]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[IV_CMP]]) [ "deopt"() ]
 ; CHECK-NEXT:    [[BECOND:%.*]] = load volatile i1, ptr [[COND_BUF]], align 1
 ; CHECK-NEXT:    br i1 [[BECOND]], label [[LOOP]], label [[LEAVE:%.*]]
diff --git a/llvm/test/Transforms/IndVarSimplify/lftr-promote.ll b/llvm/test/Transforms/IndVarSimplify/lftr-promote.ll
index 037662db9baca..418c6c5578554 100644
--- a/llvm/test/Transforms/IndVarSimplify/lftr-promote.ll
+++ b/llvm/test/Transforms/IndVarSimplify/lftr-promote.ll
@@ -26,7 +26,7 @@ define void @foo(ptr %p, i32 %n) nounwind {
 ; CHECK-NEXT:    [[TMP7]] = add nuw nsw i32 [[I_01]], 1
 ; CHECK-NEXT:    br label [[BB3]]
 ; CHECK:       bb3:
-; CHECK-NEXT:    [[TMP8:%.*]] = icmp slt i32 [[TMP7]], [[N]]
+; CHECK-NEXT:    [[TMP8:%.*]] = icmp samesign ult i32 [[TMP7]], [[N]]
 ; CHECK-NEXT:    br i1 [[TMP8]], label [[BB2]], label [[BB3_RETURN_CRIT_EDGE:%.*]]
 ; CHECK:       bb3.return_crit_edge:
 ; CHECK-NEXT:    br label [[RETURN]]
diff --git a/llvm/test/Transforms/IndVarSimplify/lrev-existing-umin.ll b/llvm/test/Transforms/IndVarSimplify/lrev-existing-umin.ll
index 305ecb9ffe756..cf0abf6ca736d 100644
--- a/llvm/test/Transforms/IndVarSimplify/lrev-existing-umin.ll
+++ b/llvm/test/Transforms/IndVarSimplify/lrev-existing-umin.ll
@@ -23,7 +23,7 @@ define void @f(i32 %length.i.88, i32 %length.i, ptr %tmp12, i32 %tmp10, ptr %tmp
 ; CHECK-NEXT:    [[ADDR22:%.*]] = getelementptr inbounds i8, ptr [[TMP12:%.*]], i64 [[TMP16]]
 ; CHECK-NEXT:    store i8 [[TMP21]], ptr [[ADDR22]], align 1
 ; CHECK-NEXT:    [[TMP22]] = add nuw nsw i32 [[V_1]], 1
-; CHECK-NEXT:    [[TMP23:%.*]] = icmp slt i32 [[TMP22]], [[TMP14]]
+; CHECK-NEXT:    [[TMP23:%.*]] = icmp samesign ult i32 [[TMP22]], [[TMP14]]
 ; CHECK-NEXT:    br i1 [[TMP23]], label [[NOT_ZERO11]], label [[MAIN_EXIT_SELECTOR:%.*]]
 ; CHECK:       main.exit.selector:
 ; CHECK-NEXT:    [[TMP22_LCSSA:%.*]] = phi i32 [ [[TMP22]], [[NOT_ZERO11]] ]
diff --git a/llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll b/llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll
index 3f0ada281b1e3..f67e2670adaf6 100644
--- a/llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll
+++ b/llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll
@@ -196,8 +196,8 @@ define void @promote_latch_condition_decrementing_loop_01(ptr %p, ptr %a) {
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ [[TMP0]], [[PREHEADER]] ]
 ; CHECK-NEXT:    [[EL:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[INDVARS_IV]]
 ; CHECK-NEXT:    store atomic i32 0, ptr [[EL]] unordered, align 4
+; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp samesign ult i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
-; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp slt i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    br i1 [[LOOPCOND]], label [[LOOPEXIT_LOOPEXIT:%.*]], label [[LOOP]]
 ;
 
@@ -240,8 +240,8 @@ define void @promote_latch_condition_decrementing_loop_02(ptr %p, ptr %a) {
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ [[TMP0]], [[PREHEADER]] ]
 ; CHECK-NEXT:    [[EL:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[INDVARS_IV]]
 ; CHECK-NEXT:    store atomic i32 0, ptr [[EL]] unordered, align 4
+; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp samesign ult i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
-; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp slt i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    br i1 [[LOOPCOND]], label [[LOOPEXIT_LOOPEXIT:%.*]], label [[LOOP]]
 ;
 
@@ -284,8 +284,8 @@ define void @promote_latch_condition_decrementing_loop_03(ptr %p, ptr %a) {
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ [[TMP1]], [[PREHEADER]] ]
 ; CHECK-NEXT:    [[EL:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[INDVARS_IV]]
 ; CHECK-NEXT:    store atomic i32 0, ptr [[EL]] unordered, align 4
+; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp samesign ult i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
-; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp slt i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    br i1 [[LOOPCOND]], label [[LOOPEXIT_LOOPEXIT:%.*]], label [[LOOP]]
 ;
 
@@ -336,8 +336,8 @@ define void @promote_latch_condition_decrementing_loop_04(ptr %p, ptr %a, i1 %co
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ [[TMP0]], [[PREHEADER]] ]
 ; CHECK-NEXT:    [[EL:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[INDVARS_IV]]
 ; CHECK-NEXT:    store atomic i32 0, ptr [[EL]] unordered, align 4
+; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp samesign ult i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
-; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp slt i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    br i1 [[LOOPCOND]], label [[LOOPEXIT_LOOPEXIT:%.*]], label [[LOOP]]
 ;
 
@@ -398,8 +398,8 @@ define void @promote_latch_condition_decrementing_loop_05(ptr %p, ptr %a, i1 %co
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ [[TMP0]], [[PREHEADER]] ]
 ; CHECK-NEXT:    [[EL:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[INDVARS_IV]]
 ; CHECK-NEXT:    store atomic i32 0, ptr [[EL]] unordered, align 4
+; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp samesign ult i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
-; CHECK-NEXT:    [[LOOPCOND:%.*]] = icmp slt i64 [[INDVARS_IV]], 1
 ; CHECK-NEXT:    br i1 [[LOOPCOND]], label [[LOOPEXIT_LOOPEXIT:%.*]], label [[LOOP]]
 ;
 
diff --git a/llvm/test/Transforms/IndVarSimplify/rewrite-loop-exit-value.ll b/llvm/test/Transforms/IndVarSimplify/rewrite-loop-exit-value.ll
index fa47d06d859e9..43cbdaf2ed00b 100644
--- a/llvm/test/Transforms/IndVarSimplify/rewrite-loop-exit-value.ll
+++ b/llvm/test/Transforms/IndVarSimplify/rewrite-loop-exit-value.ll
@@ -214,7 +214,7 @@ define i32 @vscale_slt_with_vp_umin(ptr nocapture %A, i32 %n) mustprogress vscal
 ; CHECK-NEXT:    [[VF_CAPPED:%.*]] = call i32 @llvm.umin.i32(i32 [[VF]], i32 [[LEFT]])
 ; CHECK-NEXT:    store i32 [[VF_CAPPED]], ptr [[A:%.*]], align 4
 ; CHECK-NEXT:    [[ADD]] = add nuw nsw i32 [[I_05]], [[VF]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD]], [[N]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ult i32 [[ADD]], [[N]]
 ; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
 ; CHECK:       for.end:
 ; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i32 [[N]], -1
@@ -267,7 +267,7 @@ define i32 @vscale_slt_with_vp_umin2(ptr nocapture %A, i32 %n) mustprogress vsca
 ; CHECK-NEXT:    [[VF_CAPPED:%.*]] = call i32 @llvm.umin.i32(i32 [[VF]], i32 [[LEFT]])
 ; CHECK-NEXT:    store i32 [[VF_CAPPED]], ptr [[A:%.*]], align 4
 ; CHECK-NEXT:    [[ADD]] = add nuw nsw i32 [[I_05]], [[VF]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD]], [[N]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ult i32 [[ADD]], [[N]]
 ; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
 ; CHECK:       for.end:
 ; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[N]], -1
diff --git a/llvm/test/Transforms/IndVarSimplify/samesign-signed-comparison.ll b/llvm/test/Transforms/IndVarSimplify/samesign-signed-comparison.ll
new file mode 100644
index 0000000000000..be6d93907c103
--- /dev/null
+++ b/llvm/test/Transforms/IndVarSimplify/samesign-signed-comparison.ll
@@ -0,0 +1,209 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=indvars -S < %s | FileCheck %s
+
+; Make sure that IV starting from zero turns to unsigned.
+define i32 @test_01(i32 %start, i32 %end, ptr %p) {
+; CHECK-LABEL: define i32 @test_01(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[END:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
+; CHECK-NEXT:    br i1 true, label %[[CHECKED:.*]], label %[[BAD:.*]]
+; CHECK:       [[CHECKED]]:
+; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0:![0-9]+]], !invariant.load [[META1:![0-9]+]], !noundef [[META1]]
+; CHECK-NEXT:    [[CMP_S:%.*]] = icmp samesign ult i32 [[I]], [[LEN]]
+; CHECK-NEXT:    br i1 [[CMP_S]], label %[[BACKEDGE]], label %[[BAD]]
+; CHECK:       [[BACKEDGE]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[I]], 1
+; CHECK-NEXT:    [[LOOP_COND:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label %[[LOOP]], label %[[GOOD:.*]]
+; CHECK:       [[GOOD]]:
+; CHECK-NEXT:    ret i32 42
+; CHECK:       [[BAD]]:
+; CHECK-NEXT:    ret i32 -1
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i32 [0, %entry], [%iv.next, %backedge]
+  %cond_i = icmp sge i32 %i, 0
+  br i1 %cond_i, label %checked, label %bad
+
+checked:
+  %len = load i32, ptr %p, align 4, !invariant.load !0, !noundef !0, !range !1
+  %cmp_s = icmp slt i32 %i, %len
+  br i1 %cmp_s, label %backedge, label %bad
+
+backedge:
+  %iv.next = add i32 %i, 1
+  %loop_cond = call i1 @cond()
+  br i1 %loop_cond, label %loop, label %good
+
+good:
+  ret i32 42
+
+bad:
+  ret i32 -1
+}
+
+; Make sure that IV starting from zero turns to unsigned even if comparison is a part of AND.
+define i32 @test_02(i32 %start, i32 %end, ptr %p) {
+; CHECK-LABEL: define i32 @test_02(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[END:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
+; CHECK-NEXT:    br i1 true, label %[[CHECKED:.*]], label %[[BAD:.*]]
+; CHECK:       [[CHECKED]]:
+; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0]], !invariant.load [[META1]], !noundef [[META1]]
+; CHECK-NEXT:    [[CMP_S:%.*]] = icmp samesign ult i32 [[I]], [[LEN]]
+; CHECK-NEXT:    [[CMP_U:%.*]] = icmp samesign ult i32 [[I]], [[LEN]]
+; CHECK-NEXT:    [[CMP_BOTH:%.*]] = and i1 [[CMP_S]], [[CMP_U]]
+; CHECK-NEXT:    br i1 [[CMP_BOTH]], label %[[BACKEDGE]], label %[[BAD]]
+; CHECK:       [[BACKEDGE]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[I]], 1
+; CHECK-NEXT:    [[LOOP_COND:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label %[[LOOP]], label %[[GOOD:.*]]
+; CHECK:       [[GOOD]]:
+; CHECK-NEXT:    ret i32 42
+; CHECK:       [[BAD]]:
+; CHECK-NEXT:    ret i32 -1
+;
+entry:
+  br label %loop
+
+loop:
+  %i = phi i32 [0, %entry], [%iv.next, ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/181093


More information about the llvm-commits mailing list