[llvm] 8f5ef73 - [SCEV] Avoid overflow in howManyGreaterThans. (#217744)

via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 22 06:17:08 PDT 2026


Author: Florian Hahn
Date: 2026-08-22T13:17:03Z
New Revision: 8f5ef7362dc9dbb19454e458f7ca4fb99fab5d52

URL: https://github.com/llvm/llvm-project/commit/8f5ef7362dc9dbb19454e458f7ca4fb99fab5d52
DIFF: https://github.com/llvm/llvm-project/commit/8f5ef7362dc9dbb19454e458f7ca4fb99fab5d52.diff

LOG: [SCEV] Avoid overflow in howManyGreaterThans. (#217744)

howManyGreaterThans computes the backedge-taken count as ((Start - End)
+ (Stride - 1)) /u Stride. The addition can overflow, causing incorrect
results.

Instead, use getUDivCeilSCEV if Start >= End, mirroring
howManyLessThans. It also has additional handling for stride being a
power of 2, which allows using the simpler formula in more cases.

I'll check if we can unify the code (as implied by the FIXME I think),
instead of duplicating more logic.

Fixes https://github.com/llvm/llvm-project/issues/217537.
Fixes https://github.com/llvm/llvm-project/issues/187472.

PR: https://github.com/llvm/llvm-project/pull/217744

Added: 
    

Modified: 
    llvm/lib/Analysis/ScalarEvolution.cpp
    llvm/test/Analysis/ScalarEvolution/exit-count-greater-than.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 6095f59ec1413..a05b7e9714f01 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -13833,12 +13833,15 @@ ScalarEvolution::ExitLimit ScalarEvolution::howManyGreaterThans(
   // will not generate any unsigned overflow. Relaxed no-overflow conditions
   // exploit NoWrapFlags, allowing to optimize in presence of undefined
   // behaviors like the case of C language.
-  if (!Stride->isOne() && !NoWrap)
-    if (canIVOverflowOnGT(RHS, Stride, IsSigned))
-      return getCouldNotCompute();
-
+  bool MayAddOverflow = false;
   const SCEV *Start = IV->getStart();
   const SCEV *End = RHS;
+  if (!Stride->isOne() && canIVOverflowOnGT(RHS, Stride, IsSigned)) {
+    if (!NoWrap)
+      return getCouldNotCompute();
+    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.
@@ -13860,12 +13863,21 @@ ScalarEvolution::ExitLimit ScalarEvolution::howManyGreaterThans(
       return End;
   }
 
-  // Compute ((Start - End) + (Stride - 1)) / Stride.
-  // FIXME: This can overflow. Holding off on fixing this for now;
-  // howManyGreaterThans will hopefully be gone soon.
-  const SCEV *One = getOne(Stride->getType());
-  const SCEV *BECount = getUDivExpr(
-      getAddExpr(getMinusSCEV(Start, End), getMinusSCEV(Stride, One)), Stride);
+  const SCEV *Delta = getMinusSCEV(Start, End);
+  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();
+    BECount = getUDivCeilSCEV(Delta, Stride);
+  } else {
+    // Compute ((Start - End) + (Stride - 1)) / Stride, if the IV cannot
+    // overflow as it requires fewer operations.
+    const SCEV *One = getOne(Stride->getType());
+    BECount = getUDivExpr(getAddExpr(Delta, getMinusSCEV(Stride, One)), Stride);
+  }
 
   APInt MaxStart = IsSigned ? getSignedRangeMax(Start)
                             : getUnsignedRangeMax(Start);

diff  --git a/llvm/test/Analysis/ScalarEvolution/exit-count-greater-than.ll b/llvm/test/Analysis/ScalarEvolution/exit-count-greater-than.ll
index daa1695027b53..e976506d87619 100644
--- a/llvm/test/Analysis/ScalarEvolution/exit-count-greater-than.ll
+++ b/llvm/test/Analysis/ScalarEvolution/exit-count-greater-than.ll
@@ -5,14 +5,13 @@
 
 ; The IV counts down by 3 from 32767 (SMAX) and the loop exits when it reaches
 ; -32767. Test for https://github.com/llvm/llvm-project/issues/217537.
-; FIXME: Currently BTC is computed incorreclty as 0.
 define i32 @sgt_stride_3_wrapping_distance(ptr %out) {
 ; CHECK-LABEL: 'sgt_stride_3_wrapping_distance'
 ; CHECK-NEXT:  Determining loop execution counts for: @sgt_stride_3_wrapping_distance
-; CHECK-NEXT:  Loop %loop.header: backedge-taken count is i16 0
-; CHECK-NEXT:  Loop %loop.header: constant max backedge-taken count is i16 0
-; CHECK-NEXT:  Loop %loop.header: symbolic max backedge-taken count is i16 0
-; CHECK-NEXT:  Loop %loop.header: Trip multiple is 1
+; CHECK-NEXT:  Loop %loop.header: backedge-taken count is i16 21845
+; CHECK-NEXT:  Loop %loop.header: constant max backedge-taken count is i16 21845
+; CHECK-NEXT:  Loop %loop.header: symbolic max backedge-taken count is i16 21845
+; CHECK-NEXT:  Loop %loop.header: Trip multiple is 21846
 ;
 entry:
   br label %loop.header
@@ -35,14 +34,13 @@ exit:
 
 ; Unsigned variant of the above: the IV counts down by 3 from 65535 (UMAX) and
 ; the loop exits when it reaches 1.
-; FIXME: Currently BTC is computed incorreclty as 0.
 define i32 @ugt_stride_3_wrapping_distance(ptr %out) {
 ; CHECK-LABEL: 'ugt_stride_3_wrapping_distance'
 ; CHECK-NEXT:  Determining loop execution counts for: @ugt_stride_3_wrapping_distance
-; CHECK-NEXT:  Loop %loop.header: backedge-taken count is i16 0
-; CHECK-NEXT:  Loop %loop.header: constant max backedge-taken count is i16 0
-; CHECK-NEXT:  Loop %loop.header: symbolic max backedge-taken count is i16 0
-; CHECK-NEXT:  Loop %loop.header: Trip multiple is 1
+; CHECK-NEXT:  Loop %loop.header: backedge-taken count is i16 21845
+; CHECK-NEXT:  Loop %loop.header: constant max backedge-taken count is i16 21845
+; CHECK-NEXT:  Loop %loop.header: symbolic max backedge-taken count is i16 21845
+; CHECK-NEXT:  Loop %loop.header: Trip multiple is 21846
 ;
 entry:
   br label %loop.header
@@ -64,14 +62,13 @@ exit:
 }
 
 ; Same overflow, but with a stride that is itself larger than SMAX / 2.
-; FIXME: Currently BTC is computed incorreclty as 0.
 define i32 @sgt_large_stride_wrapping_distance() {
 ; CHECK-LABEL: 'sgt_large_stride_wrapping_distance'
 ; CHECK-NEXT:  Determining loop execution counts for: @sgt_large_stride_wrapping_distance
-; CHECK-NEXT:  Loop %loop: backedge-taken count is i32 0
-; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i32 0
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is i32 0
-; CHECK-NEXT:  Loop %loop: Trip multiple is 1
+; CHECK-NEXT:  Loop %loop: backedge-taken count is i32 3
+; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i32 3
+; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is i32 3
+; CHECK-NEXT:  Loop %loop: Trip multiple is 4
 ;
 entry:
   br label %loop
@@ -89,10 +86,9 @@ 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: backedge-taken count is ((3 + (-1 * %m) + %n) /u 4)
-; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i32 1073741823
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((3 + (-1 * %m) + %n) /u 4)
-; CHECK-NEXT:  Loop %loop: Trip multiple is 1
+; 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.
 ;
 entry:
   %add = add nsw i32 %n, 4
@@ -119,10 +115,9 @@ 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: backedge-taken count is ((3 + (-1 * %m) + %n) /u 4)
-; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i32 1073741823
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((3 + (-1 * %m) + %n) /u 4)
-; CHECK-NEXT:  Loop %loop: Trip multiple is 1
+; 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.
 ;
 entry:
   %add = add nuw i32 %n, 4
@@ -150,10 +145,9 @@ 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: backedge-taken count is ((2 + (-1 * %m) + %n) /u 3)
-; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i32 1431655765
-; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((2 + (-1 * %m) + %n) /u 3)
-; CHECK-NEXT:  Loop %loop: Trip multiple is 1
+; 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.
 ;
 entry:
   %add = add nsw i32 %n, 3


        


More information about the llvm-commits mailing list