[llvm] [NFC][SPIR-V] Fuse redundant full-traversal loops in prepare/emit-intrinsics/structurizer passes (PR #211299)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 22 08:47:31 PDT 2026
https://github.com/aobolensk created https://github.com/llvm/llvm-project/pull/211299
None
>From c03f56890a73f3f3e5a39101973d6f3d4a6eba08 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 22 Jul 2026 17:46:57 +0200
Subject: [PATCH] [NFC][SPIR-V] Fuse redundant full-traversal loops in
prepare/emit-intrinsics/structurizer passes
---
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 19 ++---
.../Target/SPIRV/SPIRVPrepareFunctions.cpp | 27 +++----
llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp | 76 +++++++++----------
3 files changed, 51 insertions(+), 71 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index e5afaa5c63e4b..cd3ded2334b26 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -3643,6 +3643,13 @@ bool SPIRVEmitIntrinsicsImpl::runOnFunction(Function &Func) {
// Data structure for dead instructions that were simplified and replaced.
SmallPtrSet<Instruction *, 4> DeadInsts;
for (auto &I : instructions(Func)) {
+ if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
+ Type *ElTy = SI->getValueOperand()->getType();
+ if (ElTy->isAggregateType() || ElTy->isVectorTy())
+ AggrStores.insert(&I);
+ continue;
+ }
+
auto *GEP = dyn_cast<GetElementPtrInst>(&I);
auto *SGEP = dyn_cast<StructuredGEPInst>(&I);
@@ -3670,18 +3677,6 @@ bool SPIRVEmitIntrinsicsImpl::runOnFunction(Function &Func) {
I->eraseFromParent();
}
- // StoreInst's operand type can be changed during the next
- // transformations, so we need to store it in the set. Also store already
- // transformed types.
- for (auto &I : instructions(Func)) {
- StoreInst *SI = dyn_cast<StoreInst>(&I);
- if (!SI)
- continue;
- Type *ElTy = SI->getValueOperand()->getType();
- if (ElTy->isAggregateType() || ElTy->isVectorTy())
- AggrStores.insert(&I);
- }
-
B.SetInsertPoint(&Func.getEntryBlock(), Func.getEntryBlock().begin());
for (auto &GV : Func.getParent()->globals())
processGlobalValue(GV, B);
diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
index 9b418e6f88d67..6d54b6c6fa19d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
@@ -695,20 +695,18 @@ bool SPIRVPrepareFunctionsImpl::substituteAbortKHRCalls(Function *F) {
if (!isAbortKHRBuiltin(*F))
return false;
- SmallVector<CallInst *> Calls;
- for (User *U : F->users()) {
+ bool Changed = false;
+ for (User *U : make_early_inc_range(F->users())) {
auto *CI = dyn_cast<CallInst>(U);
if (!CI || CI->getCalledFunction() != F)
continue;
if (CI->arg_size() != 1)
continue;
- Calls.push_back(CI);
- }
-
- for (CallInst *CI : Calls)
rewriteAbortKHRCall(CI);
+ Changed = true;
+ }
- return !Calls.empty();
+ return Changed;
}
// When the SPV_KHR_abort extension is enabled, `llvm.trap` and
@@ -734,16 +732,11 @@ bool SPIRVPrepareFunctionsImpl::terminateBlocksAfterTrap(Module &M,
if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort))
return false;
- SmallVector<CallInst *> Calls;
- for (User *U : F->users()) {
+ bool Changed = false;
+ for (User *U : make_early_inc_range(F->users())) {
auto *CI = dyn_cast<CallInst>(U);
if (!CI || CI->getCalledFunction() != F)
continue;
- Calls.push_back(CI);
- }
-
- bool Changed = false;
- for (CallInst *CI : Calls) {
Instruction *Next = CI->getNextNode();
if (!Next || isa<UnreachableInst>(Next))
continue;
@@ -883,6 +876,7 @@ bool SPIRVPrepareFunctionsImpl::runOnModule(Module &M) {
}
}
+ std::vector<Function *> FuncsWorklist;
for (Function &F : M) {
// MachineFunctionPass skips available_externally; strip + tag so AuxData
// can re-emit the original linkage as NonSemantic.AuxData::Linkage.
@@ -895,11 +889,8 @@ bool SPIRVPrepareFunctionsImpl::runOnModule(Module &M) {
Changed |= substituteIntrinsicCalls(&F);
Changed |= sortBlocks(F);
Changed |= removeAggregateTypesFromCalls(&F);
- }
-
- std::vector<Function *> FuncsWorklist;
- for (auto &F : M)
FuncsWorklist.push_back(&F);
+ }
for (auto *F : FuncsWorklist) {
Function *NewF = removeAggregateTypesFromSignature(F);
diff --git a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
index 0e6f5ecab1437..13b27d09ca9ef 100644
--- a/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVStructurizer.cpp
@@ -131,33 +131,6 @@ static bool isMergeInstruction(Instruction *I) {
return getDesignatedMergeBlock(I) != nullptr;
}
-// Returns all blocks in F having at least one OpLoopMerge or OpSelectionMerge
-// instruction.
-static SmallPtrSet<BasicBlock *, 2> getHeaderBlocks(Function &F) {
- SmallPtrSet<BasicBlock *, 2> Output;
- for (BasicBlock &BB : F) {
- for (Instruction &I : BB) {
- if (getDesignatedMergeBlock(&I) != nullptr)
- Output.insert(&BB);
- }
- }
- return Output;
-}
-
-// Returns all basic blocks in |F| referenced by at least 1
-// OpSelectionMerge/OpLoopMerge instruction.
-static SmallPtrSet<BasicBlock *, 2> getMergeBlocks(Function &F) {
- SmallPtrSet<BasicBlock *, 2> Output;
- for (BasicBlock &BB : F) {
- for (Instruction &I : BB) {
- BasicBlock *MB = getDesignatedMergeBlock(&I);
- if (MB != nullptr)
- Output.insert(MB);
- }
- }
- return Output;
-}
-
// Return all the merge instructions contained in BB.
// Note: the SPIR-V spec doesn't allow a single BB to contain more than 1 merge
// instruction, but this can happen while we structurize the CFG.
@@ -169,15 +142,33 @@ static std::vector<Instruction *> getMergeInstructions(BasicBlock &BB) {
return Output;
}
-// Returns all basic blocks in |F| referenced as continue target by at least 1
-// OpLoopMerge instruction.
-static SmallPtrSet<BasicBlock *, 2> getContinueBlocks(Function &F) {
- SmallPtrSet<BasicBlock *, 2> Output;
+// Bundles the header/merge/continue block sets computed by
+// getHeaderMergeContinueBlocks so callers only needing a subset of them can
+// still share the single underlying scan.
+struct HeaderMergeContinueBlocks {
+ // Blocks in F having at least one OpLoopMerge or OpSelectionMerge
+ // instruction.
+ SmallPtrSet<BasicBlock *, 2> Header;
+ // Blocks in F referenced by at least 1 OpSelectionMerge/OpLoopMerge
+ // instruction.
+ SmallPtrSet<BasicBlock *, 2> Merge;
+ // Blocks in F referenced as continue target by at least 1 OpLoopMerge
+ // instruction.
+ SmallPtrSet<BasicBlock *, 2> Continue;
+};
+
+// Computes Header, Merge and Continue block sets for |F| in a single scan,
+// since they all classify the same instructions.
+static HeaderMergeContinueBlocks getHeaderMergeContinueBlocks(Function &F) {
+ HeaderMergeContinueBlocks Output;
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
- BasicBlock *MB = getDesignatedContinueBlock(&I);
- if (MB != nullptr)
- Output.insert(MB);
+ if (BasicBlock *MB = getDesignatedMergeBlock(&I)) {
+ Output.Header.insert(&BB);
+ Output.Merge.insert(MB);
+ }
+ if (BasicBlock *CB = getDesignatedContinueBlock(&I))
+ Output.Continue.insert(CB);
}
}
return Output;
@@ -689,8 +680,9 @@ class SPIRVStructurizerImpl {
PDT.recalculate(F);
bool Modified = false;
- auto MergeBlocks = getMergeBlocks(F);
- auto ContinueBlocks = getContinueBlocks(F);
+ HeaderMergeContinueBlocks Blocks = getHeaderMergeContinueBlocks(F);
+ auto &MergeBlocks = Blocks.Merge;
+ auto &ContinueBlocks = Blocks.Continue;
for (auto &BB : F) {
if (getMergeInstructions(BB).size() != 0)
@@ -956,8 +948,9 @@ class SPIRVStructurizerImpl {
bool removeUselessBlocks(Function &F) {
std::vector<BasicBlock *> ToRemove;
- auto MergeBlocks = getMergeBlocks(F);
- auto ContinueBlocks = getContinueBlocks(F);
+ HeaderMergeContinueBlocks Blocks = getHeaderMergeContinueBlocks(F);
+ auto &MergeBlocks = Blocks.Merge;
+ auto &ContinueBlocks = Blocks.Continue;
for (BasicBlock &BB : F) {
if (BB.size() != 1)
@@ -989,9 +982,10 @@ class SPIRVStructurizerImpl {
bool addHeaderToRemainingDivergentDAG(Function &F) {
bool Modified = false;
- auto MergeBlocks = getMergeBlocks(F);
- auto ContinueBlocks = getContinueBlocks(F);
- auto HeaderBlocks = getHeaderBlocks(F);
+ HeaderMergeContinueBlocks Blocks = getHeaderMergeContinueBlocks(F);
+ auto &MergeBlocks = Blocks.Merge;
+ auto &ContinueBlocks = Blocks.Continue;
+ auto &HeaderBlocks = Blocks.Header;
DomTreeBuilder::BBDomTree DT;
DomTreeBuilder::BBPostDomTree PDT;
More information about the llvm-commits
mailing list