[llvm] ad23908 - [SLP][NFC]Cache isUsedOutsideBlock results in gather-shuffle analysis
via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 28 06:05:33 PDT 2026
Author: Alexey Bataev
Date: 2026-04-28T09:05:27-04:00
New Revision: ad2390871a5d77a12bdd9074ba6209cef4553a8f
URL: https://github.com/llvm/llvm-project/commit/ad2390871a5d77a12bdd9074ba6209cef4553a8f
DIFF: https://github.com/llvm/llvm-project/commit/ad2390871a5d77a12bdd9074ba6209cef4553a8f.diff
LOG: [SLP][NFC]Cache isUsedOutsideBlock results in gather-shuffle analysis
Hoist loop-invariant predicates and memoize per-UserTE
all_of(Scalars, isUsedOutsideBlock) in
isGatherShuffledSingleRegisterEntry and vectorizeTree to avoid
redundant walks over scalar user lists in the gather-shuffle hot path.
Reviewers:
Pull Request: https://github.com/llvm/llvm-project/pull/194612
Added:
Modified:
llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 3e40d49104315..7826076edf435 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -19702,16 +19702,50 @@ BoUpSLP::isGatherShuffledSingleRegisterEntry(
}
return false;
};
+ // Cache `isUsedOutsideBlock(TEInsertPt)` - TEInsertPt is loop-invariant and
+ // the function walks the instruction's user list.
+ std::optional<bool> TEInsertPtUsedOutsideBlock;
+ auto IsTEInsertPtUsedOutsideBlock = [&] {
+ if (!TEInsertPtUsedOutsideBlock)
+ TEInsertPtUsedOutsideBlock =
+ isUsedOutsideBlock(const_cast<Instruction *>(TEInsertPt));
+ return *TEInsertPtUsedOutsideBlock;
+ };
+ // Cache the TEUseEI/TEInsertPt-only prefix of the per-call lambda predicate
+ // below - all of these depend only on outer-scope state, not the lambda's
+ // arguments.
+ const bool TEUseEIInsertPtUsedOutside =
+ TEUseEI && TEUseEI.UserTE && TEUseEI.UserTE->hasCopyableElements() &&
+ !TEUseEI.UserTE->isCopyableElement(
+ const_cast<Instruction *>(TEInsertPt)) &&
+ IsTEInsertPtUsedOutsideBlock();
auto CheckNonSchedulableOrdering = [&](const TreeEntry *E,
Instruction *InsertPt) {
- return TEUseEI && TEUseEI.UserTE && TEUseEI.UserTE->hasCopyableElements() &&
- !TEUseEI.UserTE->isCopyableElement(
- const_cast<Instruction *>(TEInsertPt)) &&
- isUsedOutsideBlock(const_cast<Instruction *>(TEInsertPt)) &&
+ return TEUseEIInsertPtUsedOutside &&
InsertPt->getNextNode() == TEInsertPt &&
(!E->hasCopyableElements() || !E->isCopyableElement(InsertPt) ||
!isUsedOutsideBlock(InsertPt));
};
+ // Cache the TEUseEI.UserTE-dependent predicate - it is invariant across the
+ // double loop below. all_of with isUsedOutsideBlock walks each scalar's
+ // users and is the expensive component.
+ const bool TEUserNeedsEmitFirst =
+ TEUseEI.UserTE->State == TreeEntry::Vectorize &&
+ TEUseEI.UserTE->hasState() &&
+ (TEUseEI.UserTE->getOpcode() != Instruction::PHI ||
+ TEUseEI.UserTE->isAltShuffle()) &&
+ all_of(TEUseEI.UserTE->Scalars, isUsedOutsideBlock);
+ // Cache `all_of(UserTE->Scalars, isUsedOutsideBlock)` per UserTE - the
+ // same UserTE may be encountered for many TEPtr values inside the loop.
+ SmallDenseMap<const TreeEntry *, bool> ScalarsUsedOutsideBlockCache;
+ auto AllScalarsUsedOutsideBlock = [&](const TreeEntry *UserTE) {
+ auto [It, Inserted] = ScalarsUsedOutsideBlockCache.try_emplace(UserTE);
+ if (!Inserted)
+ return It->second;
+ bool Res = all_of(UserTE->Scalars, isUsedOutsideBlock);
+ It->second = Res;
+ return Res;
+ };
for (Value *V : VL) {
if (isConstant(V) || !VisitedValue.insert(V).second)
continue;
@@ -19755,15 +19789,12 @@ BoUpSLP::isGatherShuffledSingleRegisterEntry(
: &getLastInstructionInBundle(UseEI.UserTE);
if (TEInsertPt == InsertPt) {
// Check nodes, which might be emitted first.
- if (TEUseEI.UserTE->State == TreeEntry::Vectorize &&
- (TEUseEI.UserTE->getOpcode() != Instruction::PHI ||
- TEUseEI.UserTE->isAltShuffle()) &&
- all_of(TEUseEI.UserTE->Scalars, isUsedOutsideBlock)) {
+ if (TEUserNeedsEmitFirst) {
if (UseEI.UserTE->State != TreeEntry::Vectorize ||
(UseEI.UserTE->hasState() &&
UseEI.UserTE->getOpcode() == Instruction::PHI &&
!UseEI.UserTE->isAltShuffle()) ||
- !all_of(UseEI.UserTE->Scalars, isUsedOutsideBlock))
+ !AllScalarsUsedOutsideBlock(UseEI.UserTE))
continue;
}
@@ -19807,7 +19838,7 @@ BoUpSLP::isGatherShuffledSingleRegisterEntry(
TEUseEI.EdgeIdx < UseEI.EdgeIdx || TEUseEI.UserTE != UseEI.UserTE) &&
(!CheckOrdering(InsertPt) ||
(UseEI.UserTE->hasCopyableElements() &&
- isUsedOutsideBlock(const_cast<Instruction *>(TEInsertPt)) &&
+ IsTEInsertPtUsedOutsideBlock() &&
is_contained(UseEI.UserTE->Scalars, TEInsertPt))))
continue;
// The node is reused - exit.
@@ -23256,6 +23287,10 @@ Value *BoUpSLP::vectorizeTree(
// Vectorize gather operands of the nodes with the external uses only.
SmallVector<std::pair<TreeEntry *, Instruction *>> GatherEntries;
+ // Multiple gather TEs may share the same UserTE - cache the per-UserTE
+ // all_of-isUsedOutsideBlock result to avoid re-walking each scalar's
+ // user list.
+ SmallDenseMap<const TreeEntry *, bool> UserTEScalarsUsedOutsideBlockCache;
for (const std::unique_ptr<TreeEntry> &TE : VectorizableTree) {
if (DeletedNodes.contains(TE.get()))
continue;
@@ -23264,11 +23299,16 @@ Value *BoUpSLP::vectorizeTree(
TE->UserTreeIndex.UserTE->State == TreeEntry::Vectorize &&
(TE->UserTreeIndex.UserTE->getOpcode() != Instruction::PHI ||
TE->UserTreeIndex.UserTE->isAltShuffle()) &&
- !TE->UserTreeIndex.UserTE->hasCopyableElements() &&
- all_of(TE->UserTreeIndex.UserTE->Scalars,
- [](Value *V) { return isUsedOutsideBlock(V); })) {
- Instruction &LastInst =
- getLastInstructionInBundle(TE->UserTreeIndex.UserTE);
+ !TE->UserTreeIndex.UserTE->hasCopyableElements()) {
+ const TreeEntry *UserTE = TE->UserTreeIndex.UserTE;
+ auto [It, Inserted] =
+ UserTEScalarsUsedOutsideBlockCache.try_emplace(UserTE);
+ if (Inserted)
+ It->second = all_of(UserTE->Scalars,
+ [](Value *V) { return isUsedOutsideBlock(V); });
+ if (!It->second)
+ continue;
+ Instruction &LastInst = getLastInstructionInBundle(UserTE);
GatherEntries.emplace_back(TE.get(), &LastInst);
}
}
More information about the llvm-commits
mailing list