[llvm] [SCEV] Use computeMaxBECountForLT for howManyGreaterThans. (PR #224863)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 21 02:14:49 PDT 2026


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

>From f66256e0d76dc3ed67639b1ba222d9e6e396f054 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 10 Sep 2026 15:52:05 +0100
Subject: [PATCH 1/3] [SCEV] Use computeMaxBECountForLT for
 howManyGreaterThans.

Instead of checking for overflow of IV > RHS we can instead check ~IV < ~RHS.

This allows removing canIVOverflowOnGT, by extending canIVOverflowOnLT
and computeMaxBECountForLT to invert the operands if needed, replacing
hand rolled logic in howManyGreaterThans.

This improves results in some cases, because computeMaxBECountForLT
covers some additional cases:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1371.

This is also the last step in preparation for using howMt checkanyLessThans for
howManyGreaterThans.
---
 llvm/include/llvm/Analysis/ScalarEvolution.h  | 34 ++++---
 llvm/lib/Analysis/ScalarEvolution.cpp         | 92 +++++++------------
 .../exit-value-nowrap-flags.ll                | 18 ++--
 ...max-backedge-taken-count-correlated-end.ll |  2 +-
 .../Analysis/ScalarEvolution/trip-count13.ll  |  2 +-
 5 files changed, 66 insertions(+), 82 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index 7fddd4ca4119fa..8f9fdcaea30ae8 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -2512,9 +2512,25 @@ class ScalarEvolution {
   std::optional<std::pair<const SCEV *, SmallVector<const SCEVPredicate *, 3>>>
   createAddRecFromPHIWithCastsImpl(const SCEVUnknown *SymbolicPHI);
 
+  /// Return the smallest signed (\p IsSigned) or unsigned value for \p S. If \p
+  /// Invert, return it for complement ~S instead.
+  APInt getRangeMin(const SCEV *S, bool IsSigned, bool Invert = false) {
+    if (Invert)
+      return ~getRangeMax(S, IsSigned);
+    return IsSigned ? getSignedRangeMin(S) : getUnsignedRangeMin(S);
+  }
+  /// Return the largest signed (\p IsSigned) or unsigned value for \p S. If \p
+  /// Invert, return it for complement ~S instead.
+  APInt getRangeMax(const SCEV *S, bool IsSigned, bool Invert = false) {
+    if (Invert)
+      return ~getRangeMin(S, IsSigned);
+    return IsSigned ? getSignedRangeMax(S) : getUnsignedRangeMax(S);
+  }
+
   /// Compute the maximum backedge count based on the range of values
   /// permitted by Start, End, and Stride. This is for loops of the form
-  /// {Start, +, Stride} LT End.
+  /// {Start, +, Stride} LT End, or, if \p Invert is set, for the equivalent
+  /// "~Start < ~End" form of {Start, +, -Stride} GT End.
   ///
   /// Preconditions:
   /// * the induction variable is known to be positive.
@@ -2523,17 +2539,13 @@ class ScalarEvolution {
   /// We *don't* assert these preconditions so please be careful.
   const SCEV *computeMaxBECountForLT(const SCEV *Start, const SCEV *Stride,
                                      const SCEV *End, unsigned BitWidth,
-                                     bool IsSigned);
-
-  /// Verify if an linear IV with positive stride can overflow when in a
-  /// less-than comparison, knowing the invariant term of the comparison,
-  /// the stride.
-  bool canIVOverflowOnLT(const SCEV *RHS, const SCEV *Stride, bool IsSigned);
+                                     bool IsSigned, bool Invert);
 
-  /// Verify if an linear IV with negative stride can overflow when in a
-  /// greater-than comparison, knowing the invariant term of the comparison,
-  /// the stride.
-  bool canIVOverflowOnGT(const SCEV *RHS, const SCEV *Stride, bool IsSigned);
+  /// Verify if a linear IV with positive \p Stride can overflow when compared
+  /// against the invariant \p RHS with a less-than. If \p Invert is true, both
+  /// the IV and \p RHS are inverted
+  bool canIVOverflowOnLT(const SCEV *RHS, const SCEV *Stride, bool IsSigned,
+                         bool Invert = false);
 
   /// Get add expr already created or create a new one.
   const SCEV *getOrCreateAddExpr(ArrayRef<SCEVUse> Ops,
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 50e0170b550894..c3122b04564149 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -13278,14 +13278,14 @@ bool ScalarEvolution::isImpliedCondOperandsViaRanges(
 }
 
 bool ScalarEvolution::canIVOverflowOnLT(const SCEV *RHS, const SCEV *Stride,
-                                        bool IsSigned) {
+                                        bool IsSigned, bool Invert) {
   assert(isKnownPositive(Stride) && "Positive stride expected!");
 
   unsigned BitWidth = getTypeSizeInBits(RHS->getType());
   const SCEV *One = getOne(Stride->getType());
 
   if (IsSigned) {
-    APInt MaxRHS = getSignedRangeMax(RHS);
+    APInt MaxRHS = getRangeMax(RHS, /*IsSigned=*/true, Invert);
     APInt MaxValue = APInt::getSignedMaxValue(BitWidth);
     APInt MaxStrideMinusOne = getSignedRangeMax(getMinusSCEV(Stride, One));
 
@@ -13293,7 +13293,7 @@ bool ScalarEvolution::canIVOverflowOnLT(const SCEV *RHS, const SCEV *Stride,
     return (std::move(MaxValue) - MaxStrideMinusOne).slt(MaxRHS);
   }
 
-  APInt MaxRHS = getUnsignedRangeMax(RHS);
+  APInt MaxRHS = getRangeMax(RHS, /*IsSigned=*/false, Invert);
   APInt MaxValue = APInt::getMaxValue(BitWidth);
   APInt MaxStrideMinusOne = getUnsignedRangeMax(getMinusSCEV(Stride, One));
 
@@ -13301,29 +13301,6 @@ bool ScalarEvolution::canIVOverflowOnLT(const SCEV *RHS, const SCEV *Stride,
   return (std::move(MaxValue) - MaxStrideMinusOne).ult(MaxRHS);
 }
 
-bool ScalarEvolution::canIVOverflowOnGT(const SCEV *RHS, const SCEV *Stride,
-                                        bool IsSigned) {
-
-  unsigned BitWidth = getTypeSizeInBits(RHS->getType());
-  const SCEV *One = getOne(Stride->getType());
-
-  if (IsSigned) {
-    APInt MinRHS = getSignedRangeMin(RHS);
-    APInt MinValue = APInt::getSignedMinValue(BitWidth);
-    APInt MaxStrideMinusOne = getSignedRangeMax(getMinusSCEV(Stride, One));
-
-    // SMinRHS - SMaxStrideMinusOne < SMinValue => overflow!
-    return (std::move(MinValue) + MaxStrideMinusOne).sgt(MinRHS);
-  }
-
-  APInt MinRHS = getUnsignedRangeMin(RHS);
-  APInt MinValue = APInt::getMinValue(BitWidth);
-  APInt MaxStrideMinusOne = getUnsignedRangeMax(getMinusSCEV(Stride, One));
-
-  // UMinRHS - UMaxStrideMinusOne < UMinValue => overflow!
-  return (std::move(MinValue) + MaxStrideMinusOne).ugt(MinRHS);
-}
-
 const SCEV *ScalarEvolution::getUDivCeilSCEV(const SCEV *N, const SCEV *D) {
   // umin(N, 1) + floor((N - umin(N, 1)) / D)
   // This is equivalent to "1 + floor((N - 1) / D)" for N != 0. The umin
@@ -13333,11 +13310,10 @@ const SCEV *ScalarEvolution::getUDivCeilSCEV(const SCEV *N, const SCEV *D) {
   return getAddExpr(MinNOne, getUDivExpr(NMinusOne, D));
 }
 
-const SCEV *ScalarEvolution::computeMaxBECountForLT(const SCEV *Start,
-                                                    const SCEV *Stride,
-                                                    const SCEV *End,
-                                                    unsigned BitWidth,
-                                                    bool IsSigned) {
+const SCEV *
+ScalarEvolution::computeMaxBECountForLT(const SCEV *Start, const SCEV *Stride,
+                                        const SCEV *End, unsigned BitWidth,
+                                        bool IsSigned, bool Invert) {
   // The logic in this function assumes we can represent a positive stride.
   // If we can't, the backedge-taken count must be zero.
   if (IsSigned && BitWidth == 1)
@@ -13350,9 +13326,9 @@ const SCEV *ScalarEvolution::computeMaxBECountForLT(const SCEV *Start,
     return getCouldNotCompute();
 
   // Calculate the maximum backedge count based on the range of values
-  // permitted by Start, End, and Stride.
-  APInt MinStart =
-      IsSigned ? getSignedRangeMin(Start) : getUnsignedRangeMin(Start);
+  // permitted by Start, End, and Stride. If Invert is true, both Start and End
+  // need inverting. Stride is already inverted by the caller.
+  APInt MinStart = getRangeMin(Start, IsSigned, Invert);
 
   APInt MinStride =
       IsSigned ? getSignedRangeMin(Stride) : getUnsignedRangeMin(Stride);
@@ -13371,8 +13347,9 @@ const SCEV *ScalarEvolution::computeMaxBECountForLT(const SCEV *Start,
   // the case End = RHS of the loop termination condition. This is safe because
   // in the other case (End - Start) is zero, leading to a zero maximum backedge
   // taken count.
-  APInt MaxEnd = IsSigned ? APIntOps::smin(getSignedRangeMax(End), Limit)
-                          : APIntOps::umin(getUnsignedRangeMax(End), Limit);
+  APInt MaxEnd = getRangeMax(End, IsSigned, Invert);
+  MaxEnd =
+      IsSigned ? APIntOps::smin(MaxEnd, Limit) : APIntOps::umin(MaxEnd, Limit);
 
   // MaxBECount = ceil((max(MaxEnd, MinStart) - MinStart) / Stride)
   MaxEnd = IsSigned ? APIntOps::smax(MaxEnd, MinStart)
@@ -13380,9 +13357,11 @@ const SCEV *ScalarEvolution::computeMaxBECountForLT(const SCEV *Start,
 
   APInt Delta = MaxEnd - MinStart;
 
-  // Try to refine Delta in case End - Start gives a tighter bound after
-  // folding.
-  Delta = APIntOps::umin(Delta, getUnsignedRangeMax(getMinusSCEV(End, Start)));
+  // Try to refine Delta in case End - Start (or Start - End if Invert) gives a
+  // tighter bound after folding.
+  const SCEV *DeltaExpr =
+      Invert ? getMinusSCEV(Start, End) : getMinusSCEV(End, Start);
+  Delta = APIntOps::umin(Delta, getUnsignedRangeMax(DeltaExpr));
 
   return getUDivCeilSCEV(getConstant(Delta), getConstant(StrideForMaxBECount));
 }
@@ -13835,7 +13814,8 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
     MaxOrZero = true;
   } else {
     ConstantMaxBECount = computeMaxBECountForLT(
-        Start, Stride, RHS, getTypeSizeInBits(LHS->getType()), IsSigned);
+        Start, Stride, RHS, getTypeSizeInBits(LHS->getType()), IsSigned,
+        /*Invert=*/false);
   }
 
   if (isa<SCEVCouldNotCompute>(ConstantMaxBECount) &&
@@ -13884,7 +13864,8 @@ ScalarEvolution::ExitLimit ScalarEvolution::howManyGreaterThans(
   bool MayAddOverflow = false;
   const SCEV *Start = IV->getStart();
   const SCEV *End = RHS;
-  if (!Stride->isOne() && canIVOverflowOnGT(RHS, Stride, IsSigned)) {
+  if (!Stride->isOne() &&
+      canIVOverflowOnLT(RHS, Stride, IsSigned, /*Invert=*/true)) {
     if (!NoWrap)
       return getCouldNotCompute();
     MayAddOverflow = true;
@@ -13910,6 +13891,11 @@ ScalarEvolution::ExitLimit ScalarEvolution::howManyGreaterThans(
     if (isa<SCEVCouldNotCompute>(End))
       return End;
   }
+  if (RHS->getType()->isPointerTy()) {
+    RHS = getPtrToAddrExpr(RHS);
+    if (isa<SCEVCouldNotCompute>(RHS))
+      return RHS;
+  }
 
   const SCEV *Delta = getMinusSCEV(Start, End);
   const SCEV *BECount;
@@ -13927,28 +13913,14 @@ ScalarEvolution::ExitLimit ScalarEvolution::howManyGreaterThans(
     BECount = getUDivExpr(getAddExpr(Delta, getMinusSCEV(Stride, One)), Stride);
   }
 
-  APInt MaxStart = IsSigned ? getSignedRangeMax(Start)
-                            : getUnsignedRangeMax(Start);
-
-  APInt MinStride = IsSigned ? getSignedRangeMin(Stride)
-                             : getUnsignedRangeMin(Stride);
-
-  unsigned BitWidth = getTypeSizeInBits(LHS->getType());
-  APInt Limit = IsSigned ? APInt::getSignedMinValue(BitWidth) + (MinStride - 1)
-                         : APInt::getMinValue(BitWidth) + (MinStride - 1);
-
-  // Although End can be a MIN expression we estimate MinEnd considering only
-  // the case End = RHS. This is safe because in the other case (Start - End)
-  // is zero, leading to a zero maximum backedge taken count.
-  APInt MinEnd =
-    IsSigned ? APIntOps::smax(getSignedRangeMin(RHS), Limit)
-             : APIntOps::umax(getUnsignedRangeMin(RHS), Limit);
-
+  // "IV > RHS" is analyzed as the equivalent "~IV < ~RHS"; Stride is already
+  // the negated step.
   const SCEV *ConstantMaxBECount =
       isa<SCEVConstant>(BECount)
           ? BECount
-          : getUDivCeilSCEV(getConstant(MaxStart - MinEnd),
-                            getConstant(MinStride));
+          : computeMaxBECountForLT(Start, Stride, RHS,
+                                   getTypeSizeInBits(LHS->getType()), IsSigned,
+                                   /*Invert=*/true);
 
   if (isa<SCEVCouldNotCompute>(ConstantMaxBECount))
     ConstantMaxBECount = BECount;
diff --git a/llvm/test/Analysis/ScalarEvolution/exit-value-nowrap-flags.ll b/llvm/test/Analysis/ScalarEvolution/exit-value-nowrap-flags.ll
index 92e1a3da73c85e..4774b792abc6c4 100644
--- a/llvm/test/Analysis/ScalarEvolution/exit-value-nowrap-flags.ll
+++ b/llvm/test/Analysis/ScalarEvolution/exit-value-nowrap-flags.ll
@@ -13,12 +13,12 @@ define void @dec_to_start_of_nuw_addrec(i64 %start) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%up> U: [1,11) S: [1,11) Exits: 10 LoopDispositions: { %up: Computable }
 ; CHECK-NEXT:    %y = phi i64 [ %x, %up ], [ %y.next, %down ]
-; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up>,+,-1}<%down> U: full-set S: full-set --> {(9 + %start)<u nuw>,+,-1}<%down> U: full-set S: full-set Exits: (1 + ((8 + %start) umin %start)) LoopDispositions: { %down: Computable }
+; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up>,+,-1}<nw><%down> U: full-set S: full-set --> {(9 + %start)<u nuw>,+,-1}<nw><%down> U: full-set S: full-set Exits: (1 + ((8 + %start) umin %start)) LoopDispositions: { %down: Computable }
 ; CHECK-NEXT:    %y.next = add i64 %y, -1
-; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up>,+,-1}<%down> U: full-set S: full-set --> {(8 + %start),+,-1}<%down> U: full-set S: full-set Exits: ((8 + %start) umin %start) LoopDispositions: { %down: Computable }
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up>,+,-1}<nw><%down> U: full-set S: full-set --> {(8 + %start),+,-1}<nw><%down> U: full-set S: full-set Exits: ((8 + %start) umin %start) LoopDispositions: { %down: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nuw_addrec
 ; CHECK-NEXT:  Loop %down: backedge-taken count is (8 + (-1 * ((8 + %start) umin %start)) + %start)
-; CHECK-NEXT:  Loop %down: constant max backedge-taken count is i64 -1
+; CHECK-NEXT:  Loop %down: constant max backedge-taken count is i64 8
 ; CHECK-NEXT:  Loop %down: symbolic max backedge-taken count is (8 + (-1 * ((8 + %start) umin %start)) + %start)
 ; CHECK-NEXT:  Loop %down: Trip multiple is 1
 ; CHECK-NEXT:  Loop %up: backedge-taken count is i32 9
@@ -59,12 +59,12 @@ define void @dec_to_start_of_nuw_ptr_addrec(ptr %start) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%up> U: [1,11) S: [1,11) Exits: 10 LoopDispositions: { %up: Computable }
 ; CHECK-NEXT:    %q = phi ptr [ %p, %up ], [ %q.next, %down ]
-; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up>,+,-1}<%down> U: full-set S: full-set --> {(9 + %start)<u nuw>,+,-1}<%down> U: full-set S: full-set Exits: (1 + (-1 * (ptrtoaddr ptr %start to i64)) + ((8 + (ptrtoaddr ptr %start to i64)) umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down: Computable }
+; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up>,+,-1}<nw><%down> U: full-set S: full-set --> {(9 + %start)<u nuw>,+,-1}<nw><%down> U: full-set S: full-set Exits: (1 + (-1 * (ptrtoaddr ptr %start to i64)) + ((8 + (ptrtoaddr ptr %start to i64)) umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down: Computable }
 ; CHECK-NEXT:    %q.next = getelementptr i8, ptr %q, i64 -1
-; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up>,+,-1}<%down> U: full-set S: full-set --> {(8 + %start),+,-1}<%down> U: full-set S: full-set Exits: ((-1 * (ptrtoaddr ptr %start to i64)) + ((8 + (ptrtoaddr ptr %start to i64)) umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down: Computable }
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up>,+,-1}<nw><%down> U: full-set S: full-set --> {(8 + %start),+,-1}<nw><%down> U: full-set S: full-set Exits: ((-1 * (ptrtoaddr ptr %start to i64)) + ((8 + (ptrtoaddr ptr %start to i64)) umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nuw_ptr_addrec
 ; CHECK-NEXT:  Loop %down: backedge-taken count is (8 + (-1 * ((8 + (ptrtoaddr ptr %start to i64)) umin (ptrtoaddr ptr %start to i64))) + (ptrtoaddr ptr %start to i64))
-; CHECK-NEXT:  Loop %down: constant max backedge-taken count is i64 -1
+; CHECK-NEXT:  Loop %down: constant max backedge-taken count is i64 8
 ; CHECK-NEXT:  Loop %down: symbolic max backedge-taken count is (8 + (-1 * ((8 + (ptrtoaddr ptr %start to i64)) umin (ptrtoaddr ptr %start to i64))) + (ptrtoaddr ptr %start to i64))
 ; CHECK-NEXT:  Loop %down: Trip multiple is 1
 ; CHECK-NEXT:  Loop %up: backedge-taken count is i32 9
@@ -105,12 +105,12 @@ define void @dec_to_start_of_wrapping_addrec(i64 %start) {
 ; CHECK-NEXT:    %i.next = add i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%up> U: [1,11) S: [1,11) Exits: 10 LoopDispositions: { %up: Computable }
 ; CHECK-NEXT:    %y = phi i64 [ %x, %up ], [ %y.next, %down ]
-; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nw><%up>,+,-1}<%down> U: full-set S: full-set --> {(9 + %start),+,-1}<%down> U: full-set S: full-set Exits: (1 + ((8 + %start) umin %start)) LoopDispositions: { %down: Computable }
+; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nw><%up>,+,-1}<nw><%down> U: full-set S: full-set --> {(9 + %start),+,-1}<nw><%down> U: full-set S: full-set Exits: (1 + ((8 + %start) umin %start)) LoopDispositions: { %down: Computable }
 ; CHECK-NEXT:    %y.next = add i64 %y, -1
-; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up>,+,-1}<%down> U: full-set S: full-set --> {(8 + %start),+,-1}<%down> U: full-set S: full-set Exits: ((8 + %start) umin %start) LoopDispositions: { %down: Computable }
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up>,+,-1}<nw><%down> U: full-set S: full-set --> {(8 + %start),+,-1}<nw><%down> U: full-set S: full-set Exits: ((8 + %start) umin %start) LoopDispositions: { %down: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_wrapping_addrec
 ; CHECK-NEXT:  Loop %down: backedge-taken count is (8 + (-1 * ((8 + %start) umin %start)) + %start)
-; CHECK-NEXT:  Loop %down: constant max backedge-taken count is i64 -1
+; CHECK-NEXT:  Loop %down: constant max backedge-taken count is i64 8
 ; CHECK-NEXT:  Loop %down: symbolic max backedge-taken count is (8 + (-1 * ((8 + %start) umin %start)) + %start)
 ; CHECK-NEXT:  Loop %down: Trip multiple is 1
 ; CHECK-NEXT:  Loop %up: backedge-taken count is i32 9
diff --git a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-correlated-end.ll b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-correlated-end.ll
index 9bfa7c3299ec03..15327d514daa1a 100644
--- a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-correlated-end.ll
+++ b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-correlated-end.ll
@@ -120,7 +120,7 @@ define void @gt_end_is_start_minus_bounded_n(i8 %nraw, i8 %a) {
 ; CHECK-LABEL: 'gt_end_is_start_minus_bounded_n'
 ; CHECK-NEXT:  Determining loop execution counts for: @gt_end_is_start_minus_bounded_n
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * (((-1 * (zext i3 (trunc i8 %nraw to i3) to i8))<nsw> + %a) umin %a)) + %a)
-; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i8 -1
+; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i8 7
 ; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * (((-1 * (zext i3 (trunc i8 %nraw to i3) to i8))<nsw> + %a) umin %a)) + %a)
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;
diff --git a/llvm/test/Analysis/ScalarEvolution/trip-count13.ll b/llvm/test/Analysis/ScalarEvolution/trip-count13.ll
index 720b2ae49c0905..e3e17a97da6393 100644
--- a/llvm/test/Analysis/ScalarEvolution/trip-count13.ll
+++ b/llvm/test/Analysis/ScalarEvolution/trip-count13.ll
@@ -106,7 +106,7 @@ define void @s_2(i8 %start) {
 ; CHECK-LABEL: 's_2'
 ; CHECK-NEXT:  Determining loop execution counts for: @s_2
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is ((-1 * ((-100 + %start) smin %start)) + %start)
-; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i8 -1
+; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i8 100
 ; CHECK-NEXT:  Loop %loop: symbolic max backedge-taken count is ((-1 * ((-100 + %start) smin %start)) + %start)
 ; CHECK-NEXT:  Loop %loop: Trip multiple is 1
 ;

>From b60dc0ebb61cb0b48e95e3da6364e542995506ee Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 20 Sep 2026 13:18:48 +0100
Subject: [PATCH 2/3] !fixup combine pointer conversion under single guard.

---
 llvm/lib/Analysis/ScalarEvolution.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index c3122b04564149..b7c6c8d99b4359 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -13882,16 +13882,16 @@ ScalarEvolution::ExitLimit ScalarEvolution::howManyGreaterThans(
   }
 
   if (Start->getType()->isPointerTy()) {
+    assert(End->getType()->isPointerTy() && RHS->getType()->isPointerTy() &&
+           "Start, End and RHS all must be pointers");
     Start = getPtrToAddrExpr(Start);
     if (isa<SCEVCouldNotCompute>(Start))
       return Start;
-  }
-  if (End->getType()->isPointerTy()) {
+
     End = getPtrToAddrExpr(End);
     if (isa<SCEVCouldNotCompute>(End))
       return End;
-  }
-  if (RHS->getType()->isPointerTy()) {
+
     RHS = getPtrToAddrExpr(RHS);
     if (isa<SCEVCouldNotCompute>(RHS))
       return RHS;

>From 6ff4af23a159be5877ff74a4baa80573150bafb6 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 21 Sep 2026 10:13:16 +0100
Subject: [PATCH 3/3] !fixup inverted -> negated

---
 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 b7c6c8d99b4359..20e1c64f7e94c6 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -13327,7 +13327,7 @@ ScalarEvolution::computeMaxBECountForLT(const SCEV *Start, const SCEV *Stride,
 
   // Calculate the maximum backedge count based on the range of values
   // permitted by Start, End, and Stride. If Invert is true, both Start and End
-  // need inverting. Stride is already inverted by the caller.
+  // need negating w.r.t. Stride. Stride was already adjusted by the caller.
   APInt MinStart = getRangeMin(Start, IsSigned, Invert);
 
   APInt MinStride =



More information about the llvm-commits mailing list