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