[llvm] [SCEV] Collect loop guards once in getSmallConstantTripMultiple (NFC). (PR #219722)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 29 13:26:58 PDT 2026


https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/219722

Add a new variant of getSmallConstantTripMultiple that takes loop guards. Use it to collect loop guards once per call, instead of per exit. Loop guards hold for the entry of the loop, so can be shared between all exits.

This avoids some unnecessary work (and should make it easier to extend collection with less compile-time impact in the future), even though compile-time impact is currently in the noise
https://llvm-compile-time-tracker.com/compare.php?from=ad3ba4569c37e0dc028cc928393f90a16e0b162d&to=1f7467b845a398fdcdf49c4c9151cb7612e19e40&stat=instructions:u

>From 4283a7a4911fa2d4ffbf006ff4b121a7b626a887 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 29 Aug 2026 21:11:23 +0100
Subject: [PATCH] [SCEV] Collect loop guards once in
 getSmallConstantTripMultiple (NFC).

Add a new variant of getSmallConstantTripMultiple that takes loop
guards. Use it to collect loop guards once per call, instead of per
exit. Loop guards hold for the entry of the loop, so can be shared
between all exits.

This avoids some unnecessary work, even though compile-time impact is
currently in the noise
https://llvm-compile-time-tracker.com/compare.php?from=ad3ba4569c37e0dc028cc928393f90a16e0b162d&to=1f7467b845a398fdcdf49c4c9151cb7612e19e40&stat=instructions:u
---
 llvm/include/llvm/Analysis/ScalarEvolution.h |  5 +++
 llvm/lib/Analysis/ScalarEvolution.cpp        | 40 +++++++++++++-------
 2 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index 95e545477fa77..da9c82b700ef3 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -2094,6 +2094,11 @@ class ScalarEvolution {
   BackedgeTakenInfo computeBackedgeTakenCount(const Loop *L,
                                               bool AllowPredicates = false);
 
+  /// Variant of getSmallConstantTripMultiple taking pre-collected loop
+  /// \p Guards. \p ExitCount must be computable.
+  unsigned getSmallConstantTripMultiple(const SCEV *ExitCount,
+                                        const LoopGuards &Guards);
+
   /// Compute the number of times the backedge of the specified loop will
   /// execute if it exits via the specified block. If AllowPredicates is set,
   /// this call will try to use a minimal set of SCEV predicates in order to
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index e81d91c03c130..ef3cd80089a62 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -8411,23 +8411,29 @@ unsigned ScalarEvolution::getSmallConstantTripMultiple(const Loop *L) {
   SmallVector<BasicBlock *, 8> ExitingBlocks;
   L->getExitingBlocks(ExitingBlocks);
 
-  std::optional<unsigned> Res;
-  for (auto *ExitingBB : ExitingBlocks) {
-    unsigned Multiple = getSmallConstantTripMultiple(L, ExitingBB);
-    if (!Res)
-      Res = Multiple;
-    Res = std::gcd(*Res, Multiple);
-  }
-  return Res.value_or(1);
+  // An exit with an uncomputable exit count makes the result 1.
+  if (ExitingBlocks.empty() ||
+      any_of(ExitingBlocks, [this, L](BasicBlock *ExitingBB) {
+        return isa<SCEVCouldNotCompute>(getExitCount(L, ExitingBB));
+      }))
+    return 1;
+
+  LoopGuards Guards = LoopGuards::collect(L, *this);
+  unsigned Res = 0;
+  for (BasicBlock *ExitingBB : ExitingBlocks)
+    Res = std::gcd(
+        Res, getSmallConstantTripMultiple(getExitCount(L, ExitingBB), Guards));
+  return Res;
 }
 
-unsigned ScalarEvolution::getSmallConstantTripMultiple(const Loop *L,
-                                                       const SCEV *ExitCount) {
-  if (isa<SCEVCouldNotCompute>(ExitCount))
-    return 1;
+unsigned
+ScalarEvolution::getSmallConstantTripMultiple(const SCEV *ExitCount,
+                                              const LoopGuards &Guards) {
+  assert(!isa<SCEVCouldNotCompute>(ExitCount) && "Must be computable!");
 
   // Get the trip count
-  const SCEV *TCExpr = getTripCountFromExitCount(applyLoopGuards(ExitCount, L));
+  const SCEV *TCExpr =
+      getTripCountFromExitCount(applyLoopGuards(ExitCount, Guards));
 
   APInt Multiple = getNonZeroConstantMultiple(TCExpr);
   // If a trip multiple is huge (>=2^32), the trip count is still divisible by
@@ -8437,6 +8443,14 @@ unsigned ScalarEvolution::getSmallConstantTripMultiple(const Loop *L,
              : (unsigned)Multiple.getZExtValue();
 }
 
+unsigned ScalarEvolution::getSmallConstantTripMultiple(const Loop *L,
+                                                       const SCEV *ExitCount) {
+  if (isa<SCEVCouldNotCompute>(ExitCount))
+    return 1;
+
+  return getSmallConstantTripMultiple(ExitCount, LoopGuards::collect(L, *this));
+}
+
 /// Returns the largest constant divisor of the trip count of this loop as a
 /// normal unsigned value, if possible. This means that the actual trip count is
 /// always a multiple of the returned value (don't forget the trip count could



More information about the llvm-commits mailing list