[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