1*0eae32dcSDimitry Andric //===- GenericCycleImpl.h -------------------------------------*- C++ -*---===// 2*0eae32dcSDimitry Andric // 3*0eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0eae32dcSDimitry Andric // 7*0eae32dcSDimitry Andric //===----------------------------------------------------------------------===// 8*0eae32dcSDimitry Andric // 9*0eae32dcSDimitry Andric // This template implementation resides in a separate file so that it 10*0eae32dcSDimitry Andric // does not get injected into every .cpp file that includes the 11*0eae32dcSDimitry Andric // generic header. 12*0eae32dcSDimitry Andric // 13*0eae32dcSDimitry Andric // DO NOT INCLUDE THIS FILE WHEN MERELY USING CYCLEINFO. 14*0eae32dcSDimitry Andric // 15*0eae32dcSDimitry Andric // This file should only be included by files that implement a 16*0eae32dcSDimitry Andric // specialization of the relevant templates. Currently these are: 17*0eae32dcSDimitry Andric // - CycleAnalysis.cpp 18*0eae32dcSDimitry Andric // - MachineCycleAnalysis.cpp 19*0eae32dcSDimitry Andric // 20*0eae32dcSDimitry Andric //===----------------------------------------------------------------------===// 21*0eae32dcSDimitry Andric 22*0eae32dcSDimitry Andric #ifndef LLVM_ADT_GENERICCYCLEIMPL_H 23*0eae32dcSDimitry Andric #define LLVM_ADT_GENERICCYCLEIMPL_H 24*0eae32dcSDimitry Andric 25*0eae32dcSDimitry Andric #include "llvm/ADT/DenseSet.h" 26*0eae32dcSDimitry Andric #include "llvm/ADT/DepthFirstIterator.h" 27*0eae32dcSDimitry Andric #include "llvm/ADT/GenericCycleInfo.h" 28*0eae32dcSDimitry Andric 29*0eae32dcSDimitry Andric #define DEBUG_TYPE "generic-cycle-impl" 30*0eae32dcSDimitry Andric 31*0eae32dcSDimitry Andric namespace llvm { 32*0eae32dcSDimitry Andric 33*0eae32dcSDimitry Andric template <typename ContextT> 34*0eae32dcSDimitry Andric bool GenericCycle<ContextT>::contains(const GenericCycle *C) const { 35*0eae32dcSDimitry Andric if (!C) 36*0eae32dcSDimitry Andric return false; 37*0eae32dcSDimitry Andric 38*0eae32dcSDimitry Andric if (Depth > C->Depth) 39*0eae32dcSDimitry Andric return false; 40*0eae32dcSDimitry Andric while (Depth < C->Depth) 41*0eae32dcSDimitry Andric C = C->ParentCycle; 42*0eae32dcSDimitry Andric return this == C; 43*0eae32dcSDimitry Andric } 44*0eae32dcSDimitry Andric 45*0eae32dcSDimitry Andric template <typename ContextT> 46*0eae32dcSDimitry Andric void GenericCycle<ContextT>::getExitBlocks( 47*0eae32dcSDimitry Andric SmallVectorImpl<BlockT *> &TmpStorage) const { 48*0eae32dcSDimitry Andric TmpStorage.clear(); 49*0eae32dcSDimitry Andric 50*0eae32dcSDimitry Andric size_t NumExitBlocks = 0; 51*0eae32dcSDimitry Andric for (BlockT *Block : blocks()) { 52*0eae32dcSDimitry Andric llvm::append_range(TmpStorage, successors(Block)); 53*0eae32dcSDimitry Andric 54*0eae32dcSDimitry Andric for (size_t Idx = NumExitBlocks, End = TmpStorage.size(); Idx < End; 55*0eae32dcSDimitry Andric ++Idx) { 56*0eae32dcSDimitry Andric BlockT *Succ = TmpStorage[Idx]; 57*0eae32dcSDimitry Andric if (!contains(Succ)) { 58*0eae32dcSDimitry Andric auto ExitEndIt = TmpStorage.begin() + NumExitBlocks; 59*0eae32dcSDimitry Andric if (std::find(TmpStorage.begin(), ExitEndIt, Succ) == ExitEndIt) 60*0eae32dcSDimitry Andric TmpStorage[NumExitBlocks++] = Succ; 61*0eae32dcSDimitry Andric } 62*0eae32dcSDimitry Andric } 63*0eae32dcSDimitry Andric 64*0eae32dcSDimitry Andric TmpStorage.resize(NumExitBlocks); 65*0eae32dcSDimitry Andric } 66*0eae32dcSDimitry Andric } 67*0eae32dcSDimitry Andric 68*0eae32dcSDimitry Andric /// \brief Helper class for computing cycle information. 69*0eae32dcSDimitry Andric template <typename ContextT> class GenericCycleInfoCompute { 70*0eae32dcSDimitry Andric using BlockT = typename ContextT::BlockT; 71*0eae32dcSDimitry Andric using CycleInfoT = GenericCycleInfo<ContextT>; 72*0eae32dcSDimitry Andric using CycleT = typename CycleInfoT::CycleT; 73*0eae32dcSDimitry Andric 74*0eae32dcSDimitry Andric CycleInfoT &Info; 75*0eae32dcSDimitry Andric 76*0eae32dcSDimitry Andric struct DFSInfo { 77*0eae32dcSDimitry Andric unsigned Start = 0; // DFS start; positive if block is found 78*0eae32dcSDimitry Andric unsigned End = 0; // DFS end 79*0eae32dcSDimitry Andric 80*0eae32dcSDimitry Andric DFSInfo() {} 81*0eae32dcSDimitry Andric explicit DFSInfo(unsigned Start) : Start(Start) {} 82*0eae32dcSDimitry Andric 83*0eae32dcSDimitry Andric /// Whether this node is an ancestor (or equal to) the node \p Other 84*0eae32dcSDimitry Andric /// in the DFS tree. 85*0eae32dcSDimitry Andric bool isAncestorOf(const DFSInfo &Other) const { 86*0eae32dcSDimitry Andric return Start <= Other.Start && Other.End <= End; 87*0eae32dcSDimitry Andric } 88*0eae32dcSDimitry Andric }; 89*0eae32dcSDimitry Andric 90*0eae32dcSDimitry Andric DenseMap<BlockT *, DFSInfo> BlockDFSInfo; 91*0eae32dcSDimitry Andric SmallVector<BlockT *, 8> BlockPreorder; 92*0eae32dcSDimitry Andric 93*0eae32dcSDimitry Andric GenericCycleInfoCompute(const GenericCycleInfoCompute &) = delete; 94*0eae32dcSDimitry Andric GenericCycleInfoCompute &operator=(const GenericCycleInfoCompute &) = delete; 95*0eae32dcSDimitry Andric 96*0eae32dcSDimitry Andric public: 97*0eae32dcSDimitry Andric GenericCycleInfoCompute(CycleInfoT &Info) : Info(Info) {} 98*0eae32dcSDimitry Andric 99*0eae32dcSDimitry Andric void run(BlockT *EntryBlock); 100*0eae32dcSDimitry Andric 101*0eae32dcSDimitry Andric static void updateDepth(CycleT *SubTree); 102*0eae32dcSDimitry Andric 103*0eae32dcSDimitry Andric private: 104*0eae32dcSDimitry Andric void dfs(BlockT *EntryBlock); 105*0eae32dcSDimitry Andric }; 106*0eae32dcSDimitry Andric 107*0eae32dcSDimitry Andric template <typename ContextT> 108*0eae32dcSDimitry Andric auto GenericCycleInfo<ContextT>::getTopLevelParentCycle( 109*0eae32dcSDimitry Andric const BlockT *Block) const -> CycleT * { 110*0eae32dcSDimitry Andric auto MapIt = BlockMap.find(Block); 111*0eae32dcSDimitry Andric if (MapIt == BlockMap.end()) 112*0eae32dcSDimitry Andric return nullptr; 113*0eae32dcSDimitry Andric 114*0eae32dcSDimitry Andric auto *C = MapIt->second; 115*0eae32dcSDimitry Andric while (C->ParentCycle) 116*0eae32dcSDimitry Andric C = C->ParentCycle; 117*0eae32dcSDimitry Andric return C; 118*0eae32dcSDimitry Andric } 119*0eae32dcSDimitry Andric 120*0eae32dcSDimitry Andric template <typename ContextT> 121*0eae32dcSDimitry Andric void GenericCycleInfo<ContextT>::moveToNewParent(CycleT *NewParent, 122*0eae32dcSDimitry Andric CycleT *Child) { 123*0eae32dcSDimitry Andric auto &CurrentContainer = 124*0eae32dcSDimitry Andric Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles; 125*0eae32dcSDimitry Andric auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool { 126*0eae32dcSDimitry Andric return Child == Ptr.get(); 127*0eae32dcSDimitry Andric }); 128*0eae32dcSDimitry Andric assert(Pos != CurrentContainer.end()); 129*0eae32dcSDimitry Andric NewParent->Children.push_back(std::move(*Pos)); 130*0eae32dcSDimitry Andric *Pos = std::move(CurrentContainer.back()); 131*0eae32dcSDimitry Andric CurrentContainer.pop_back(); 132*0eae32dcSDimitry Andric Child->ParentCycle = NewParent; 133*0eae32dcSDimitry Andric } 134*0eae32dcSDimitry Andric 135*0eae32dcSDimitry Andric /// \brief Main function of the cycle info computations. 136*0eae32dcSDimitry Andric template <typename ContextT> 137*0eae32dcSDimitry Andric void GenericCycleInfoCompute<ContextT>::run(BlockT *EntryBlock) { 138*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock) 139*0eae32dcSDimitry Andric << "\n"); 140*0eae32dcSDimitry Andric dfs(EntryBlock); 141*0eae32dcSDimitry Andric 142*0eae32dcSDimitry Andric SmallVector<BlockT *, 8> Worklist; 143*0eae32dcSDimitry Andric 144*0eae32dcSDimitry Andric for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) { 145*0eae32dcSDimitry Andric const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate); 146*0eae32dcSDimitry Andric 147*0eae32dcSDimitry Andric for (BlockT *Pred : predecessors(HeaderCandidate)) { 148*0eae32dcSDimitry Andric const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred); 149*0eae32dcSDimitry Andric if (CandidateInfo.isAncestorOf(PredDFSInfo)) 150*0eae32dcSDimitry Andric Worklist.push_back(Pred); 151*0eae32dcSDimitry Andric } 152*0eae32dcSDimitry Andric if (Worklist.empty()) { 153*0eae32dcSDimitry Andric continue; 154*0eae32dcSDimitry Andric } 155*0eae32dcSDimitry Andric 156*0eae32dcSDimitry Andric // Found a cycle with the candidate as its header. 157*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << "Found cycle for header: " 158*0eae32dcSDimitry Andric << Info.Context.print(HeaderCandidate) << "\n"); 159*0eae32dcSDimitry Andric std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>(); 160*0eae32dcSDimitry Andric NewCycle->appendEntry(HeaderCandidate); 161*0eae32dcSDimitry Andric NewCycle->appendBlock(HeaderCandidate); 162*0eae32dcSDimitry Andric Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get()); 163*0eae32dcSDimitry Andric 164*0eae32dcSDimitry Andric // Helper function to process (non-back-edge) predecessors of a discovered 165*0eae32dcSDimitry Andric // block and either add them to the worklist or recognize that the given 166*0eae32dcSDimitry Andric // block is an additional cycle entry. 167*0eae32dcSDimitry Andric auto ProcessPredecessors = [&](BlockT *Block) { 168*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": "); 169*0eae32dcSDimitry Andric 170*0eae32dcSDimitry Andric bool IsEntry = false; 171*0eae32dcSDimitry Andric for (BlockT *Pred : predecessors(Block)) { 172*0eae32dcSDimitry Andric const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred); 173*0eae32dcSDimitry Andric if (CandidateInfo.isAncestorOf(PredDFSInfo)) { 174*0eae32dcSDimitry Andric Worklist.push_back(Pred); 175*0eae32dcSDimitry Andric } else { 176*0eae32dcSDimitry Andric IsEntry = true; 177*0eae32dcSDimitry Andric } 178*0eae32dcSDimitry Andric } 179*0eae32dcSDimitry Andric if (IsEntry) { 180*0eae32dcSDimitry Andric assert(!NewCycle->isEntry(Block)); 181*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << "append as entry\n"); 182*0eae32dcSDimitry Andric NewCycle->appendEntry(Block); 183*0eae32dcSDimitry Andric } else { 184*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << "append as child\n"); 185*0eae32dcSDimitry Andric } 186*0eae32dcSDimitry Andric }; 187*0eae32dcSDimitry Andric 188*0eae32dcSDimitry Andric do { 189*0eae32dcSDimitry Andric BlockT *Block = Worklist.pop_back_val(); 190*0eae32dcSDimitry Andric if (Block == HeaderCandidate) 191*0eae32dcSDimitry Andric continue; 192*0eae32dcSDimitry Andric 193*0eae32dcSDimitry Andric // If the block has already been discovered by some cycle 194*0eae32dcSDimitry Andric // (possibly by ourself), then the outermost cycle containing it 195*0eae32dcSDimitry Andric // should become our child. 196*0eae32dcSDimitry Andric if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) { 197*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": "); 198*0eae32dcSDimitry Andric 199*0eae32dcSDimitry Andric if (BlockParent != NewCycle.get()) { 200*0eae32dcSDimitry Andric LLVM_DEBUG(errs() 201*0eae32dcSDimitry Andric << "discovered child cycle " 202*0eae32dcSDimitry Andric << Info.Context.print(BlockParent->getHeader()) << "\n"); 203*0eae32dcSDimitry Andric // Make BlockParent the child of NewCycle. 204*0eae32dcSDimitry Andric Info.moveToNewParent(NewCycle.get(), BlockParent); 205*0eae32dcSDimitry Andric NewCycle->Blocks.insert(NewCycle->Blocks.end(), 206*0eae32dcSDimitry Andric BlockParent->block_begin(), 207*0eae32dcSDimitry Andric BlockParent->block_end()); 208*0eae32dcSDimitry Andric 209*0eae32dcSDimitry Andric for (auto *ChildEntry : BlockParent->entries()) 210*0eae32dcSDimitry Andric ProcessPredecessors(ChildEntry); 211*0eae32dcSDimitry Andric } else { 212*0eae32dcSDimitry Andric LLVM_DEBUG(errs() 213*0eae32dcSDimitry Andric << "known child cycle " 214*0eae32dcSDimitry Andric << Info.Context.print(BlockParent->getHeader()) << "\n"); 215*0eae32dcSDimitry Andric } 216*0eae32dcSDimitry Andric } else { 217*0eae32dcSDimitry Andric Info.BlockMap.try_emplace(Block, NewCycle.get()); 218*0eae32dcSDimitry Andric assert(!is_contained(NewCycle->Blocks, Block)); 219*0eae32dcSDimitry Andric NewCycle->Blocks.push_back(Block); 220*0eae32dcSDimitry Andric ProcessPredecessors(Block); 221*0eae32dcSDimitry Andric } 222*0eae32dcSDimitry Andric } while (!Worklist.empty()); 223*0eae32dcSDimitry Andric 224*0eae32dcSDimitry Andric Info.TopLevelCycles.push_back(std::move(NewCycle)); 225*0eae32dcSDimitry Andric } 226*0eae32dcSDimitry Andric 227*0eae32dcSDimitry Andric // Fix top-level cycle links and compute cycle depths. 228*0eae32dcSDimitry Andric for (auto *TLC : Info.toplevel_cycles()) { 229*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << "top-level cycle: " 230*0eae32dcSDimitry Andric << Info.Context.print(TLC->getHeader()) << "\n"); 231*0eae32dcSDimitry Andric 232*0eae32dcSDimitry Andric TLC->ParentCycle = nullptr; 233*0eae32dcSDimitry Andric updateDepth(TLC); 234*0eae32dcSDimitry Andric } 235*0eae32dcSDimitry Andric } 236*0eae32dcSDimitry Andric 237*0eae32dcSDimitry Andric /// \brief Recompute depth values of \p SubTree and all descendants. 238*0eae32dcSDimitry Andric template <typename ContextT> 239*0eae32dcSDimitry Andric void GenericCycleInfoCompute<ContextT>::updateDepth(CycleT *SubTree) { 240*0eae32dcSDimitry Andric for (CycleT *Cycle : depth_first(SubTree)) 241*0eae32dcSDimitry Andric Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1; 242*0eae32dcSDimitry Andric } 243*0eae32dcSDimitry Andric 244*0eae32dcSDimitry Andric /// \brief Compute a DFS of basic blocks starting at the function entry. 245*0eae32dcSDimitry Andric /// 246*0eae32dcSDimitry Andric /// Fills BlockDFSInfo with start/end counters and BlockPreorder. 247*0eae32dcSDimitry Andric template <typename ContextT> 248*0eae32dcSDimitry Andric void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) { 249*0eae32dcSDimitry Andric SmallVector<unsigned, 8> DFSTreeStack; 250*0eae32dcSDimitry Andric SmallVector<BlockT *, 8> TraverseStack; 251*0eae32dcSDimitry Andric unsigned Counter = 0; 252*0eae32dcSDimitry Andric TraverseStack.emplace_back(EntryBlock); 253*0eae32dcSDimitry Andric 254*0eae32dcSDimitry Andric do { 255*0eae32dcSDimitry Andric BlockT *Block = TraverseStack.back(); 256*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << "DFS visiting block: " << Info.Context.print(Block) 257*0eae32dcSDimitry Andric << "\n"); 258*0eae32dcSDimitry Andric if (!BlockDFSInfo.count(Block)) { 259*0eae32dcSDimitry Andric // We're visiting the block for the first time. Open its DFSInfo, add 260*0eae32dcSDimitry Andric // successors to the traversal stack, and remember the traversal stack 261*0eae32dcSDimitry Andric // depth at which the block was opened, so that we can correctly record 262*0eae32dcSDimitry Andric // its end time. 263*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << " first encountered at depth " 264*0eae32dcSDimitry Andric << TraverseStack.size() << "\n"); 265*0eae32dcSDimitry Andric 266*0eae32dcSDimitry Andric DFSTreeStack.emplace_back(TraverseStack.size()); 267*0eae32dcSDimitry Andric llvm::append_range(TraverseStack, successors(Block)); 268*0eae32dcSDimitry Andric 269*0eae32dcSDimitry Andric LLVM_ATTRIBUTE_UNUSED 270*0eae32dcSDimitry Andric bool Added = BlockDFSInfo.try_emplace(Block, ++Counter).second; 271*0eae32dcSDimitry Andric assert(Added); 272*0eae32dcSDimitry Andric BlockPreorder.push_back(Block); 273*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << " preorder number: " << Counter << "\n"); 274*0eae32dcSDimitry Andric } else { 275*0eae32dcSDimitry Andric assert(!DFSTreeStack.empty()); 276*0eae32dcSDimitry Andric if (DFSTreeStack.back() == TraverseStack.size()) { 277*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << " ended at " << Counter << "\n"); 278*0eae32dcSDimitry Andric BlockDFSInfo.find(Block)->second.End = Counter; 279*0eae32dcSDimitry Andric DFSTreeStack.pop_back(); 280*0eae32dcSDimitry Andric } else { 281*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << " already done\n"); 282*0eae32dcSDimitry Andric } 283*0eae32dcSDimitry Andric TraverseStack.pop_back(); 284*0eae32dcSDimitry Andric } 285*0eae32dcSDimitry Andric } while (!TraverseStack.empty()); 286*0eae32dcSDimitry Andric assert(DFSTreeStack.empty()); 287*0eae32dcSDimitry Andric 288*0eae32dcSDimitry Andric LLVM_DEBUG( 289*0eae32dcSDimitry Andric errs() << "Preorder:\n"; 290*0eae32dcSDimitry Andric for (int i = 0, e = BlockPreorder.size(); i != e; ++i) { 291*0eae32dcSDimitry Andric errs() << " " << Info.Context.print(BlockPreorder[i]) << ": " << i << "\n"; 292*0eae32dcSDimitry Andric } 293*0eae32dcSDimitry Andric ); 294*0eae32dcSDimitry Andric } 295*0eae32dcSDimitry Andric 296*0eae32dcSDimitry Andric /// \brief Reset the object to its initial state. 297*0eae32dcSDimitry Andric template <typename ContextT> void GenericCycleInfo<ContextT>::clear() { 298*0eae32dcSDimitry Andric TopLevelCycles.clear(); 299*0eae32dcSDimitry Andric BlockMap.clear(); 300*0eae32dcSDimitry Andric } 301*0eae32dcSDimitry Andric 302*0eae32dcSDimitry Andric /// \brief Compute the cycle info for a function. 303*0eae32dcSDimitry Andric template <typename ContextT> 304*0eae32dcSDimitry Andric void GenericCycleInfo<ContextT>::compute(FunctionT &F) { 305*0eae32dcSDimitry Andric GenericCycleInfoCompute<ContextT> Compute(*this); 306*0eae32dcSDimitry Andric Context.setFunction(F); 307*0eae32dcSDimitry Andric 308*0eae32dcSDimitry Andric LLVM_DEBUG(errs() << "Computing cycles for function: " << F.getName() 309*0eae32dcSDimitry Andric << "\n"); 310*0eae32dcSDimitry Andric Compute.run(ContextT::getEntryBlock(F)); 311*0eae32dcSDimitry Andric 312*0eae32dcSDimitry Andric assert(validateTree()); 313*0eae32dcSDimitry Andric } 314*0eae32dcSDimitry Andric 315*0eae32dcSDimitry Andric /// \brief Find the innermost cycle containing a given block. 316*0eae32dcSDimitry Andric /// 317*0eae32dcSDimitry Andric /// \returns the innermost cycle containing \p Block or nullptr if 318*0eae32dcSDimitry Andric /// it is not contained in any cycle. 319*0eae32dcSDimitry Andric template <typename ContextT> 320*0eae32dcSDimitry Andric auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const 321*0eae32dcSDimitry Andric -> CycleT * { 322*0eae32dcSDimitry Andric auto MapIt = BlockMap.find(Block); 323*0eae32dcSDimitry Andric if (MapIt != BlockMap.end()) 324*0eae32dcSDimitry Andric return MapIt->second; 325*0eae32dcSDimitry Andric return nullptr; 326*0eae32dcSDimitry Andric } 327*0eae32dcSDimitry Andric 328*0eae32dcSDimitry Andric /// \brief Validate the internal consistency of the cycle tree. 329*0eae32dcSDimitry Andric /// 330*0eae32dcSDimitry Andric /// Note that this does \em not check that cycles are really cycles in the CFG, 331*0eae32dcSDimitry Andric /// or that the right set of cycles in the CFG were found. 332*0eae32dcSDimitry Andric template <typename ContextT> 333*0eae32dcSDimitry Andric bool GenericCycleInfo<ContextT>::validateTree() const { 334*0eae32dcSDimitry Andric DenseSet<BlockT *> Blocks; 335*0eae32dcSDimitry Andric DenseSet<BlockT *> Entries; 336*0eae32dcSDimitry Andric 337*0eae32dcSDimitry Andric auto reportError = [](const char *File, int Line, const char *Cond) { 338*0eae32dcSDimitry Andric errs() << File << ':' << Line 339*0eae32dcSDimitry Andric << ": GenericCycleInfo::validateTree: " << Cond << '\n'; 340*0eae32dcSDimitry Andric }; 341*0eae32dcSDimitry Andric #define check(cond) \ 342*0eae32dcSDimitry Andric do { \ 343*0eae32dcSDimitry Andric if (!(cond)) { \ 344*0eae32dcSDimitry Andric reportError(__FILE__, __LINE__, #cond); \ 345*0eae32dcSDimitry Andric return false; \ 346*0eae32dcSDimitry Andric } \ 347*0eae32dcSDimitry Andric } while (false) 348*0eae32dcSDimitry Andric 349*0eae32dcSDimitry Andric for (const auto *TLC : toplevel_cycles()) { 350*0eae32dcSDimitry Andric for (const CycleT *Cycle : depth_first(TLC)) { 351*0eae32dcSDimitry Andric if (Cycle->ParentCycle) 352*0eae32dcSDimitry Andric check(is_contained(Cycle->ParentCycle->children(), Cycle)); 353*0eae32dcSDimitry Andric 354*0eae32dcSDimitry Andric for (BlockT *Block : Cycle->Blocks) { 355*0eae32dcSDimitry Andric auto MapIt = BlockMap.find(Block); 356*0eae32dcSDimitry Andric check(MapIt != BlockMap.end()); 357*0eae32dcSDimitry Andric check(Cycle->contains(MapIt->second)); 358*0eae32dcSDimitry Andric check(Blocks.insert(Block).second); // duplicates in block list? 359*0eae32dcSDimitry Andric } 360*0eae32dcSDimitry Andric Blocks.clear(); 361*0eae32dcSDimitry Andric 362*0eae32dcSDimitry Andric check(!Cycle->Entries.empty()); 363*0eae32dcSDimitry Andric for (BlockT *Entry : Cycle->Entries) { 364*0eae32dcSDimitry Andric check(Entries.insert(Entry).second); // duplicate entry? 365*0eae32dcSDimitry Andric check(is_contained(Cycle->Blocks, Entry)); 366*0eae32dcSDimitry Andric } 367*0eae32dcSDimitry Andric Entries.clear(); 368*0eae32dcSDimitry Andric 369*0eae32dcSDimitry Andric unsigned ChildDepth = 0; 370*0eae32dcSDimitry Andric for (const CycleT *Child : Cycle->children()) { 371*0eae32dcSDimitry Andric check(Child->Depth > Cycle->Depth); 372*0eae32dcSDimitry Andric if (!ChildDepth) { 373*0eae32dcSDimitry Andric ChildDepth = Child->Depth; 374*0eae32dcSDimitry Andric } else { 375*0eae32dcSDimitry Andric check(ChildDepth == Child->Depth); 376*0eae32dcSDimitry Andric } 377*0eae32dcSDimitry Andric } 378*0eae32dcSDimitry Andric } 379*0eae32dcSDimitry Andric } 380*0eae32dcSDimitry Andric 381*0eae32dcSDimitry Andric for (const auto &Entry : BlockMap) { 382*0eae32dcSDimitry Andric BlockT *Block = Entry.first; 383*0eae32dcSDimitry Andric for (const CycleT *Cycle = Entry.second; Cycle; 384*0eae32dcSDimitry Andric Cycle = Cycle->ParentCycle) { 385*0eae32dcSDimitry Andric check(is_contained(Cycle->Blocks, Block)); 386*0eae32dcSDimitry Andric } 387*0eae32dcSDimitry Andric } 388*0eae32dcSDimitry Andric 389*0eae32dcSDimitry Andric #undef check 390*0eae32dcSDimitry Andric 391*0eae32dcSDimitry Andric return true; 392*0eae32dcSDimitry Andric } 393*0eae32dcSDimitry Andric 394*0eae32dcSDimitry Andric /// \brief Print the cycle info. 395*0eae32dcSDimitry Andric template <typename ContextT> 396*0eae32dcSDimitry Andric void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const { 397*0eae32dcSDimitry Andric for (const auto *TLC : toplevel_cycles()) { 398*0eae32dcSDimitry Andric for (const CycleT *Cycle : depth_first(TLC)) { 399*0eae32dcSDimitry Andric for (unsigned I = 0; I < Cycle->Depth; ++I) 400*0eae32dcSDimitry Andric Out << " "; 401*0eae32dcSDimitry Andric 402*0eae32dcSDimitry Andric Out << Cycle->print(Context) << '\n'; 403*0eae32dcSDimitry Andric } 404*0eae32dcSDimitry Andric } 405*0eae32dcSDimitry Andric } 406*0eae32dcSDimitry Andric 407*0eae32dcSDimitry Andric } // namespace llvm 408*0eae32dcSDimitry Andric 409*0eae32dcSDimitry Andric #undef DEBUG_TYPE 410*0eae32dcSDimitry Andric 411*0eae32dcSDimitry Andric #endif // LLVM_ADT_GENERICCYCLEIMPL_H 412