xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/Analysis/SPIRVConvergenceRegionAnalysis.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- ConvergenceRegionAnalysis.h -----------------------------*- C++ -*--===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // The analysis determines the convergence region for each basic block of
10*0fca6ea1SDimitry Andric // the module, and provides a tree-like structure describing the region
11*0fca6ea1SDimitry Andric // hierarchy.
12*0fca6ea1SDimitry Andric //
13*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
14*0fca6ea1SDimitry Andric 
15*0fca6ea1SDimitry Andric #include "SPIRVConvergenceRegionAnalysis.h"
16*0fca6ea1SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
17*0fca6ea1SDimitry Andric #include "llvm/IR/Dominators.h"
18*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
19*0fca6ea1SDimitry Andric #include "llvm/InitializePasses.h"
20*0fca6ea1SDimitry Andric #include "llvm/Transforms/Utils/LoopSimplify.h"
21*0fca6ea1SDimitry Andric #include <optional>
22*0fca6ea1SDimitry Andric #include <queue>
23*0fca6ea1SDimitry Andric 
24*0fca6ea1SDimitry Andric #define DEBUG_TYPE "spirv-convergence-region-analysis"
25*0fca6ea1SDimitry Andric 
26*0fca6ea1SDimitry Andric using namespace llvm;
27*0fca6ea1SDimitry Andric 
28*0fca6ea1SDimitry Andric namespace llvm {
29*0fca6ea1SDimitry Andric void initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PassRegistry &);
30*0fca6ea1SDimitry Andric } // namespace llvm
31*0fca6ea1SDimitry Andric 
32*0fca6ea1SDimitry Andric INITIALIZE_PASS_BEGIN(SPIRVConvergenceRegionAnalysisWrapperPass,
33*0fca6ea1SDimitry Andric                       "convergence-region",
34*0fca6ea1SDimitry Andric                       "SPIRV convergence regions analysis", true, true)
35*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LoopSimplify)
36*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
37*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
38*0fca6ea1SDimitry Andric INITIALIZE_PASS_END(SPIRVConvergenceRegionAnalysisWrapperPass,
39*0fca6ea1SDimitry Andric                     "convergence-region", "SPIRV convergence regions analysis",
40*0fca6ea1SDimitry Andric                     true, true)
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric namespace llvm {
43*0fca6ea1SDimitry Andric namespace SPIRV {
44*0fca6ea1SDimitry Andric namespace {
45*0fca6ea1SDimitry Andric 
46*0fca6ea1SDimitry Andric template <typename BasicBlockType, typename IntrinsicInstType>
47*0fca6ea1SDimitry Andric std::optional<IntrinsicInstType *>
48*0fca6ea1SDimitry Andric getConvergenceTokenInternal(BasicBlockType *BB) {
49*0fca6ea1SDimitry Andric   static_assert(std::is_const_v<IntrinsicInstType> ==
50*0fca6ea1SDimitry Andric                     std::is_const_v<BasicBlockType>,
51*0fca6ea1SDimitry Andric                 "Constness must match between input and output.");
52*0fca6ea1SDimitry Andric   static_assert(std::is_same_v<BasicBlock, std::remove_const_t<BasicBlockType>>,
53*0fca6ea1SDimitry Andric                 "Input must be a basic block.");
54*0fca6ea1SDimitry Andric   static_assert(
55*0fca6ea1SDimitry Andric       std::is_same_v<IntrinsicInst, std::remove_const_t<IntrinsicInstType>>,
56*0fca6ea1SDimitry Andric       "Output type must be an intrinsic instruction.");
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric   for (auto &I : *BB) {
59*0fca6ea1SDimitry Andric     if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
60*0fca6ea1SDimitry Andric       switch (II->getIntrinsicID()) {
61*0fca6ea1SDimitry Andric       case Intrinsic::experimental_convergence_entry:
62*0fca6ea1SDimitry Andric       case Intrinsic::experimental_convergence_loop:
63*0fca6ea1SDimitry Andric         return II;
64*0fca6ea1SDimitry Andric       case Intrinsic::experimental_convergence_anchor: {
65*0fca6ea1SDimitry Andric         auto Bundle = II->getOperandBundle(LLVMContext::OB_convergencectrl);
66*0fca6ea1SDimitry Andric         assert(Bundle->Inputs.size() == 1 &&
67*0fca6ea1SDimitry Andric                Bundle->Inputs[0]->getType()->isTokenTy());
68*0fca6ea1SDimitry Andric         auto TII = dyn_cast<IntrinsicInst>(Bundle->Inputs[0].get());
69*0fca6ea1SDimitry Andric         assert(TII != nullptr);
70*0fca6ea1SDimitry Andric         return TII;
71*0fca6ea1SDimitry Andric       }
72*0fca6ea1SDimitry Andric       }
73*0fca6ea1SDimitry Andric     }
74*0fca6ea1SDimitry Andric 
75*0fca6ea1SDimitry Andric     if (auto *CI = dyn_cast<CallInst>(&I)) {
76*0fca6ea1SDimitry Andric       auto OB = CI->getOperandBundle(LLVMContext::OB_convergencectrl);
77*0fca6ea1SDimitry Andric       if (!OB.has_value())
78*0fca6ea1SDimitry Andric         continue;
79*0fca6ea1SDimitry Andric       return dyn_cast<IntrinsicInst>(OB.value().Inputs[0]);
80*0fca6ea1SDimitry Andric     }
81*0fca6ea1SDimitry Andric   }
82*0fca6ea1SDimitry Andric 
83*0fca6ea1SDimitry Andric   return std::nullopt;
84*0fca6ea1SDimitry Andric }
85*0fca6ea1SDimitry Andric 
86*0fca6ea1SDimitry Andric // Given a ConvergenceRegion tree with |Start| as its root, finds the smallest
87*0fca6ea1SDimitry Andric // region |Entry| belongs to. If |Entry| does not belong to the region defined
88*0fca6ea1SDimitry Andric // by |Start|, this function returns |nullptr|.
89*0fca6ea1SDimitry Andric ConvergenceRegion *findParentRegion(ConvergenceRegion *Start,
90*0fca6ea1SDimitry Andric                                     BasicBlock *Entry) {
91*0fca6ea1SDimitry Andric   ConvergenceRegion *Candidate = nullptr;
92*0fca6ea1SDimitry Andric   ConvergenceRegion *NextCandidate = Start;
93*0fca6ea1SDimitry Andric 
94*0fca6ea1SDimitry Andric   while (Candidate != NextCandidate && NextCandidate != nullptr) {
95*0fca6ea1SDimitry Andric     Candidate = NextCandidate;
96*0fca6ea1SDimitry Andric     NextCandidate = nullptr;
97*0fca6ea1SDimitry Andric 
98*0fca6ea1SDimitry Andric     // End of the search, we can return.
99*0fca6ea1SDimitry Andric     if (Candidate->Children.size() == 0)
100*0fca6ea1SDimitry Andric       return Candidate;
101*0fca6ea1SDimitry Andric 
102*0fca6ea1SDimitry Andric     for (auto *Child : Candidate->Children) {
103*0fca6ea1SDimitry Andric       if (Child->Blocks.count(Entry) != 0) {
104*0fca6ea1SDimitry Andric         NextCandidate = Child;
105*0fca6ea1SDimitry Andric         break;
106*0fca6ea1SDimitry Andric       }
107*0fca6ea1SDimitry Andric     }
108*0fca6ea1SDimitry Andric   }
109*0fca6ea1SDimitry Andric 
110*0fca6ea1SDimitry Andric   return Candidate;
111*0fca6ea1SDimitry Andric }
112*0fca6ea1SDimitry Andric 
113*0fca6ea1SDimitry Andric } // anonymous namespace
114*0fca6ea1SDimitry Andric 
115*0fca6ea1SDimitry Andric std::optional<IntrinsicInst *> getConvergenceToken(BasicBlock *BB) {
116*0fca6ea1SDimitry Andric   return getConvergenceTokenInternal<BasicBlock, IntrinsicInst>(BB);
117*0fca6ea1SDimitry Andric }
118*0fca6ea1SDimitry Andric 
119*0fca6ea1SDimitry Andric std::optional<const IntrinsicInst *> getConvergenceToken(const BasicBlock *BB) {
120*0fca6ea1SDimitry Andric   return getConvergenceTokenInternal<const BasicBlock, const IntrinsicInst>(BB);
121*0fca6ea1SDimitry Andric }
122*0fca6ea1SDimitry Andric 
123*0fca6ea1SDimitry Andric ConvergenceRegion::ConvergenceRegion(DominatorTree &DT, LoopInfo &LI,
124*0fca6ea1SDimitry Andric                                      Function &F)
125*0fca6ea1SDimitry Andric     : DT(DT), LI(LI), Parent(nullptr) {
126*0fca6ea1SDimitry Andric   Entry = &F.getEntryBlock();
127*0fca6ea1SDimitry Andric   ConvergenceToken = getConvergenceToken(Entry);
128*0fca6ea1SDimitry Andric   for (auto &B : F) {
129*0fca6ea1SDimitry Andric     Blocks.insert(&B);
130*0fca6ea1SDimitry Andric     if (isa<ReturnInst>(B.getTerminator()))
131*0fca6ea1SDimitry Andric       Exits.insert(&B);
132*0fca6ea1SDimitry Andric   }
133*0fca6ea1SDimitry Andric }
134*0fca6ea1SDimitry Andric 
135*0fca6ea1SDimitry Andric ConvergenceRegion::ConvergenceRegion(
136*0fca6ea1SDimitry Andric     DominatorTree &DT, LoopInfo &LI,
137*0fca6ea1SDimitry Andric     std::optional<IntrinsicInst *> ConvergenceToken, BasicBlock *Entry,
138*0fca6ea1SDimitry Andric     SmallPtrSet<BasicBlock *, 8> &&Blocks, SmallPtrSet<BasicBlock *, 2> &&Exits)
139*0fca6ea1SDimitry Andric     : DT(DT), LI(LI), ConvergenceToken(ConvergenceToken), Entry(Entry),
140*0fca6ea1SDimitry Andric       Exits(std::move(Exits)), Blocks(std::move(Blocks)) {
141*0fca6ea1SDimitry Andric   for ([[maybe_unused]] auto *BB : this->Exits)
142*0fca6ea1SDimitry Andric     assert(this->Blocks.count(BB) != 0);
143*0fca6ea1SDimitry Andric   assert(this->Blocks.count(this->Entry) != 0);
144*0fca6ea1SDimitry Andric }
145*0fca6ea1SDimitry Andric 
146*0fca6ea1SDimitry Andric void ConvergenceRegion::releaseMemory() {
147*0fca6ea1SDimitry Andric   // Parent memory is owned by the parent.
148*0fca6ea1SDimitry Andric   Parent = nullptr;
149*0fca6ea1SDimitry Andric   for (auto *Child : Children) {
150*0fca6ea1SDimitry Andric     Child->releaseMemory();
151*0fca6ea1SDimitry Andric     delete Child;
152*0fca6ea1SDimitry Andric   }
153*0fca6ea1SDimitry Andric   Children.resize(0);
154*0fca6ea1SDimitry Andric }
155*0fca6ea1SDimitry Andric 
156*0fca6ea1SDimitry Andric void ConvergenceRegion::dump(const unsigned IndentSize) const {
157*0fca6ea1SDimitry Andric   const std::string Indent(IndentSize, '\t');
158*0fca6ea1SDimitry Andric   dbgs() << Indent << this << ": {\n";
159*0fca6ea1SDimitry Andric   dbgs() << Indent << "	Parent: " << Parent << "\n";
160*0fca6ea1SDimitry Andric 
161*0fca6ea1SDimitry Andric   if (ConvergenceToken.value_or(nullptr)) {
162*0fca6ea1SDimitry Andric     dbgs() << Indent
163*0fca6ea1SDimitry Andric            << "	ConvergenceToken: " << ConvergenceToken.value()->getName()
164*0fca6ea1SDimitry Andric            << "\n";
165*0fca6ea1SDimitry Andric   }
166*0fca6ea1SDimitry Andric 
167*0fca6ea1SDimitry Andric   if (Entry->getName() != "")
168*0fca6ea1SDimitry Andric     dbgs() << Indent << "	Entry: " << Entry->getName() << "\n";
169*0fca6ea1SDimitry Andric   else
170*0fca6ea1SDimitry Andric     dbgs() << Indent << "	Entry: " << Entry << "\n";
171*0fca6ea1SDimitry Andric 
172*0fca6ea1SDimitry Andric   dbgs() << Indent << "	Exits: { ";
173*0fca6ea1SDimitry Andric   for (const auto &Exit : Exits) {
174*0fca6ea1SDimitry Andric     if (Exit->getName() != "")
175*0fca6ea1SDimitry Andric       dbgs() << Exit->getName() << ", ";
176*0fca6ea1SDimitry Andric     else
177*0fca6ea1SDimitry Andric       dbgs() << Exit << ", ";
178*0fca6ea1SDimitry Andric   }
179*0fca6ea1SDimitry Andric   dbgs() << "	}\n";
180*0fca6ea1SDimitry Andric 
181*0fca6ea1SDimitry Andric   dbgs() << Indent << "	Blocks: { ";
182*0fca6ea1SDimitry Andric   for (const auto &Block : Blocks) {
183*0fca6ea1SDimitry Andric     if (Block->getName() != "")
184*0fca6ea1SDimitry Andric       dbgs() << Block->getName() << ", ";
185*0fca6ea1SDimitry Andric     else
186*0fca6ea1SDimitry Andric       dbgs() << Block << ", ";
187*0fca6ea1SDimitry Andric   }
188*0fca6ea1SDimitry Andric   dbgs() << "	}\n";
189*0fca6ea1SDimitry Andric 
190*0fca6ea1SDimitry Andric   dbgs() << Indent << "	Children: {\n";
191*0fca6ea1SDimitry Andric   for (const auto Child : Children)
192*0fca6ea1SDimitry Andric     Child->dump(IndentSize + 2);
193*0fca6ea1SDimitry Andric   dbgs() << Indent << "	}\n";
194*0fca6ea1SDimitry Andric 
195*0fca6ea1SDimitry Andric   dbgs() << Indent << "}\n";
196*0fca6ea1SDimitry Andric }
197*0fca6ea1SDimitry Andric 
198*0fca6ea1SDimitry Andric class ConvergenceRegionAnalyzer {
199*0fca6ea1SDimitry Andric 
200*0fca6ea1SDimitry Andric public:
201*0fca6ea1SDimitry Andric   ConvergenceRegionAnalyzer(Function &F, DominatorTree &DT, LoopInfo &LI)
202*0fca6ea1SDimitry Andric       : DT(DT), LI(LI), F(F) {}
203*0fca6ea1SDimitry Andric 
204*0fca6ea1SDimitry Andric private:
205*0fca6ea1SDimitry Andric   bool isBackEdge(const BasicBlock *From, const BasicBlock *To) const {
206*0fca6ea1SDimitry Andric     assert(From != To && "From == To. This is awkward.");
207*0fca6ea1SDimitry Andric 
208*0fca6ea1SDimitry Andric     // We only handle loop in the simplified form. This means:
209*0fca6ea1SDimitry Andric     // - a single back-edge, a single latch.
210*0fca6ea1SDimitry Andric     // - meaning the back-edge target can only be the loop header.
211*0fca6ea1SDimitry Andric     // - meaning the From can only be the loop latch.
212*0fca6ea1SDimitry Andric     if (!LI.isLoopHeader(To))
213*0fca6ea1SDimitry Andric       return false;
214*0fca6ea1SDimitry Andric 
215*0fca6ea1SDimitry Andric     auto *L = LI.getLoopFor(To);
216*0fca6ea1SDimitry Andric     if (L->contains(From) && L->isLoopLatch(From))
217*0fca6ea1SDimitry Andric       return true;
218*0fca6ea1SDimitry Andric 
219*0fca6ea1SDimitry Andric     return false;
220*0fca6ea1SDimitry Andric   }
221*0fca6ea1SDimitry Andric 
222*0fca6ea1SDimitry Andric   std::unordered_set<BasicBlock *>
223*0fca6ea1SDimitry Andric   findPathsToMatch(LoopInfo &LI, BasicBlock *From,
224*0fca6ea1SDimitry Andric                    std::function<bool(const BasicBlock *)> isMatch) const {
225*0fca6ea1SDimitry Andric     std::unordered_set<BasicBlock *> Output;
226*0fca6ea1SDimitry Andric 
227*0fca6ea1SDimitry Andric     if (isMatch(From))
228*0fca6ea1SDimitry Andric       Output.insert(From);
229*0fca6ea1SDimitry Andric 
230*0fca6ea1SDimitry Andric     auto *Terminator = From->getTerminator();
231*0fca6ea1SDimitry Andric     for (unsigned i = 0; i < Terminator->getNumSuccessors(); ++i) {
232*0fca6ea1SDimitry Andric       auto *To = Terminator->getSuccessor(i);
233*0fca6ea1SDimitry Andric       if (isBackEdge(From, To))
234*0fca6ea1SDimitry Andric         continue;
235*0fca6ea1SDimitry Andric 
236*0fca6ea1SDimitry Andric       auto ChildSet = findPathsToMatch(LI, To, isMatch);
237*0fca6ea1SDimitry Andric       if (ChildSet.size() == 0)
238*0fca6ea1SDimitry Andric         continue;
239*0fca6ea1SDimitry Andric 
240*0fca6ea1SDimitry Andric       Output.insert(ChildSet.begin(), ChildSet.end());
241*0fca6ea1SDimitry Andric       Output.insert(From);
242*0fca6ea1SDimitry Andric       if (LI.isLoopHeader(From)) {
243*0fca6ea1SDimitry Andric         auto *L = LI.getLoopFor(From);
244*0fca6ea1SDimitry Andric         for (auto *BB : L->getBlocks()) {
245*0fca6ea1SDimitry Andric           Output.insert(BB);
246*0fca6ea1SDimitry Andric         }
247*0fca6ea1SDimitry Andric       }
248*0fca6ea1SDimitry Andric     }
249*0fca6ea1SDimitry Andric 
250*0fca6ea1SDimitry Andric     return Output;
251*0fca6ea1SDimitry Andric   }
252*0fca6ea1SDimitry Andric 
253*0fca6ea1SDimitry Andric   SmallPtrSet<BasicBlock *, 2>
254*0fca6ea1SDimitry Andric   findExitNodes(const SmallPtrSetImpl<BasicBlock *> &RegionBlocks) {
255*0fca6ea1SDimitry Andric     SmallPtrSet<BasicBlock *, 2> Exits;
256*0fca6ea1SDimitry Andric 
257*0fca6ea1SDimitry Andric     for (auto *B : RegionBlocks) {
258*0fca6ea1SDimitry Andric       auto *Terminator = B->getTerminator();
259*0fca6ea1SDimitry Andric       for (unsigned i = 0; i < Terminator->getNumSuccessors(); ++i) {
260*0fca6ea1SDimitry Andric         auto *Child = Terminator->getSuccessor(i);
261*0fca6ea1SDimitry Andric         if (RegionBlocks.count(Child) == 0)
262*0fca6ea1SDimitry Andric           Exits.insert(B);
263*0fca6ea1SDimitry Andric       }
264*0fca6ea1SDimitry Andric     }
265*0fca6ea1SDimitry Andric 
266*0fca6ea1SDimitry Andric     return Exits;
267*0fca6ea1SDimitry Andric   }
268*0fca6ea1SDimitry Andric 
269*0fca6ea1SDimitry Andric public:
270*0fca6ea1SDimitry Andric   ConvergenceRegionInfo analyze() {
271*0fca6ea1SDimitry Andric     ConvergenceRegion *TopLevelRegion = new ConvergenceRegion(DT, LI, F);
272*0fca6ea1SDimitry Andric     std::queue<Loop *> ToProcess;
273*0fca6ea1SDimitry Andric     for (auto *L : LI.getLoopsInPreorder())
274*0fca6ea1SDimitry Andric       ToProcess.push(L);
275*0fca6ea1SDimitry Andric 
276*0fca6ea1SDimitry Andric     while (ToProcess.size() != 0) {
277*0fca6ea1SDimitry Andric       auto *L = ToProcess.front();
278*0fca6ea1SDimitry Andric       ToProcess.pop();
279*0fca6ea1SDimitry Andric       assert(L->isLoopSimplifyForm());
280*0fca6ea1SDimitry Andric 
281*0fca6ea1SDimitry Andric       auto CT = getConvergenceToken(L->getHeader());
282*0fca6ea1SDimitry Andric       SmallPtrSet<BasicBlock *, 8> RegionBlocks(L->block_begin(),
283*0fca6ea1SDimitry Andric                                                 L->block_end());
284*0fca6ea1SDimitry Andric       SmallVector<BasicBlock *> LoopExits;
285*0fca6ea1SDimitry Andric       L->getExitingBlocks(LoopExits);
286*0fca6ea1SDimitry Andric       if (CT.has_value()) {
287*0fca6ea1SDimitry Andric         for (auto *Exit : LoopExits) {
288*0fca6ea1SDimitry Andric           auto N = findPathsToMatch(LI, Exit, [&CT](const BasicBlock *block) {
289*0fca6ea1SDimitry Andric             auto Token = getConvergenceToken(block);
290*0fca6ea1SDimitry Andric             if (Token == std::nullopt)
291*0fca6ea1SDimitry Andric               return false;
292*0fca6ea1SDimitry Andric             return Token.value() == CT.value();
293*0fca6ea1SDimitry Andric           });
294*0fca6ea1SDimitry Andric           RegionBlocks.insert(N.begin(), N.end());
295*0fca6ea1SDimitry Andric         }
296*0fca6ea1SDimitry Andric       }
297*0fca6ea1SDimitry Andric 
298*0fca6ea1SDimitry Andric       auto RegionExits = findExitNodes(RegionBlocks);
299*0fca6ea1SDimitry Andric       ConvergenceRegion *Region = new ConvergenceRegion(
300*0fca6ea1SDimitry Andric           DT, LI, CT, L->getHeader(), std::move(RegionBlocks),
301*0fca6ea1SDimitry Andric           std::move(RegionExits));
302*0fca6ea1SDimitry Andric       Region->Parent = findParentRegion(TopLevelRegion, Region->Entry);
303*0fca6ea1SDimitry Andric       assert(Region->Parent != nullptr && "This is impossible.");
304*0fca6ea1SDimitry Andric       Region->Parent->Children.push_back(Region);
305*0fca6ea1SDimitry Andric     }
306*0fca6ea1SDimitry Andric 
307*0fca6ea1SDimitry Andric     return ConvergenceRegionInfo(TopLevelRegion);
308*0fca6ea1SDimitry Andric   }
309*0fca6ea1SDimitry Andric 
310*0fca6ea1SDimitry Andric private:
311*0fca6ea1SDimitry Andric   DominatorTree &DT;
312*0fca6ea1SDimitry Andric   LoopInfo &LI;
313*0fca6ea1SDimitry Andric   Function &F;
314*0fca6ea1SDimitry Andric };
315*0fca6ea1SDimitry Andric 
316*0fca6ea1SDimitry Andric ConvergenceRegionInfo getConvergenceRegions(Function &F, DominatorTree &DT,
317*0fca6ea1SDimitry Andric                                             LoopInfo &LI) {
318*0fca6ea1SDimitry Andric   ConvergenceRegionAnalyzer Analyzer(F, DT, LI);
319*0fca6ea1SDimitry Andric   return Analyzer.analyze();
320*0fca6ea1SDimitry Andric }
321*0fca6ea1SDimitry Andric 
322*0fca6ea1SDimitry Andric } // namespace SPIRV
323*0fca6ea1SDimitry Andric 
324*0fca6ea1SDimitry Andric char SPIRVConvergenceRegionAnalysisWrapperPass::ID = 0;
325*0fca6ea1SDimitry Andric 
326*0fca6ea1SDimitry Andric SPIRVConvergenceRegionAnalysisWrapperPass::
327*0fca6ea1SDimitry Andric     SPIRVConvergenceRegionAnalysisWrapperPass()
328*0fca6ea1SDimitry Andric     : FunctionPass(ID) {}
329*0fca6ea1SDimitry Andric 
330*0fca6ea1SDimitry Andric bool SPIRVConvergenceRegionAnalysisWrapperPass::runOnFunction(Function &F) {
331*0fca6ea1SDimitry Andric   DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
332*0fca6ea1SDimitry Andric   LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
333*0fca6ea1SDimitry Andric 
334*0fca6ea1SDimitry Andric   CRI = SPIRV::getConvergenceRegions(F, DT, LI);
335*0fca6ea1SDimitry Andric   // Nothing was modified.
336*0fca6ea1SDimitry Andric   return false;
337*0fca6ea1SDimitry Andric }
338*0fca6ea1SDimitry Andric 
339*0fca6ea1SDimitry Andric SPIRVConvergenceRegionAnalysis::Result
340*0fca6ea1SDimitry Andric SPIRVConvergenceRegionAnalysis::run(Function &F, FunctionAnalysisManager &AM) {
341*0fca6ea1SDimitry Andric   Result CRI;
342*0fca6ea1SDimitry Andric   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
343*0fca6ea1SDimitry Andric   auto &LI = AM.getResult<LoopAnalysis>(F);
344*0fca6ea1SDimitry Andric   CRI = SPIRV::getConvergenceRegions(F, DT, LI);
345*0fca6ea1SDimitry Andric   return CRI;
346*0fca6ea1SDimitry Andric }
347*0fca6ea1SDimitry Andric 
348*0fca6ea1SDimitry Andric AnalysisKey SPIRVConvergenceRegionAnalysis::Key;
349*0fca6ea1SDimitry Andric 
350*0fca6ea1SDimitry Andric } // namespace llvm
351