[llvm] [SCEV] Consider IVMayOverflow to use cheap BE-count formula. (PR #218694)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 06:08:25 PDT 2026


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

>From a5ca4c18b62b459fe340e94d59b276ff72e9d66c Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 25 Aug 2026 10:25:18 +0100
Subject: [PATCH] [SCEV] Consider IVMayOverflow to use cheap BE-count formula.

If !IVMayOverflow, we proven RHS + stride - 1 does not wrap. This means
adding the `Stride - 1` part of `RHS - (Start - Stride) - 1` does not wrap.

Together with the other condition `Start - Stride < RHS`, this should
guarantee `RHS - (Start - Stride) - 1` does not wrap and the cheap
formula can be used.

This triggers in a number of real-world cases, mostly resulting in
simpler SCEV expansions/checks, and extra unrolling. In a small number
of cases, expansion is slightly worse.

https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1043

Alive2 Proof: https://alive2.llvm.org/ce/z/u_KUx5

Depends on https://github.com/llvm/llvm-project/pull/218251 (included in
PR)
---
 llvm/lib/Analysis/ScalarEvolution.cpp                    | 8 ++++++--
 llvm/test/Analysis/ScalarEvolution/2008-11-18-Stride2.ll | 4 ++--
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 1f2b8baafdaf0..97ac3c483b4e0 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -13569,7 +13569,8 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
     assert(isAvailableAtLoopEntry(OrigStart, L) && "Must be!");
     assert(isAvailableAtLoopEntry(OrigRHS, L) && "Must be!");
     // Can we prove (max(RHS,Start) > Start - Stride?
-    if (isLoopEntryGuardedByCond(L, Cond, OrigStartMinusStride, OrigStart) &&
+    if ((!IVMayOverflow ||
+         isLoopEntryGuardedByCond(L, Cond, OrigStartMinusStride, OrigStart)) &&
         isLoopEntryGuardedByCond(L, Cond, OrigStartMinusStride, OrigRHS)) {
       // In this case, we can use a refined formula for computing backedge
       // taken count.  The general formula remains:
@@ -13589,7 +13590,10 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
       //   "((End - 1) - (Start - Stride)) /u Stride" reduces to
       //   "((RHS - 1) - (Start - Stride)) /u Stride" reassociates to
       //   "((RHS - (Start - Stride) - 1) /u Stride".
-      //   Our preconditions trivially imply no overflow in that form.
+      //   Our preconditions imply no overflow in that form: If !IVMayOverflow,
+      //   we proven RHS + stride - 1 does not wrap. Otherwise,  if "Start -
+      //   Stride" does not overflow, both operands of the subtraction are in
+      //   range and their difference is the exact distance between them.
       const SCEV *MinusOne = getMinusOne(Stride->getType());
       const SCEV *Numerator =
           getMinusSCEV(getAddExpr(RHS, MinusOne), getMinusSCEV(Start, Stride));
diff --git a/llvm/test/Analysis/ScalarEvolution/2008-11-18-Stride2.ll b/llvm/test/Analysis/ScalarEvolution/2008-11-18-Stride2.ll
index 86f1757c46002..ca539e5f3c626 100644
--- a/llvm/test/Analysis/ScalarEvolution/2008-11-18-Stride2.ll
+++ b/llvm/test/Analysis/ScalarEvolution/2008-11-18-Stride2.ll
@@ -8,9 +8,9 @@ define i32 @f(i32 %x) nounwind readnone {
 ;
 ; CHECK-LABEL: 'f'
 ; CHECK-NEXT:  Determining loop execution counts for: @f
-; CHECK-NEXT:  Loop %bb: backedge-taken count is ((-1 + (-1 * %x) + (1000 umax (3 + %x))) /u 3)
+; CHECK-NEXT:  Loop %bb: backedge-taken count is ((999 + (-1 * %x)) /u 3)
 ; CHECK-NEXT:  Loop %bb: constant max backedge-taken count is i32 334
-; CHECK-NEXT:  Loop %bb: symbolic max backedge-taken count is ((-1 + (-1 * %x) + (1000 umax (3 + %x))) /u 3)
+; CHECK-NEXT:  Loop %bb: symbolic max backedge-taken count is ((999 + (-1 * %x)) /u 3)
 ; CHECK-NEXT:  Loop %bb: Trip multiple is 1
 ;
 entry:



More information about the llvm-commits mailing list