[llvm] [SCEV] Clamp End instead of bailing out when using the ceiling division. (PR #224952)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 21 01:45:44 PDT 2026


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/224952

>From f07be20fd74052e625fbd4cbce2a47dd373fed2f Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 19 Sep 2026 17:04:29 +0100
Subject: [PATCH] [SCEV] Clamp End instead of bailing out when using the
 ceiling division.

For the ceiling division, Start >= End is needed. When this is not known
on loop entry, we can instead clamp it to smin(End, Start) in the
existing code path above.

Then we can still compute extact trip counts for such cases.

Fixes a regression after https://github.com/llvm/llvm-project/pull/217744.

One minor change in
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1377
end-to-end.
---
 llvm/lib/Analysis/ScalarEvolution.cpp         | 21 +++++++++----------
 .../exit-count-greater-than.ll                | 21 +++++++++++--------
 2 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 50e0170b55089..5bce3e01d3697 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -13890,13 +13890,13 @@ ScalarEvolution::ExitLimit ScalarEvolution::howManyGreaterThans(
     MayAddOverflow = true;
   }
 
-  if (!isLoopEntryGuardedByCond(L, Cond, getAddExpr(Start, Stride), RHS)) {
-    // If we know that Start >= RHS in the context of loop, then we know that
-    // min(RHS, Start) = RHS at this point.
-    if (isLoopEntryGuardedByCond(
-            L, IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, Start, RHS))
-      End = RHS;
-    else
+  // If we know that Start >= RHS in the context of loop, then we know that
+  // min(RHS, Start) = RHS at this point and End needs no clamping.
+  if (!isLoopEntryGuardedByCond(
+          L, IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, Start, RHS)) {
+    // Otherwise clamp End to min(RHS, Start) when needed.
+    if (MayAddOverflow ||
+        !isLoopEntryGuardedByCond(L, Cond, getAddExpr(Start, Stride), RHS))
       End = IsSigned ? getSMinExpr(RHS, Start) : getUMinExpr(RHS, Start);
   }
 
@@ -13915,10 +13915,9 @@ ScalarEvolution::ExitLimit ScalarEvolution::howManyGreaterThans(
   const SCEV *BECount;
   if (MayAddOverflow) {
     // The ceiling division instead needs Start >= End, so that (Start - End) is
-    // the exact unsigned distance between them.
-    if (!isLoopEntryGuardedByCond(
-            L, IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, Start, End))
-      return getCouldNotCompute();
+    // the exact unsigned distance between them. It holds, either either because
+    // the loop is guarded by Start >= RHS or because End has been clamped to
+    // min(RHS, Start) above,
     BECount = getUDivCeilSCEV(Delta, Stride);
   } else {
     // Compute ((Start - End) + (Stride - 1)) / Stride, if the IV cannot
diff --git a/llvm/test/Analysis/ScalarEvolution/exit-count-greater-than.ll b/llvm/test/Analysis/ScalarEvolution/exit-count-greater-than.ll
index e976506d87619..cb5870aff29ab 100644
--- a/llvm/test/Analysis/ScalarEvolution/exit-count-greater-than.ll
+++ b/llvm/test/Analysis/ScalarEvolution/exit-count-greater-than.ll
@@ -86,9 +86,10 @@ exit:
 define i32 @sgt_stride_4_variable_bound(i32 %n, i32 %m) {
 ; CHECK-LABEL: 'sgt_stride_4_variable_bound'
 ; CHECK-NEXT:  Determining loop execution counts for: @sgt_stride_4_variable_bound
-; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
-; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
-; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((((-1 * (1 umin ((-1 * (%n smin %m)) + %n)))<nuw><nsw> + (-1 * (%n smin %m)) + %n) /u 4) + (1 umin ((-1 * (%n smin %m)) + %n)))
+; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i32 1073741823
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((((-1 * (1 umin ((-1 * (%n smin %m)) + %n)))<nuw><nsw> + (-1 * (%n smin %m)) + %n) /u 4) + (1 umin ((-1 * (%n smin %m)) + %n)))
+; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
   %add = add nsw i32 %n, 4
@@ -115,9 +116,10 @@ ret:
 define i32 @ugt_stride_4_variable_bound(i32 %n, i32 %m) {
 ; CHECK-LABEL: 'ugt_stride_4_variable_bound'
 ; CHECK-NEXT:  Determining loop execution counts for: @ugt_stride_4_variable_bound
-; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
-; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
-; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((((-1 * (1 umin ((-1 * (%n umin %m)) + %n)))<nuw><nsw> + (-1 * (%n umin %m)) + %n) /u 4) + (1 umin ((-1 * (%n umin %m)) + %n)))
+; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i32 1073741823
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((((-1 * (1 umin ((-1 * (%n umin %m)) + %n)))<nuw><nsw> + (-1 * (%n umin %m)) + %n) /u 4) + (1 umin ((-1 * (%n umin %m)) + %n)))
+; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
   %add = add nuw i32 %n, 4
@@ -145,9 +147,10 @@ ret:
 define i32 @sgt_stride_3_variable_bound(i32 %n, i32 %m) {
 ; CHECK-LABEL: 'sgt_stride_3_variable_bound'
 ; CHECK-NEXT:  Determining loop execution counts for: @sgt_stride_3_variable_bound
-; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
-; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
-; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: backedge-taken count is ((((-1 * (1 umin ((-1 * (%n smin %m)) + %n)))<nuw><nsw> + (-1 * (%n smin %m)) + %n) /u 3) + (1 umin ((-1 * (%n smin %m)) + %n)))
+; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i32 1431655765
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((((-1 * (1 umin ((-1 * (%n smin %m)) + %n)))<nuw><nsw> + (-1 * (%n smin %m)) + %n) /u 3) + (1 umin ((-1 * (%n smin %m)) + %n)))
+; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
 entry:
   %add = add nsw i32 %n, 3



More information about the llvm-commits mailing list