10eae32dcSDimitry Andric //===- GenericCycleImpl.h -------------------------------------*- C++ -*---===// 20eae32dcSDimitry Andric // 30eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60eae32dcSDimitry Andric // 70eae32dcSDimitry Andric //===----------------------------------------------------------------------===// 81fd87a68SDimitry Andric /// 91fd87a68SDimitry Andric /// \file 101fd87a68SDimitry Andric /// This template implementation resides in a separate file so that it 111fd87a68SDimitry Andric /// does not get injected into every .cpp file that includes the 121fd87a68SDimitry Andric /// generic header. 131fd87a68SDimitry Andric /// 141fd87a68SDimitry Andric /// DO NOT INCLUDE THIS FILE WHEN MERELY USING CYCLEINFO. 151fd87a68SDimitry Andric /// 161fd87a68SDimitry Andric /// This file should only be included by files that implement a 171fd87a68SDimitry Andric /// specialization of the relevant templates. Currently these are: 181fd87a68SDimitry Andric /// - CycleAnalysis.cpp 191fd87a68SDimitry Andric /// - MachineCycleAnalysis.cpp 201fd87a68SDimitry Andric /// 210eae32dcSDimitry Andric //===----------------------------------------------------------------------===// 220eae32dcSDimitry Andric 230eae32dcSDimitry Andric #ifndef LLVM_ADT_GENERICCYCLEIMPL_H 240eae32dcSDimitry Andric #define LLVM_ADT_GENERICCYCLEIMPL_H 250eae32dcSDimitry Andric 260eae32dcSDimitry Andric #include "llvm/ADT/DenseSet.h" 270eae32dcSDimitry Andric #include "llvm/ADT/DepthFirstIterator.h" 280eae32dcSDimitry Andric #include "llvm/ADT/GenericCycleInfo.h" 290eae32dcSDimitry Andric 300eae32dcSDimitry Andric #define DEBUG_TYPE "generic-cycle-impl" 310eae32dcSDimitry Andric 320eae32dcSDimitry Andric namespace llvm { 330eae32dcSDimitry Andric 340eae32dcSDimitry Andric template <typename ContextT> 350eae32dcSDimitry Andric bool GenericCycle<ContextT>::contains(const GenericCycle *C) const { 360eae32dcSDimitry Andric if (!C) 370eae32dcSDimitry Andric return false; 380eae32dcSDimitry Andric 390eae32dcSDimitry Andric if (Depth > C->Depth) 400eae32dcSDimitry Andric return false; 410eae32dcSDimitry Andric while (Depth < C->Depth) 420eae32dcSDimitry Andric C = C->ParentCycle; 430eae32dcSDimitry Andric return this == C; 440eae32dcSDimitry Andric } 450eae32dcSDimitry Andric 460eae32dcSDimitry Andric template <typename ContextT> 470eae32dcSDimitry Andric void GenericCycle<ContextT>::getExitBlocks( 480eae32dcSDimitry Andric SmallVectorImpl<BlockT *> &TmpStorage) const { 490eae32dcSDimitry Andric TmpStorage.clear(); 500eae32dcSDimitry Andric 510eae32dcSDimitry Andric size_t NumExitBlocks = 0; 520eae32dcSDimitry Andric for (BlockT *Block : blocks()) { 530eae32dcSDimitry Andric llvm::append_range(TmpStorage, successors(Block)); 540eae32dcSDimitry Andric 550eae32dcSDimitry Andric for (size_t Idx = NumExitBlocks, End = TmpStorage.size(); Idx < End; 560eae32dcSDimitry Andric ++Idx) { 570eae32dcSDimitry Andric BlockT *Succ = TmpStorage[Idx]; 580eae32dcSDimitry Andric if (!contains(Succ)) { 590eae32dcSDimitry Andric auto ExitEndIt = TmpStorage.begin() + NumExitBlocks; 600eae32dcSDimitry Andric if (std::find(TmpStorage.begin(), ExitEndIt, Succ) == ExitEndIt) 610eae32dcSDimitry Andric TmpStorage[NumExitBlocks++] = Succ; 620eae32dcSDimitry Andric } 630eae32dcSDimitry Andric } 640eae32dcSDimitry Andric 650eae32dcSDimitry Andric TmpStorage.resize(NumExitBlocks); 660eae32dcSDimitry Andric } 670eae32dcSDimitry Andric } 680eae32dcSDimitry Andric 69*81ad6265SDimitry Andric template <typename ContextT> 70*81ad6265SDimitry Andric auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * { 71*81ad6265SDimitry Andric BlockT *Predecessor = getCyclePredecessor(); 72*81ad6265SDimitry Andric if (!Predecessor) 73*81ad6265SDimitry Andric return nullptr; 74*81ad6265SDimitry Andric 75*81ad6265SDimitry Andric assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!"); 76*81ad6265SDimitry Andric 77*81ad6265SDimitry Andric if (succ_size(Predecessor) != 1) 78*81ad6265SDimitry Andric return nullptr; 79*81ad6265SDimitry Andric 80*81ad6265SDimitry Andric // Make sure we are allowed to hoist instructions into the predecessor. 81*81ad6265SDimitry Andric if (!Predecessor->isLegalToHoistInto()) 82*81ad6265SDimitry Andric return nullptr; 83*81ad6265SDimitry Andric 84*81ad6265SDimitry Andric return Predecessor; 85*81ad6265SDimitry Andric } 86*81ad6265SDimitry Andric 87*81ad6265SDimitry Andric template <typename ContextT> 88*81ad6265SDimitry Andric auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * { 89*81ad6265SDimitry Andric if (!isReducible()) 90*81ad6265SDimitry Andric return nullptr; 91*81ad6265SDimitry Andric 92*81ad6265SDimitry Andric BlockT *Out = nullptr; 93*81ad6265SDimitry Andric 94*81ad6265SDimitry Andric // Loop over the predecessors of the header node... 95*81ad6265SDimitry Andric BlockT *Header = getHeader(); 96*81ad6265SDimitry Andric for (const auto Pred : predecessors(Header)) { 97*81ad6265SDimitry Andric if (!contains(Pred)) { 98*81ad6265SDimitry Andric if (Out && Out != Pred) 99*81ad6265SDimitry Andric return nullptr; 100*81ad6265SDimitry Andric Out = Pred; 101*81ad6265SDimitry Andric } 102*81ad6265SDimitry Andric } 103*81ad6265SDimitry Andric 104*81ad6265SDimitry Andric return Out; 105*81ad6265SDimitry Andric } 106*81ad6265SDimitry Andric 1070eae32dcSDimitry Andric /// \brief Helper class for computing cycle information. 1080eae32dcSDimitry Andric template <typename ContextT> class GenericCycleInfoCompute { 1090eae32dcSDimitry Andric using BlockT = typename ContextT::BlockT; 1100eae32dcSDimitry Andric using CycleInfoT = GenericCycleInfo<ContextT>; 1110eae32dcSDimitry Andric using CycleT = typename CycleInfoT::CycleT; 1120eae32dcSDimitry Andric 1130eae32dcSDimitry Andric CycleInfoT &Info; 1140eae32dcSDimitry Andric 1150eae32dcSDimitry Andric struct DFSInfo { 1160eae32dcSDimitry Andric unsigned Start = 0; // DFS start; positive if block is found 1170eae32dcSDimitry Andric unsigned End = 0; // DFS end 1180eae32dcSDimitry Andric 1191fd87a68SDimitry Andric DFSInfo() = default; 1200eae32dcSDimitry Andric explicit DFSInfo(unsigned Start) : Start(Start) {} 1210eae32dcSDimitry Andric 1220eae32dcSDimitry Andric /// Whether this node is an ancestor (or equal to) the node \p Other 1230eae32dcSDimitry Andric /// in the DFS tree. 1240eae32dcSDimitry Andric bool isAncestorOf(const DFSInfo &Other) const { 1250eae32dcSDimitry Andric return Start <= Other.Start && Other.End <= End; 1260eae32dcSDimitry Andric } 1270eae32dcSDimitry Andric }; 1280eae32dcSDimitry Andric 1290eae32dcSDimitry Andric DenseMap<BlockT *, DFSInfo> BlockDFSInfo; 1300eae32dcSDimitry Andric SmallVector<BlockT *, 8> BlockPreorder; 1310eae32dcSDimitry Andric 1320eae32dcSDimitry Andric GenericCycleInfoCompute(const GenericCycleInfoCompute &) = delete; 1330eae32dcSDimitry Andric GenericCycleInfoCompute &operator=(const GenericCycleInfoCompute &) = delete; 1340eae32dcSDimitry Andric 1350eae32dcSDimitry Andric public: 1360eae32dcSDimitry Andric GenericCycleInfoCompute(CycleInfoT &Info) : Info(Info) {} 1370eae32dcSDimitry Andric 1380eae32dcSDimitry Andric void run(BlockT *EntryBlock); 1390eae32dcSDimitry Andric 1400eae32dcSDimitry Andric static void updateDepth(CycleT *SubTree); 1410eae32dcSDimitry Andric 1420eae32dcSDimitry Andric private: 1430eae32dcSDimitry Andric void dfs(BlockT *EntryBlock); 1440eae32dcSDimitry Andric }; 1450eae32dcSDimitry Andric 1460eae32dcSDimitry Andric template <typename ContextT> 1470eae32dcSDimitry Andric auto GenericCycleInfo<ContextT>::getTopLevelParentCycle( 1480eae32dcSDimitry Andric const BlockT *Block) const -> CycleT * { 1490eae32dcSDimitry Andric auto MapIt = BlockMap.find(Block); 1500eae32dcSDimitry Andric if (MapIt == BlockMap.end()) 1510eae32dcSDimitry Andric return nullptr; 1520eae32dcSDimitry Andric 1530eae32dcSDimitry Andric auto *C = MapIt->second; 1540eae32dcSDimitry Andric while (C->ParentCycle) 1550eae32dcSDimitry Andric C = C->ParentCycle; 1560eae32dcSDimitry Andric return C; 1570eae32dcSDimitry Andric } 1580eae32dcSDimitry Andric 1590eae32dcSDimitry Andric template <typename ContextT> 1600eae32dcSDimitry Andric void GenericCycleInfo<ContextT>::moveToNewParent(CycleT *NewParent, 1610eae32dcSDimitry Andric CycleT *Child) { 1620eae32dcSDimitry Andric auto &CurrentContainer = 1630eae32dcSDimitry Andric Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles; 1640eae32dcSDimitry Andric auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool { 1650eae32dcSDimitry Andric return Child == Ptr.get(); 1660eae32dcSDimitry Andric }); 1670eae32dcSDimitry Andric assert(Pos != CurrentContainer.end()); 1680eae32dcSDimitry Andric NewParent->Children.push_back(std::move(*Pos)); 1690eae32dcSDimitry Andric *Pos = std::move(CurrentContainer.back()); 1700eae32dcSDimitry Andric CurrentContainer.pop_back(); 1710eae32dcSDimitry Andric Child->ParentCycle = NewParent; 1720eae32dcSDimitry Andric } 1730eae32dcSDimitry Andric 1740eae32dcSDimitry Andric /// \brief Main function of the cycle info computations. 1750eae32dcSDimitry Andric template <typename ContextT> 1760eae32dcSDimitry Andric void GenericCycleInfoCompute<ContextT>::run(BlockT *EntryBlock) { 1770eae32dcSDimitry Andric LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock) 1780eae32dcSDimitry Andric << "\n"); 1790eae32dcSDimitry Andric dfs(EntryBlock); 1800eae32dcSDimitry Andric 1810eae32dcSDimitry Andric SmallVector<BlockT *, 8> Worklist; 1820eae32dcSDimitry Andric 1830eae32dcSDimitry Andric for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) { 1840eae32dcSDimitry Andric const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate); 1850eae32dcSDimitry Andric 1860eae32dcSDimitry Andric for (BlockT *Pred : predecessors(HeaderCandidate)) { 1870eae32dcSDimitry Andric const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred); 1880eae32dcSDimitry Andric if (CandidateInfo.isAncestorOf(PredDFSInfo)) 1890eae32dcSDimitry Andric Worklist.push_back(Pred); 1900eae32dcSDimitry Andric } 1910eae32dcSDimitry Andric if (Worklist.empty()) { 1920eae32dcSDimitry Andric continue; 1930eae32dcSDimitry Andric } 1940eae32dcSDimitry Andric 1950eae32dcSDimitry Andric // Found a cycle with the candidate as its header. 1960eae32dcSDimitry Andric LLVM_DEBUG(errs() << "Found cycle for header: " 1970eae32dcSDimitry Andric << Info.Context.print(HeaderCandidate) << "\n"); 1980eae32dcSDimitry Andric std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>(); 1990eae32dcSDimitry Andric NewCycle->appendEntry(HeaderCandidate); 2000eae32dcSDimitry Andric NewCycle->appendBlock(HeaderCandidate); 2010eae32dcSDimitry Andric Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get()); 2020eae32dcSDimitry Andric 2030eae32dcSDimitry Andric // Helper function to process (non-back-edge) predecessors of a discovered 2040eae32dcSDimitry Andric // block and either add them to the worklist or recognize that the given 2050eae32dcSDimitry Andric // block is an additional cycle entry. 2060eae32dcSDimitry Andric auto ProcessPredecessors = [&](BlockT *Block) { 2070eae32dcSDimitry Andric LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": "); 2080eae32dcSDimitry Andric 2090eae32dcSDimitry Andric bool IsEntry = false; 2100eae32dcSDimitry Andric for (BlockT *Pred : predecessors(Block)) { 2110eae32dcSDimitry Andric const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred); 2120eae32dcSDimitry Andric if (CandidateInfo.isAncestorOf(PredDFSInfo)) { 2130eae32dcSDimitry Andric Worklist.push_back(Pred); 2140eae32dcSDimitry Andric } else { 2150eae32dcSDimitry Andric IsEntry = true; 2160eae32dcSDimitry Andric } 2170eae32dcSDimitry Andric } 2180eae32dcSDimitry Andric if (IsEntry) { 2190eae32dcSDimitry Andric assert(!NewCycle->isEntry(Block)); 2200eae32dcSDimitry Andric LLVM_DEBUG(errs() << "append as entry\n"); 2210eae32dcSDimitry Andric NewCycle->appendEntry(Block); 2220eae32dcSDimitry Andric } else { 2230eae32dcSDimitry Andric LLVM_DEBUG(errs() << "append as child\n"); 2240eae32dcSDimitry Andric } 2250eae32dcSDimitry Andric }; 2260eae32dcSDimitry Andric 2270eae32dcSDimitry Andric do { 2280eae32dcSDimitry Andric BlockT *Block = Worklist.pop_back_val(); 2290eae32dcSDimitry Andric if (Block == HeaderCandidate) 2300eae32dcSDimitry Andric continue; 2310eae32dcSDimitry Andric 2320eae32dcSDimitry Andric // If the block has already been discovered by some cycle 2330eae32dcSDimitry Andric // (possibly by ourself), then the outermost cycle containing it 2340eae32dcSDimitry Andric // should become our child. 2350eae32dcSDimitry Andric if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) { 2360eae32dcSDimitry Andric LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": "); 2370eae32dcSDimitry Andric 2380eae32dcSDimitry Andric if (BlockParent != NewCycle.get()) { 2390eae32dcSDimitry Andric LLVM_DEBUG(errs() 2400eae32dcSDimitry Andric << "discovered child cycle " 2410eae32dcSDimitry Andric << Info.Context.print(BlockParent->getHeader()) << "\n"); 2420eae32dcSDimitry Andric // Make BlockParent the child of NewCycle. 2430eae32dcSDimitry Andric Info.moveToNewParent(NewCycle.get(), BlockParent); 2440eae32dcSDimitry Andric NewCycle->Blocks.insert(NewCycle->Blocks.end(), 2450eae32dcSDimitry Andric BlockParent->block_begin(), 2460eae32dcSDimitry Andric BlockParent->block_end()); 2470eae32dcSDimitry Andric 2480eae32dcSDimitry Andric for (auto *ChildEntry : BlockParent->entries()) 2490eae32dcSDimitry Andric ProcessPredecessors(ChildEntry); 2500eae32dcSDimitry Andric } else { 2510eae32dcSDimitry Andric LLVM_DEBUG(errs() 2520eae32dcSDimitry Andric << "known child cycle " 2530eae32dcSDimitry Andric << Info.Context.print(BlockParent->getHeader()) << "\n"); 2540eae32dcSDimitry Andric } 2550eae32dcSDimitry Andric } else { 2560eae32dcSDimitry Andric Info.BlockMap.try_emplace(Block, NewCycle.get()); 2570eae32dcSDimitry Andric assert(!is_contained(NewCycle->Blocks, Block)); 2580eae32dcSDimitry Andric NewCycle->Blocks.push_back(Block); 2590eae32dcSDimitry Andric ProcessPredecessors(Block); 2600eae32dcSDimitry Andric } 2610eae32dcSDimitry Andric } while (!Worklist.empty()); 2620eae32dcSDimitry Andric 2630eae32dcSDimitry Andric Info.TopLevelCycles.push_back(std::move(NewCycle)); 2640eae32dcSDimitry Andric } 2650eae32dcSDimitry Andric 2660eae32dcSDimitry Andric // Fix top-level cycle links and compute cycle depths. 2670eae32dcSDimitry Andric for (auto *TLC : Info.toplevel_cycles()) { 2680eae32dcSDimitry Andric LLVM_DEBUG(errs() << "top-level cycle: " 2690eae32dcSDimitry Andric << Info.Context.print(TLC->getHeader()) << "\n"); 2700eae32dcSDimitry Andric 2710eae32dcSDimitry Andric TLC->ParentCycle = nullptr; 2720eae32dcSDimitry Andric updateDepth(TLC); 2730eae32dcSDimitry Andric } 2740eae32dcSDimitry Andric } 2750eae32dcSDimitry Andric 2760eae32dcSDimitry Andric /// \brief Recompute depth values of \p SubTree and all descendants. 2770eae32dcSDimitry Andric template <typename ContextT> 2780eae32dcSDimitry Andric void GenericCycleInfoCompute<ContextT>::updateDepth(CycleT *SubTree) { 2790eae32dcSDimitry Andric for (CycleT *Cycle : depth_first(SubTree)) 2800eae32dcSDimitry Andric Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1; 2810eae32dcSDimitry Andric } 2820eae32dcSDimitry Andric 2830eae32dcSDimitry Andric /// \brief Compute a DFS of basic blocks starting at the function entry. 2840eae32dcSDimitry Andric /// 2850eae32dcSDimitry Andric /// Fills BlockDFSInfo with start/end counters and BlockPreorder. 2860eae32dcSDimitry Andric template <typename ContextT> 2870eae32dcSDimitry Andric void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) { 2880eae32dcSDimitry Andric SmallVector<unsigned, 8> DFSTreeStack; 2890eae32dcSDimitry Andric SmallVector<BlockT *, 8> TraverseStack; 2900eae32dcSDimitry Andric unsigned Counter = 0; 2910eae32dcSDimitry Andric TraverseStack.emplace_back(EntryBlock); 2920eae32dcSDimitry Andric 2930eae32dcSDimitry Andric do { 2940eae32dcSDimitry Andric BlockT *Block = TraverseStack.back(); 2950eae32dcSDimitry Andric LLVM_DEBUG(errs() << "DFS visiting block: " << Info.Context.print(Block) 2960eae32dcSDimitry Andric << "\n"); 2970eae32dcSDimitry Andric if (!BlockDFSInfo.count(Block)) { 2980eae32dcSDimitry Andric // We're visiting the block for the first time. Open its DFSInfo, add 2990eae32dcSDimitry Andric // successors to the traversal stack, and remember the traversal stack 3000eae32dcSDimitry Andric // depth at which the block was opened, so that we can correctly record 3010eae32dcSDimitry Andric // its end time. 3020eae32dcSDimitry Andric LLVM_DEBUG(errs() << " first encountered at depth " 3030eae32dcSDimitry Andric << TraverseStack.size() << "\n"); 3040eae32dcSDimitry Andric 3050eae32dcSDimitry Andric DFSTreeStack.emplace_back(TraverseStack.size()); 3060eae32dcSDimitry Andric llvm::append_range(TraverseStack, successors(Block)); 3070eae32dcSDimitry Andric 3080eae32dcSDimitry Andric bool Added = BlockDFSInfo.try_emplace(Block, ++Counter).second; 309*81ad6265SDimitry Andric (void)Added; 3100eae32dcSDimitry Andric assert(Added); 3110eae32dcSDimitry Andric BlockPreorder.push_back(Block); 3120eae32dcSDimitry Andric LLVM_DEBUG(errs() << " preorder number: " << Counter << "\n"); 3130eae32dcSDimitry Andric } else { 3140eae32dcSDimitry Andric assert(!DFSTreeStack.empty()); 3150eae32dcSDimitry Andric if (DFSTreeStack.back() == TraverseStack.size()) { 3160eae32dcSDimitry Andric LLVM_DEBUG(errs() << " ended at " << Counter << "\n"); 3170eae32dcSDimitry Andric BlockDFSInfo.find(Block)->second.End = Counter; 3180eae32dcSDimitry Andric DFSTreeStack.pop_back(); 3190eae32dcSDimitry Andric } else { 3200eae32dcSDimitry Andric LLVM_DEBUG(errs() << " already done\n"); 3210eae32dcSDimitry Andric } 3220eae32dcSDimitry Andric TraverseStack.pop_back(); 3230eae32dcSDimitry Andric } 3240eae32dcSDimitry Andric } while (!TraverseStack.empty()); 3250eae32dcSDimitry Andric assert(DFSTreeStack.empty()); 3260eae32dcSDimitry Andric 3270eae32dcSDimitry Andric LLVM_DEBUG( 3280eae32dcSDimitry Andric errs() << "Preorder:\n"; 3290eae32dcSDimitry Andric for (int i = 0, e = BlockPreorder.size(); i != e; ++i) { 3300eae32dcSDimitry Andric errs() << " " << Info.Context.print(BlockPreorder[i]) << ": " << i << "\n"; 3310eae32dcSDimitry Andric } 3320eae32dcSDimitry Andric ); 3330eae32dcSDimitry Andric } 3340eae32dcSDimitry Andric 3350eae32dcSDimitry Andric /// \brief Reset the object to its initial state. 3360eae32dcSDimitry Andric template <typename ContextT> void GenericCycleInfo<ContextT>::clear() { 3370eae32dcSDimitry Andric TopLevelCycles.clear(); 3380eae32dcSDimitry Andric BlockMap.clear(); 3390eae32dcSDimitry Andric } 3400eae32dcSDimitry Andric 3410eae32dcSDimitry Andric /// \brief Compute the cycle info for a function. 3420eae32dcSDimitry Andric template <typename ContextT> 3430eae32dcSDimitry Andric void GenericCycleInfo<ContextT>::compute(FunctionT &F) { 3440eae32dcSDimitry Andric GenericCycleInfoCompute<ContextT> Compute(*this); 3450eae32dcSDimitry Andric Context.setFunction(F); 3460eae32dcSDimitry Andric 3470eae32dcSDimitry Andric LLVM_DEBUG(errs() << "Computing cycles for function: " << F.getName() 3480eae32dcSDimitry Andric << "\n"); 3490eae32dcSDimitry Andric Compute.run(ContextT::getEntryBlock(F)); 3500eae32dcSDimitry Andric 3510eae32dcSDimitry Andric assert(validateTree()); 3520eae32dcSDimitry Andric } 3530eae32dcSDimitry Andric 3540eae32dcSDimitry Andric /// \brief Find the innermost cycle containing a given block. 3550eae32dcSDimitry Andric /// 3560eae32dcSDimitry Andric /// \returns the innermost cycle containing \p Block or nullptr if 3570eae32dcSDimitry Andric /// it is not contained in any cycle. 3580eae32dcSDimitry Andric template <typename ContextT> 3590eae32dcSDimitry Andric auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const 3600eae32dcSDimitry Andric -> CycleT * { 3610eae32dcSDimitry Andric auto MapIt = BlockMap.find(Block); 3620eae32dcSDimitry Andric if (MapIt != BlockMap.end()) 3630eae32dcSDimitry Andric return MapIt->second; 3640eae32dcSDimitry Andric return nullptr; 3650eae32dcSDimitry Andric } 3660eae32dcSDimitry Andric 367*81ad6265SDimitry Andric /// \brief get the depth for the cycle which containing a given block. 368*81ad6265SDimitry Andric /// 369*81ad6265SDimitry Andric /// \returns the depth for the innermost cycle containing \p Block or 0 if it is 370*81ad6265SDimitry Andric /// not contained in any cycle. 371*81ad6265SDimitry Andric template <typename ContextT> 372*81ad6265SDimitry Andric unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const { 373*81ad6265SDimitry Andric CycleT *Cycle = getCycle(Block); 374*81ad6265SDimitry Andric if (!Cycle) 375*81ad6265SDimitry Andric return 0; 376*81ad6265SDimitry Andric return Cycle->getDepth(); 377*81ad6265SDimitry Andric } 378*81ad6265SDimitry Andric 379*81ad6265SDimitry Andric #ifndef NDEBUG 3800eae32dcSDimitry Andric /// \brief Validate the internal consistency of the cycle tree. 3810eae32dcSDimitry Andric /// 3820eae32dcSDimitry Andric /// Note that this does \em not check that cycles are really cycles in the CFG, 3830eae32dcSDimitry Andric /// or that the right set of cycles in the CFG were found. 3840eae32dcSDimitry Andric template <typename ContextT> 3850eae32dcSDimitry Andric bool GenericCycleInfo<ContextT>::validateTree() const { 3860eae32dcSDimitry Andric DenseSet<BlockT *> Blocks; 3870eae32dcSDimitry Andric DenseSet<BlockT *> Entries; 3880eae32dcSDimitry Andric 3890eae32dcSDimitry Andric auto reportError = [](const char *File, int Line, const char *Cond) { 3900eae32dcSDimitry Andric errs() << File << ':' << Line 3910eae32dcSDimitry Andric << ": GenericCycleInfo::validateTree: " << Cond << '\n'; 3920eae32dcSDimitry Andric }; 3930eae32dcSDimitry Andric #define check(cond) \ 3940eae32dcSDimitry Andric do { \ 3950eae32dcSDimitry Andric if (!(cond)) { \ 3960eae32dcSDimitry Andric reportError(__FILE__, __LINE__, #cond); \ 3970eae32dcSDimitry Andric return false; \ 3980eae32dcSDimitry Andric } \ 3990eae32dcSDimitry Andric } while (false) 4000eae32dcSDimitry Andric 4010eae32dcSDimitry Andric for (const auto *TLC : toplevel_cycles()) { 4020eae32dcSDimitry Andric for (const CycleT *Cycle : depth_first(TLC)) { 4030eae32dcSDimitry Andric if (Cycle->ParentCycle) 4040eae32dcSDimitry Andric check(is_contained(Cycle->ParentCycle->children(), Cycle)); 4050eae32dcSDimitry Andric 4060eae32dcSDimitry Andric for (BlockT *Block : Cycle->Blocks) { 4070eae32dcSDimitry Andric auto MapIt = BlockMap.find(Block); 4080eae32dcSDimitry Andric check(MapIt != BlockMap.end()); 4090eae32dcSDimitry Andric check(Cycle->contains(MapIt->second)); 4100eae32dcSDimitry Andric check(Blocks.insert(Block).second); // duplicates in block list? 4110eae32dcSDimitry Andric } 4120eae32dcSDimitry Andric Blocks.clear(); 4130eae32dcSDimitry Andric 4140eae32dcSDimitry Andric check(!Cycle->Entries.empty()); 4150eae32dcSDimitry Andric for (BlockT *Entry : Cycle->Entries) { 4160eae32dcSDimitry Andric check(Entries.insert(Entry).second); // duplicate entry? 4170eae32dcSDimitry Andric check(is_contained(Cycle->Blocks, Entry)); 4180eae32dcSDimitry Andric } 4190eae32dcSDimitry Andric Entries.clear(); 4200eae32dcSDimitry Andric 4210eae32dcSDimitry Andric unsigned ChildDepth = 0; 4220eae32dcSDimitry Andric for (const CycleT *Child : Cycle->children()) { 4230eae32dcSDimitry Andric check(Child->Depth > Cycle->Depth); 4240eae32dcSDimitry Andric if (!ChildDepth) { 4250eae32dcSDimitry Andric ChildDepth = Child->Depth; 4260eae32dcSDimitry Andric } else { 4270eae32dcSDimitry Andric check(ChildDepth == Child->Depth); 4280eae32dcSDimitry Andric } 4290eae32dcSDimitry Andric } 4300eae32dcSDimitry Andric } 4310eae32dcSDimitry Andric } 4320eae32dcSDimitry Andric 4330eae32dcSDimitry Andric for (const auto &Entry : BlockMap) { 4340eae32dcSDimitry Andric BlockT *Block = Entry.first; 4350eae32dcSDimitry Andric for (const CycleT *Cycle = Entry.second; Cycle; 4360eae32dcSDimitry Andric Cycle = Cycle->ParentCycle) { 4370eae32dcSDimitry Andric check(is_contained(Cycle->Blocks, Block)); 4380eae32dcSDimitry Andric } 4390eae32dcSDimitry Andric } 4400eae32dcSDimitry Andric 4410eae32dcSDimitry Andric #undef check 4420eae32dcSDimitry Andric 4430eae32dcSDimitry Andric return true; 4440eae32dcSDimitry Andric } 445*81ad6265SDimitry Andric #endif 4460eae32dcSDimitry Andric 4470eae32dcSDimitry Andric /// \brief Print the cycle info. 4480eae32dcSDimitry Andric template <typename ContextT> 4490eae32dcSDimitry Andric void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const { 4500eae32dcSDimitry Andric for (const auto *TLC : toplevel_cycles()) { 4510eae32dcSDimitry Andric for (const CycleT *Cycle : depth_first(TLC)) { 4520eae32dcSDimitry Andric for (unsigned I = 0; I < Cycle->Depth; ++I) 4530eae32dcSDimitry Andric Out << " "; 4540eae32dcSDimitry Andric 4550eae32dcSDimitry Andric Out << Cycle->print(Context) << '\n'; 4560eae32dcSDimitry Andric } 4570eae32dcSDimitry Andric } 4580eae32dcSDimitry Andric } 4590eae32dcSDimitry Andric 4600eae32dcSDimitry Andric } // namespace llvm 4610eae32dcSDimitry Andric 4620eae32dcSDimitry Andric #undef DEBUG_TYPE 4630eae32dcSDimitry Andric 4640eae32dcSDimitry Andric #endif // LLVM_ADT_GENERICCYCLEIMPL_H 465