24#define DEBUG_TYPE "spirv-convergence-region-analysis"
34 "SPIRV convergence regions analysis",
true,
true)
46template <
typename BasicBlockType,
typename IntrinsicInstType>
47std::optional<IntrinsicInstType *>
48getConvergenceTokenInternal(BasicBlockType *BB) {
49 static_assert(std::is_const_v<IntrinsicInstType> ==
50 std::is_const_v<BasicBlockType>,
51 "Constness must match between input and output.");
52 static_assert(std::is_same_v<BasicBlock, std::remove_const_t<BasicBlockType>>,
53 "Input must be a basic block.");
55 std::is_same_v<IntrinsicInst, std::remove_const_t<IntrinsicInstType>>,
56 "Output type must be an intrinsic instruction.");
59 if (
auto *
II = dyn_cast<IntrinsicInst>(&
I)) {
60 switch (
II->getIntrinsicID()) {
61 case Intrinsic::experimental_convergence_entry:
62 case Intrinsic::experimental_convergence_loop:
64 case Intrinsic::experimental_convergence_anchor: {
66 assert(Bundle->Inputs.size() == 1 &&
67 Bundle->Inputs[0]->getType()->isTokenTy());
68 auto TII = dyn_cast<IntrinsicInst>(Bundle->Inputs[0].get());
75 if (
auto *CI = dyn_cast<CallInst>(&
I)) {
79 return dyn_cast<IntrinsicInst>(OB.value().Inputs[0]);
94 while (Candidate != NextCandidate && NextCandidate !=
nullptr) {
95 Candidate = NextCandidate;
96 NextCandidate =
nullptr;
102 for (
auto *Child : Candidate->
Children) {
103 if (Child->Blocks.count(Entry) != 0) {
104 NextCandidate = Child;
116 return getConvergenceTokenInternal<BasicBlock, IntrinsicInst>(BB);
120 return getConvergenceTokenInternal<const BasicBlock, const IntrinsicInst>(BB);
125 : DT(DT), LI(LI), Parent(nullptr) {
126 Entry = &
F.getEntryBlock();
130 if (isa<ReturnInst>(
B.getTerminator()))
137 std::optional<IntrinsicInst *> ConvergenceToken,
BasicBlock *Entry,
139 : DT(DT), LI(LI), ConvergenceToken(ConvergenceToken), Entry(Entry),
141 for ([[maybe_unused]]
auto *BB : this->
Exits)
157 const std::string Indent(IndentSize,
'\t');
158 dbgs() << Indent <<
this <<
": {\n";
159 dbgs() << Indent <<
" Parent: " <<
Parent <<
"\n";
170 dbgs() << Indent <<
" Entry: " <<
Entry <<
"\n";
172 dbgs() << Indent <<
" Exits: { ";
173 for (
const auto &Exit :
Exits) {
174 if (Exit->getName() !=
"")
175 dbgs() << Exit->getName() <<
", ";
177 dbgs() << Exit <<
", ";
181 dbgs() << Indent <<
" Blocks: { ";
183 if (
Block->getName() !=
"")
190 dbgs() << Indent <<
" Children: {\n";
192 Child->dump(IndentSize + 2);
193 dbgs() << Indent <<
" }\n";
195 dbgs() << Indent <<
"}\n";
202 : DT(DT), LI(LI),
F(
F) {}
206 assert(
From != To &&
"From == To. This is awkward.");
216 if (L->contains(
From) && L->isLoopLatch(
From))
222 std::unordered_set<BasicBlock *>
224 std::function<
bool(
const BasicBlock *)> isMatch)
const {
225 std::unordered_set<BasicBlock *> Output;
230 auto *Terminator =
From->getTerminator();
231 for (
unsigned i = 0; i < Terminator->getNumSuccessors(); ++i) {
232 auto *To = Terminator->getSuccessor(i);
233 if (isBackEdge(
From, To))
236 auto ChildSet = findPathsToMatch(LI, To, isMatch);
237 if (ChildSet.size() == 0)
240 Output.insert(ChildSet.begin(), ChildSet.end());
244 for (
auto *BB : L->getBlocks()) {
257 for (
auto *
B : RegionBlocks) {
259 for (
unsigned i = 0; i <
Terminator->getNumSuccessors(); ++i) {
261 if (RegionBlocks.count(Child) == 0)
272 std::queue<Loop *> ToProcess;
276 while (ToProcess.size() != 0) {
277 auto *L = ToProcess.front();
279 assert(L->isLoopSimplifyForm());
285 L->getExitingBlocks(LoopExits);
286 if (CT.has_value()) {
287 for (
auto *Exit : LoopExits) {
290 if (Token == std::nullopt)
292 return Token.value() == CT.value();
294 RegionBlocks.
insert(
N.begin(),
N.end());
298 auto RegionExits = findExitNodes(RegionBlocks);
300 DT, LI, CT, L->getHeader(), std::move(RegionBlocks),
301 std::move(RegionExits));
302 Region->Parent = findParentRegion(TopLevelRegion,
Region->Entry);
303 assert(
Region->Parent !=
nullptr &&
"This is impossible.");
331 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
332 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
BlockVerifier::State From
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
DenseMap< Block *, BlockRelaxAux > Blocks
const HexagonInstrInfo * TII
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
convergence SPIRV convergence regions true
convergence SPIRV convergence regions analysis
unify loop Fixup each natural loop to have a single exit block
A container for analyses that lazily runs them and caches their results.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
Analysis pass which computes a DominatorTree.
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
FunctionPass class - This class is used to implement most global optimizations.
Analysis pass that exposes the LoopInfo for a function.
bool isLoopHeader(const BlockT *BB) const
SmallVector< LoopT *, 4 > getLoopsInPreorder() const
Return all of the loops in the function in preorder across the loop nests, with siblings in forward p...
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
The legacy pass manager's analysis pass to compute loop information.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
bool runOnFunction(Function &F) override
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
SPIRVConvergenceRegionAnalysisWrapperPass()
Result run(Function &F, FunctionAnalysisManager &AM)
ConvergenceRegionAnalyzer(Function &F, DominatorTree &DT, LoopInfo &LI)
ConvergenceRegionInfo analyze()
SmallVector< ConvergenceRegion * > Children
SmallPtrSet< BasicBlock *, 2 > Exits
std::optional< IntrinsicInst * > ConvergenceToken
ConvergenceRegion * Parent
void dump(const unsigned IndentSize=0) const
ConvergenceRegion(DominatorTree &DT, LoopInfo &LI, Function &F)
SmallPtrSet< BasicBlock *, 8 > Blocks
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef getName() const
Return a constant reference to the value's name.
ConvergenceRegionInfo getConvergenceRegions(Function &F, DominatorTree &DT, LoopInfo &LI)
std::optional< IntrinsicInst * > getConvergenceToken(BasicBlock *BB)
This is an optimization pass for GlobalISel generic memory operations.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
void initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PassRegistry &)
Implement std::hash so that hash_code can be used in STL containers.
A special type used by analysis passes to provide an address that identifies that particular analysis...