[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