[llvm] [SLP][NFC]Cache IsExternallyUsed by Value in cost computation (PR #194637)
Alexey Bataev via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 28 07:05:12 PDT 2026
https://github.com/alexey-bataev created https://github.com/llvm/llvm-project/pull/194637
Same V is commonly seen in multiple TEs (shared scalars), and the
expensive part of IsExternallyUsed walks V->users() with multiple
match() pattern checks plus per-user getTreeEntries lookups - all
V-only-dependent. Split out the V-dependent body and memoize by
Value pointer, leaving the TE-specific copyable check at the call
site. DeletedNodes is read-only during the cost loop, so caching
is safe.
>From 9b35b094841a7ce72439d9f49538f490eb9de27f Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Tue, 28 Apr 2026 07:04:53 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
=?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.7
---
.../Transforms/Vectorize/SLPVectorizer.cpp | 75 +++++++++++--------
1 file changed, 42 insertions(+), 33 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index c6f388ec1e0f5..c18ebe3e23cc5 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -18332,44 +18332,53 @@ InstructionCost BoUpSLP::calculateTreeCostAndTrimNonProfitable(
SmallDenseMap<const TreeEntry *, InstructionCost> ExtractCosts;
LLVM_DEBUG(dbgs() << "SLP: Calculating cost for tree of size "
<< VectorizableTree.size() << ".\n");
+ // The V-only-dependent part of the predicate. Same V is commonly seen in
+ // multiple TEs (shared scalars), so cache the result across calls.
+ // DeletedNodes is read-only during this cost loop, so caching is safe.
+ const size_t NumVectScalars = ScalarToTreeEntries.size() + 1;
+ SmallDenseMap<Value *, bool> ExternalUseVCache;
+ auto IsExternallyUsedV = [&](Value *V) {
+ auto [It, Inserted] = ExternalUseVCache.try_emplace(V);
+ if (!Inserted)
+ return It->second;
+ bool Res = false;
+ if (V->hasOneUse() || V->getType()->isVoidTy()) {
+ // Res stays false.
+ } else if (V->hasNUsesOrMore(NumVectScalars)) {
+ Res = true;
+ } else if (auto *I = dyn_cast<Instruction>(V)) {
+ Res = any_of(I->users(), [&](const User *U) {
+ // store/insertelt v, [cast]U will likely be vectorized.
+ if (match(U,
+ m_InsertElt(m_Value(), m_OneUse(m_CastOrSelf(m_Specific(I))),
+ m_ConstantInt())))
+ return false;
+ if (match(U, m_InsertElt(m_Value(), m_Specific(I), m_ConstantInt())))
+ return false;
+ if (match(U, m_Store(m_OneUse(m_CastOrSelf(m_Specific(I))), m_Value())))
+ return false;
+ if (match(U, m_Store(m_Specific(I), m_Value())))
+ return false;
+ ArrayRef<TreeEntry *> Entries = getTreeEntries(U);
+ if (Entries.empty() && !MustGather.contains(U))
+ return true;
+ if (any_of(Entries,
+ [&](TreeEntry *TE) { return DeletedNodes.contains(TE); }))
+ return true;
+ return any_of(ValueToGatherNodes.lookup(U), [&](const TreeEntry *TE) {
+ return DeletedNodes.contains(TE);
+ });
+ });
+ }
+ It->second = Res;
+ return Res;
+ };
auto IsExternallyUsed = [&](const TreeEntry &TE, Value *V) {
assert(TE.hasState() && !TE.isGather() &&
TE.State != TreeEntry::SplitVectorize && "Expected vector node.");
- if (V->hasOneUse() || V->getType()->isVoidTy())
- return false;
if (TE.hasCopyableElements() && TE.isCopyableElement(V))
return false;
- const size_t NumVectScalars = ScalarToTreeEntries.size() + 1;
- if (V->hasNUsesOrMore(NumVectScalars))
- return true;
- auto *I = dyn_cast<Instruction>(V);
- // Check if any user is used outside of the tree.
- return I && any_of(I->users(), [&](const User *U) {
- // store/insertelt v, [cast]U will likely be vectorized.
- if (match(U, m_InsertElt(m_Value(),
- m_OneUse(m_CastOrSelf(m_Specific(I))),
- m_ConstantInt())))
- return false;
- if (match(U,
- m_InsertElt(m_Value(), m_Specific(I), m_ConstantInt())))
- return false;
- if (match(U, m_Store(m_OneUse(m_CastOrSelf(m_Specific(I))),
- m_Value())))
- return false;
- if (match(U, m_Store(m_Specific(I), m_Value())))
- return false;
- ArrayRef<TreeEntry *> Entries = getTreeEntries(U);
- if (Entries.empty() && !MustGather.contains(U))
- return true;
- if (any_of(Entries, [&](TreeEntry *TE) {
- return DeletedNodes.contains(TE);
- }))
- return true;
- return any_of(ValueToGatherNodes.lookup(U),
- [&](const TreeEntry *TE) {
- return DeletedNodes.contains(TE);
- });
- });
+ return IsExternallyUsedV(V);
};
constexpr TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
InstructionCost Cost = 0;
More information about the llvm-commits
mailing list