[llvm-branch-commits] [llvm] [SLP][modularisation][NFC] Move loop trip-count helpers to SLPUtils (PR #222614)
Madhur Amilkanthwar via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Sep 10 04:21:33 PDT 2026
https://github.com/madhur13490 created https://github.com/llvm/llvm-project/pull/222614
Move the BoUpSLP-independent helpers findInnermostNonInvariantLoop and
getLoopTripCount out of SLPVectorizer.cpp into the self-contained
SLPVectorizer/SLPUtils.{h,cpp} module. getLoopTripCount reads the file-local
LoopAwareTripCount cl::opt, which stays static in SLPVectorizer.cpp and is
passed to the moved helper as an explicit parameter. NFC.
Part of the SLPVectorizer.cpp modularization effort:
https://discourse.llvm.org/t/modularizing-slpvectorizer-cpp/90922
>From 365ad50d78628d648608f752922fb65fd0f2901d Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Thu, 10 Sep 2026 04:21:05 -0700
Subject: [PATCH] [SLP][modularisation][NFC] Move loop trip-count helpers to
SLPUtils
Move the BoUpSLP-independent helpers findInnermostNonInvariantLoop and
getLoopTripCount out of SLPVectorizer.cpp into the self-contained
SLPVectorizer/SLPUtils.{h,cpp} module. getLoopTripCount reads the file-local
LoopAwareTripCount cl::opt, which stays static in SLPVectorizer.cpp and is
passed to the moved helper as an explicit parameter. NFC.
Part of the SLPVectorizer.cpp modularization effort:
https://discourse.llvm.org/t/modularizing-slpvectorizer-cpp/90922
---
.../Transforms/Vectorize/SLPVectorizer.cpp | 36 ++-----------------
.../Vectorize/SLPVectorizer/SLPUtils.cpp | 33 +++++++++++++++++
.../Vectorize/SLPVectorizer/SLPUtils.h | 11 ++++++
3 files changed, 46 insertions(+), 34 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 19fabd2ab9e65..b998f7785c951 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -9141,21 +9141,6 @@ static bool isPoorThroughputOp(Instruction *I, const TargetTransformInfo &TTI,
[&] { Cache.CheapOpcodes.insert(Key); });
}
-/// Find the innermost loop starting from \p L, for which at least a single
-/// value in \p VL is not invariant.
-static const Loop *findInnermostNonInvariantLoop(const Loop *L,
- ArrayRef<Value *> VL) {
- assert(L && "Expected valid loop");
- auto IsLoopInvariant = [&](const Loop *L, ArrayRef<Value *> VL) {
- return all_of(VL, [&](Value *V) {
- return isa<Constant>(V) || !isa<Instruction>(V) || L->isLoopInvariant(V);
- });
- };
- while (L && IsLoopInvariant(L, VL))
- L = L->getParentLoop();
- return L;
-}
-
/// Get the loop nest for the given loop.
ArrayRef<const Loop *> BoUpSLP::getLoopNest(const Loop *L) {
assert(L && "Expected valid loop");
@@ -15392,24 +15377,6 @@ TTI::CastContextHint BoUpSLP::getCastContextHint(const TreeEntry &TE) const {
return TTI::CastContextHint::None;
}
-/// Get the assumed loop trip count for the loop \p L.
-static unsigned getLoopTripCount(const Loop *L, ScalarEvolution &SE) {
- if (LoopAwareTripCount == 0)
- return 1;
- unsigned Scale = SE.getSmallConstantTripCount(L);
- if (Scale == 0)
- Scale = getLoopEstimatedTripCount(const_cast<Loop *>(L)).value_or(0);
- if (Scale != 0) {
- // Multiple exiting blocks - choose the minimum between trip count (scale)
- // and LoopAwareTripCount, since the multiple exit loops can be terminated
- // early.
- if (!L->getExitingBlock())
- return std::min<unsigned>(LoopAwareTripCount, Scale);
- return Scale;
- }
- return LoopAwareTripCount;
-}
-
uint64_t BoUpSLP::getScaleToLoopIterations(const TreeEntry &TE, Value *Scalar,
Instruction *U) {
BasicBlock *Parent = nullptr;
@@ -15495,7 +15462,8 @@ uint64_t BoUpSLP::getLoopNestScale(const Loop *L) {
// Use SaturatingMultiply to clamp at uint64_t max on deep/large nests
// rather than wrapping around.
for (const Loop *Cur : reverse(Chain)) {
- uint64_t TC = std::max<uint64_t>(1, getLoopTripCount(Cur, *SE));
+ uint64_t TC =
+ std::max<uint64_t>(1, getLoopTripCount(Cur, *SE, LoopAwareTripCount));
Scale = SaturatingMultiply(Scale, TC);
LoopNestScaleCache.try_emplace(Cur, std::max<uint64_t>(1, Scale));
}
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
index 56915bda370cf..7853832268952 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
@@ -12,6 +12,8 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/Constants.h"
@@ -25,6 +27,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Utils/LoopUtils.h"
#include <algorithm>
#include <numeric>
@@ -1173,4 +1176,34 @@ DebugLoc getDebugLocFromPHI(PHINode &PN) {
return DebugLoc::getUnknown();
}
+const Loop *findInnermostNonInvariantLoop(const Loop *L, ArrayRef<Value *> VL) {
+ assert(L && "Expected valid loop");
+ auto IsLoopInvariant = [&](const Loop *L, ArrayRef<Value *> VL) {
+ return all_of(VL, [&](Value *V) {
+ return isa<Constant>(V) || !isa<Instruction>(V) || L->isLoopInvariant(V);
+ });
+ };
+ while (L && IsLoopInvariant(L, VL))
+ L = L->getParentLoop();
+ return L;
+}
+
+unsigned getLoopTripCount(const Loop *L, ScalarEvolution &SE,
+ unsigned LoopAwareTripCount) {
+ if (LoopAwareTripCount == 0)
+ return 1;
+ unsigned Scale = SE.getSmallConstantTripCount(L);
+ if (Scale == 0)
+ Scale = getLoopEstimatedTripCount(const_cast<Loop *>(L)).value_or(0);
+ if (Scale != 0) {
+ // Multiple exiting blocks - choose the minimum between trip count (scale)
+ // and LoopAwareTripCount, since the multiple exit loops can be terminated
+ // early.
+ if (!L->getExitingBlock())
+ return std::min<unsigned>(LoopAwareTripCount, Scale);
+ return Scale;
+ }
+ return LoopAwareTripCount;
+}
+
} // namespace llvm::slpvectorizer
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
index f319b1aea7e5a..a89db7a7f971d 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
@@ -36,7 +36,9 @@ class DebugLoc;
class Instruction;
class InsertElementInst;
class IRBuilderBase;
+class Loop;
class PHINode;
+class ScalarEvolution;
class TargetLibraryInfo;
class Type;
class Value;
@@ -423,6 +425,15 @@ bool isFirstInsertElement(const InsertElementInst *IE1,
/// none.
DebugLoc getDebugLocFromPHI(PHINode &PN);
+/// \returns the innermost loop starting from \p L for which at least one value
+/// in \p VL is not loop-invariant.
+const Loop *findInnermostNonInvariantLoop(const Loop *L, ArrayRef<Value *> VL);
+
+/// \returns an estimated trip count for \p L, bounded by the loop-aware budget
+/// \p LoopAwareTripCount. Returns 1 when the budget is 0.
+unsigned getLoopTripCount(const Loop *L, ScalarEvolution &SE,
+ unsigned LoopAwareTripCount);
+
} // namespace llvm::slpvectorizer
#endif // LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPUTILS_H
More information about the llvm-branch-commits
mailing list