[llvm] [SCEV] Discard samesign when analyzing loop invariant exits (PR #181171)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 13 01:51:42 PST 2026


https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/181171

>From cbdff19d4f2609eccb06461dd68ff66385a4690f Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Thu, 12 Feb 2026 16:46:13 +0100
Subject: [PATCH 1/3] Add test

---
 .../IndVarSimplify/turn-to-invariant.ll       | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll b/llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
index d3a5d4c443cb9..dca53a7a7c7e2 100644
--- a/llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
+++ b/llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
@@ -1059,3 +1059,47 @@ exit:
 failed:
   ret i32 -1
 }
+
+; PR180870: %range_check1 here cannot be made invariant.
+define i32 @not_invariant_samesign(i32 %unknown_limit, ptr %length_ptr) {
+; CHECK-LABEL: @not_invariant_samesign(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[RANGE_CHECK1_FIRST_ITER:%.*]] = icmp ult i32 2, [[UNKNOWN_LIMIT:%.*]]
+; CHECK-NEXT:    br label [[HEADER:%.*]]
+; CHECK:       header:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw i32 [[IV]], 1
+; CHECK-NEXT:    [[IS_POSITIVE:%.*]] = icmp sgt i32 [[UNKNOWN_LIMIT]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[RANGE_CHECK1_FIRST_ITER]], [[IS_POSITIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[LATCH]], label [[RET:%.*]]
+; CHECK:       latch:
+; CHECK-NEXT:    [[IV_PREV:%.*]] = add nsw i32 [[IV]], -1
+; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_PTR:%.*]], align 4, !range [[RNG0:![0-9]+]]
+; CHECK-NEXT:    [[RANGE_CHECK2:%.*]] = icmp samesign ult i32 [[IV_PREV]], [[LENGTH]]
+; CHECK-NEXT:    br i1 [[RANGE_CHECK2]], label [[HEADER]], label [[RET]]
+; CHECK:       ret:
+; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LATCH]] ], [ [[IV]], [[HEADER]] ]
+; CHECK-NEXT:    ret i32 [[IV_LCSSA]]
+;
+entry:
+  br label %header
+
+header:                                           ; preds = %latch, %entry
+  %iv = phi i32 [ 1, %entry ], [ %iv.next, %latch ]
+  %iv.next = add i32 %iv, 1
+  %range_check1 = icmp samesign ult i32 %iv.next, %unknown_limit
+  %is_positive = icmp sgt i32 %unknown_limit, 0
+  %or.cond = and i1 %range_check1, %is_positive
+  br i1 %or.cond, label %latch, label %ret
+
+latch:                                            ; preds = %header
+  %iv.prev = add i32 %iv, -1
+  %length = load i32, ptr %length_ptr, align 4, !range !0
+  %range_check2 = icmp ult i32 %iv.prev, %length
+  br i1 %range_check2, label %header, label %ret
+
+ret:                                              ; preds = %latch, %header
+  ret i32 %iv
+}
+
+!0 = !{i32 0, i32 2147483647}

>From b6661f99d7e7144b31b44a544f5f1b2339951872 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Thu, 12 Feb 2026 16:54:04 +0100
Subject: [PATCH 2/3] Drop samesign flag

---
 llvm/lib/Analysis/ScalarEvolution.cpp                    | 5 +++++
 llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 45f1b543b8fc7..1a8f36968adde 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -11496,6 +11496,11 @@ ScalarEvolution::getLoopInvariantExitCondDuringFirstIterationsImpl(
   if (!AR || AR->getLoop() != L)
     return std::nullopt;
 
+  // Even if both are valid, we need to consistently chose the unsigned or the
+  // signed predicate below, not mixtures of both. For now, prefer the unsigned
+  // predicate.
+  Pred = Pred.dropSameSign();
+
   // The predicate must be relational (i.e. <, <=, >=, >).
   if (!ICmpInst::isRelational(Pred))
     return std::nullopt;
diff --git a/llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll b/llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
index dca53a7a7c7e2..c013c91900fee 100644
--- a/llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
+++ b/llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
@@ -1064,11 +1064,11 @@ failed:
 define i32 @not_invariant_samesign(i32 %unknown_limit, ptr %length_ptr) {
 ; CHECK-LABEL: @not_invariant_samesign(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[RANGE_CHECK1_FIRST_ITER:%.*]] = icmp ult i32 2, [[UNKNOWN_LIMIT:%.*]]
 ; CHECK-NEXT:    br label [[HEADER:%.*]]
 ; CHECK:       header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw i32 [[IV]], 1
+; CHECK-NEXT:    [[RANGE_CHECK1_FIRST_ITER:%.*]] = icmp samesign ult i32 [[IV_NEXT]], [[UNKNOWN_LIMIT:%.*]]
 ; CHECK-NEXT:    [[IS_POSITIVE:%.*]] = icmp sgt i32 [[UNKNOWN_LIMIT]], 0
 ; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[RANGE_CHECK1_FIRST_ITER]], [[IS_POSITIVE]]
 ; CHECK-NEXT:    br i1 [[OR_COND]], label [[LATCH]], label [[RET:%.*]]

>From d2f6678d0695468815e3a19eb5128539c7a297d8 Mon Sep 17 00:00:00 2001
From: Nikita Popov <github at npopov.com>
Date: Fri, 13 Feb 2026 10:51:33 +0100
Subject: [PATCH 3/3] Apply suggestion

Co-authored-by: Ramkumar Ramachandra <r at artagnon.com>
---
 llvm/lib/Analysis/ScalarEvolution.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 1a8f36968adde..ae9ce311ec08f 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -11531,7 +11531,7 @@ ScalarEvolution::getLoopInvariantExitCondDuringFirstIterationsImpl(
   ICmpInst::Predicate NoOverflowPred =
       CmpInst::isSigned(Pred) ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE;
   if (Step == MinusOne)
-    NoOverflowPred = ICmpInst::getSwappedCmpPredicate(NoOverflowPred);
+    NoOverflowPred = ICmpInst::getSwappedPredicate(NoOverflowPred);
   const SCEV *Start = AR->getStart();
   if (!isKnownPredicateAt(NoOverflowPred, Start, Last, CtxI))
     return std::nullopt;



More information about the llvm-commits mailing list