[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