xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleImpl.h (revision 6246ae0b85d8159978c01ae916a9ad6cde9378b5)
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 
6981ad6265SDimitry Andric template <typename ContextT>
7081ad6265SDimitry Andric auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * {
7181ad6265SDimitry Andric   BlockT *Predecessor = getCyclePredecessor();
7281ad6265SDimitry Andric   if (!Predecessor)
7381ad6265SDimitry Andric     return nullptr;
7481ad6265SDimitry Andric 
7581ad6265SDimitry Andric   assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!");
7681ad6265SDimitry Andric 
7781ad6265SDimitry Andric   if (succ_size(Predecessor) != 1)
7881ad6265SDimitry Andric     return nullptr;
7981ad6265SDimitry Andric 
8081ad6265SDimitry Andric   // Make sure we are allowed to hoist instructions into the predecessor.
8181ad6265SDimitry Andric   if (!Predecessor->isLegalToHoistInto())
8281ad6265SDimitry Andric     return nullptr;
8381ad6265SDimitry Andric 
8481ad6265SDimitry Andric   return Predecessor;
8581ad6265SDimitry Andric }
8681ad6265SDimitry Andric 
8781ad6265SDimitry Andric template <typename ContextT>
8881ad6265SDimitry Andric auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * {
8981ad6265SDimitry Andric   if (!isReducible())
9081ad6265SDimitry Andric     return nullptr;
9181ad6265SDimitry Andric 
9281ad6265SDimitry Andric   BlockT *Out = nullptr;
9381ad6265SDimitry Andric 
9481ad6265SDimitry Andric   // Loop over the predecessors of the header node...
9581ad6265SDimitry Andric   BlockT *Header = getHeader();
9681ad6265SDimitry Andric   for (const auto Pred : predecessors(Header)) {
9781ad6265SDimitry Andric     if (!contains(Pred)) {
9881ad6265SDimitry Andric       if (Out && Out != Pred)
9981ad6265SDimitry Andric         return nullptr;
10081ad6265SDimitry Andric       Out = Pred;
10181ad6265SDimitry Andric     }
10281ad6265SDimitry Andric   }
10381ad6265SDimitry Andric 
10481ad6265SDimitry Andric   return Out;
10581ad6265SDimitry Andric }
10681ad6265SDimitry 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>
147*6246ae0bSDimitry Andric auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(BlockT *Block)
148*6246ae0bSDimitry Andric     -> CycleT * {
149*6246ae0bSDimitry Andric   auto Cycle = BlockMapTopLevel.find(Block);
150*6246ae0bSDimitry Andric   if (Cycle != BlockMapTopLevel.end())
151*6246ae0bSDimitry Andric     return Cycle->second;
152*6246ae0bSDimitry Andric 
1530eae32dcSDimitry Andric   auto MapIt = BlockMap.find(Block);
1540eae32dcSDimitry Andric   if (MapIt == BlockMap.end())
1550eae32dcSDimitry Andric     return nullptr;
1560eae32dcSDimitry Andric 
1570eae32dcSDimitry Andric   auto *C = MapIt->second;
1580eae32dcSDimitry Andric   while (C->ParentCycle)
1590eae32dcSDimitry Andric     C = C->ParentCycle;
160*6246ae0bSDimitry Andric   BlockMapTopLevel.try_emplace(Block, C);
1610eae32dcSDimitry Andric   return C;
1620eae32dcSDimitry Andric }
1630eae32dcSDimitry Andric 
1640eae32dcSDimitry Andric template <typename ContextT>
165*6246ae0bSDimitry Andric void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
1660eae32dcSDimitry Andric                                                               CycleT *Child) {
167*6246ae0bSDimitry Andric   assert((!Child->ParentCycle && !NewParent->ParentCycle) &&
168*6246ae0bSDimitry Andric          "NewParent and Child must be both top level cycle!\n");
1690eae32dcSDimitry Andric   auto &CurrentContainer =
1700eae32dcSDimitry Andric       Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles;
1710eae32dcSDimitry Andric   auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool {
1720eae32dcSDimitry Andric     return Child == Ptr.get();
1730eae32dcSDimitry Andric   });
1740eae32dcSDimitry Andric   assert(Pos != CurrentContainer.end());
1750eae32dcSDimitry Andric   NewParent->Children.push_back(std::move(*Pos));
1760eae32dcSDimitry Andric   *Pos = std::move(CurrentContainer.back());
1770eae32dcSDimitry Andric   CurrentContainer.pop_back();
1780eae32dcSDimitry Andric   Child->ParentCycle = NewParent;
179*6246ae0bSDimitry Andric 
180*6246ae0bSDimitry Andric   NewParent->Blocks.insert(NewParent->Blocks.end(), Child->block_begin(),
181*6246ae0bSDimitry Andric                            Child->block_end());
182*6246ae0bSDimitry Andric 
183*6246ae0bSDimitry Andric   for (auto &It : BlockMapTopLevel)
184*6246ae0bSDimitry Andric     if (It.second == Child)
185*6246ae0bSDimitry Andric       It.second = NewParent;
1860eae32dcSDimitry Andric }
1870eae32dcSDimitry Andric 
1880eae32dcSDimitry Andric /// \brief Main function of the cycle info computations.
1890eae32dcSDimitry Andric template <typename ContextT>
1900eae32dcSDimitry Andric void GenericCycleInfoCompute<ContextT>::run(BlockT *EntryBlock) {
1910eae32dcSDimitry Andric   LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock)
1920eae32dcSDimitry Andric                     << "\n");
1930eae32dcSDimitry Andric   dfs(EntryBlock);
1940eae32dcSDimitry Andric 
1950eae32dcSDimitry Andric   SmallVector<BlockT *, 8> Worklist;
1960eae32dcSDimitry Andric 
1970eae32dcSDimitry Andric   for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) {
1980eae32dcSDimitry Andric     const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate);
1990eae32dcSDimitry Andric 
2000eae32dcSDimitry Andric     for (BlockT *Pred : predecessors(HeaderCandidate)) {
2010eae32dcSDimitry Andric       const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
2020eae32dcSDimitry Andric       if (CandidateInfo.isAncestorOf(PredDFSInfo))
2030eae32dcSDimitry Andric         Worklist.push_back(Pred);
2040eae32dcSDimitry Andric     }
2050eae32dcSDimitry Andric     if (Worklist.empty()) {
2060eae32dcSDimitry Andric       continue;
2070eae32dcSDimitry Andric     }
2080eae32dcSDimitry Andric 
2090eae32dcSDimitry Andric     // Found a cycle with the candidate as its header.
2100eae32dcSDimitry Andric     LLVM_DEBUG(errs() << "Found cycle for header: "
2110eae32dcSDimitry Andric                       << Info.Context.print(HeaderCandidate) << "\n");
2120eae32dcSDimitry Andric     std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
2130eae32dcSDimitry Andric     NewCycle->appendEntry(HeaderCandidate);
2140eae32dcSDimitry Andric     NewCycle->appendBlock(HeaderCandidate);
2150eae32dcSDimitry Andric     Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get());
2160eae32dcSDimitry Andric 
2170eae32dcSDimitry Andric     // Helper function to process (non-back-edge) predecessors of a discovered
2180eae32dcSDimitry Andric     // block and either add them to the worklist or recognize that the given
2190eae32dcSDimitry Andric     // block is an additional cycle entry.
2200eae32dcSDimitry Andric     auto ProcessPredecessors = [&](BlockT *Block) {
2210eae32dcSDimitry Andric       LLVM_DEBUG(errs() << "  block " << Info.Context.print(Block) << ": ");
2220eae32dcSDimitry Andric 
2230eae32dcSDimitry Andric       bool IsEntry = false;
2240eae32dcSDimitry Andric       for (BlockT *Pred : predecessors(Block)) {
2250eae32dcSDimitry Andric         const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
2260eae32dcSDimitry Andric         if (CandidateInfo.isAncestorOf(PredDFSInfo)) {
2270eae32dcSDimitry Andric           Worklist.push_back(Pred);
2280eae32dcSDimitry Andric         } else {
2290eae32dcSDimitry Andric           IsEntry = true;
2300eae32dcSDimitry Andric         }
2310eae32dcSDimitry Andric       }
2320eae32dcSDimitry Andric       if (IsEntry) {
2330eae32dcSDimitry Andric         assert(!NewCycle->isEntry(Block));
2340eae32dcSDimitry Andric         LLVM_DEBUG(errs() << "append as entry\n");
2350eae32dcSDimitry Andric         NewCycle->appendEntry(Block);
2360eae32dcSDimitry Andric       } else {
2370eae32dcSDimitry Andric         LLVM_DEBUG(errs() << "append as child\n");
2380eae32dcSDimitry Andric       }
2390eae32dcSDimitry Andric     };
2400eae32dcSDimitry Andric 
2410eae32dcSDimitry Andric     do {
2420eae32dcSDimitry Andric       BlockT *Block = Worklist.pop_back_val();
2430eae32dcSDimitry Andric       if (Block == HeaderCandidate)
2440eae32dcSDimitry Andric         continue;
2450eae32dcSDimitry Andric 
2460eae32dcSDimitry Andric       // If the block has already been discovered by some cycle
2470eae32dcSDimitry Andric       // (possibly by ourself), then the outermost cycle containing it
2480eae32dcSDimitry Andric       // should become our child.
2490eae32dcSDimitry Andric       if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) {
2500eae32dcSDimitry Andric         LLVM_DEBUG(errs() << "  block " << Info.Context.print(Block) << ": ");
2510eae32dcSDimitry Andric 
2520eae32dcSDimitry Andric         if (BlockParent != NewCycle.get()) {
2530eae32dcSDimitry Andric           LLVM_DEBUG(errs()
2540eae32dcSDimitry Andric                      << "discovered child cycle "
2550eae32dcSDimitry Andric                      << Info.Context.print(BlockParent->getHeader()) << "\n");
2560eae32dcSDimitry Andric           // Make BlockParent the child of NewCycle.
257*6246ae0bSDimitry Andric           Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent);
2580eae32dcSDimitry Andric 
2590eae32dcSDimitry Andric           for (auto *ChildEntry : BlockParent->entries())
2600eae32dcSDimitry Andric             ProcessPredecessors(ChildEntry);
2610eae32dcSDimitry Andric         } else {
2620eae32dcSDimitry Andric           LLVM_DEBUG(errs()
2630eae32dcSDimitry Andric                      << "known child cycle "
2640eae32dcSDimitry Andric                      << Info.Context.print(BlockParent->getHeader()) << "\n");
2650eae32dcSDimitry Andric         }
2660eae32dcSDimitry Andric       } else {
2670eae32dcSDimitry Andric         Info.BlockMap.try_emplace(Block, NewCycle.get());
2680eae32dcSDimitry Andric         assert(!is_contained(NewCycle->Blocks, Block));
2690eae32dcSDimitry Andric         NewCycle->Blocks.push_back(Block);
2700eae32dcSDimitry Andric         ProcessPredecessors(Block);
271*6246ae0bSDimitry Andric         Info.BlockMapTopLevel.try_emplace(Block, NewCycle.get());
2720eae32dcSDimitry Andric       }
2730eae32dcSDimitry Andric     } while (!Worklist.empty());
2740eae32dcSDimitry Andric 
2750eae32dcSDimitry Andric     Info.TopLevelCycles.push_back(std::move(NewCycle));
2760eae32dcSDimitry Andric   }
2770eae32dcSDimitry Andric 
2780eae32dcSDimitry Andric   // Fix top-level cycle links and compute cycle depths.
2790eae32dcSDimitry Andric   for (auto *TLC : Info.toplevel_cycles()) {
2800eae32dcSDimitry Andric     LLVM_DEBUG(errs() << "top-level cycle: "
2810eae32dcSDimitry Andric                       << Info.Context.print(TLC->getHeader()) << "\n");
2820eae32dcSDimitry Andric 
2830eae32dcSDimitry Andric     TLC->ParentCycle = nullptr;
2840eae32dcSDimitry Andric     updateDepth(TLC);
2850eae32dcSDimitry Andric   }
2860eae32dcSDimitry Andric }
2870eae32dcSDimitry Andric 
2880eae32dcSDimitry Andric /// \brief Recompute depth values of \p SubTree and all descendants.
2890eae32dcSDimitry Andric template <typename ContextT>
2900eae32dcSDimitry Andric void GenericCycleInfoCompute<ContextT>::updateDepth(CycleT *SubTree) {
2910eae32dcSDimitry Andric   for (CycleT *Cycle : depth_first(SubTree))
2920eae32dcSDimitry Andric     Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1;
2930eae32dcSDimitry Andric }
2940eae32dcSDimitry Andric 
2950eae32dcSDimitry Andric /// \brief Compute a DFS of basic blocks starting at the function entry.
2960eae32dcSDimitry Andric ///
2970eae32dcSDimitry Andric /// Fills BlockDFSInfo with start/end counters and BlockPreorder.
2980eae32dcSDimitry Andric template <typename ContextT>
2990eae32dcSDimitry Andric void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) {
3000eae32dcSDimitry Andric   SmallVector<unsigned, 8> DFSTreeStack;
3010eae32dcSDimitry Andric   SmallVector<BlockT *, 8> TraverseStack;
3020eae32dcSDimitry Andric   unsigned Counter = 0;
3030eae32dcSDimitry Andric   TraverseStack.emplace_back(EntryBlock);
3040eae32dcSDimitry Andric 
3050eae32dcSDimitry Andric   do {
3060eae32dcSDimitry Andric     BlockT *Block = TraverseStack.back();
3070eae32dcSDimitry Andric     LLVM_DEBUG(errs() << "DFS visiting block: " << Info.Context.print(Block)
3080eae32dcSDimitry Andric                       << "\n");
3090eae32dcSDimitry Andric     if (!BlockDFSInfo.count(Block)) {
3100eae32dcSDimitry Andric       // We're visiting the block for the first time. Open its DFSInfo, add
3110eae32dcSDimitry Andric       // successors to the traversal stack, and remember the traversal stack
3120eae32dcSDimitry Andric       // depth at which the block was opened, so that we can correctly record
3130eae32dcSDimitry Andric       // its end time.
3140eae32dcSDimitry Andric       LLVM_DEBUG(errs() << "  first encountered at depth "
3150eae32dcSDimitry Andric                         << TraverseStack.size() << "\n");
3160eae32dcSDimitry Andric 
3170eae32dcSDimitry Andric       DFSTreeStack.emplace_back(TraverseStack.size());
3180eae32dcSDimitry Andric       llvm::append_range(TraverseStack, successors(Block));
3190eae32dcSDimitry Andric 
3200eae32dcSDimitry Andric       bool Added = BlockDFSInfo.try_emplace(Block, ++Counter).second;
32181ad6265SDimitry Andric       (void)Added;
3220eae32dcSDimitry Andric       assert(Added);
3230eae32dcSDimitry Andric       BlockPreorder.push_back(Block);
3240eae32dcSDimitry Andric       LLVM_DEBUG(errs() << "  preorder number: " << Counter << "\n");
3250eae32dcSDimitry Andric     } else {
3260eae32dcSDimitry Andric       assert(!DFSTreeStack.empty());
3270eae32dcSDimitry Andric       if (DFSTreeStack.back() == TraverseStack.size()) {
3280eae32dcSDimitry Andric         LLVM_DEBUG(errs() << "  ended at " << Counter << "\n");
3290eae32dcSDimitry Andric         BlockDFSInfo.find(Block)->second.End = Counter;
3300eae32dcSDimitry Andric         DFSTreeStack.pop_back();
3310eae32dcSDimitry Andric       } else {
3320eae32dcSDimitry Andric         LLVM_DEBUG(errs() << "  already done\n");
3330eae32dcSDimitry Andric       }
3340eae32dcSDimitry Andric       TraverseStack.pop_back();
3350eae32dcSDimitry Andric     }
3360eae32dcSDimitry Andric   } while (!TraverseStack.empty());
3370eae32dcSDimitry Andric   assert(DFSTreeStack.empty());
3380eae32dcSDimitry Andric 
3390eae32dcSDimitry Andric   LLVM_DEBUG(
3400eae32dcSDimitry Andric     errs() << "Preorder:\n";
3410eae32dcSDimitry Andric     for (int i = 0, e = BlockPreorder.size(); i != e; ++i) {
3420eae32dcSDimitry Andric       errs() << "  " << Info.Context.print(BlockPreorder[i]) << ": " << i << "\n";
3430eae32dcSDimitry Andric     }
3440eae32dcSDimitry Andric   );
3450eae32dcSDimitry Andric }
3460eae32dcSDimitry Andric 
3470eae32dcSDimitry Andric /// \brief Reset the object to its initial state.
3480eae32dcSDimitry Andric template <typename ContextT> void GenericCycleInfo<ContextT>::clear() {
3490eae32dcSDimitry Andric   TopLevelCycles.clear();
3500eae32dcSDimitry Andric   BlockMap.clear();
351*6246ae0bSDimitry Andric   BlockMapTopLevel.clear();
3520eae32dcSDimitry Andric }
3530eae32dcSDimitry Andric 
3540eae32dcSDimitry Andric /// \brief Compute the cycle info for a function.
3550eae32dcSDimitry Andric template <typename ContextT>
3560eae32dcSDimitry Andric void GenericCycleInfo<ContextT>::compute(FunctionT &F) {
3570eae32dcSDimitry Andric   GenericCycleInfoCompute<ContextT> Compute(*this);
3580eae32dcSDimitry Andric   Context.setFunction(F);
3590eae32dcSDimitry Andric 
3600eae32dcSDimitry Andric   LLVM_DEBUG(errs() << "Computing cycles for function: " << F.getName()
3610eae32dcSDimitry Andric                     << "\n");
3620eae32dcSDimitry Andric   Compute.run(ContextT::getEntryBlock(F));
3630eae32dcSDimitry Andric 
3640eae32dcSDimitry Andric   assert(validateTree());
3650eae32dcSDimitry Andric }
3660eae32dcSDimitry Andric 
3670eae32dcSDimitry Andric /// \brief Find the innermost cycle containing a given block.
3680eae32dcSDimitry Andric ///
3690eae32dcSDimitry Andric /// \returns the innermost cycle containing \p Block or nullptr if
3700eae32dcSDimitry Andric ///          it is not contained in any cycle.
3710eae32dcSDimitry Andric template <typename ContextT>
3720eae32dcSDimitry Andric auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const
3730eae32dcSDimitry Andric     -> CycleT * {
3740eae32dcSDimitry Andric   auto MapIt = BlockMap.find(Block);
3750eae32dcSDimitry Andric   if (MapIt != BlockMap.end())
3760eae32dcSDimitry Andric     return MapIt->second;
3770eae32dcSDimitry Andric   return nullptr;
3780eae32dcSDimitry Andric }
3790eae32dcSDimitry Andric 
38081ad6265SDimitry Andric /// \brief get the depth for the cycle which containing a given block.
38181ad6265SDimitry Andric ///
38281ad6265SDimitry Andric /// \returns the depth for the innermost cycle containing \p Block or 0 if it is
38381ad6265SDimitry Andric ///          not contained in any cycle.
38481ad6265SDimitry Andric template <typename ContextT>
38581ad6265SDimitry Andric unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const {
38681ad6265SDimitry Andric   CycleT *Cycle = getCycle(Block);
38781ad6265SDimitry Andric   if (!Cycle)
38881ad6265SDimitry Andric     return 0;
38981ad6265SDimitry Andric   return Cycle->getDepth();
39081ad6265SDimitry Andric }
39181ad6265SDimitry Andric 
39281ad6265SDimitry Andric #ifndef NDEBUG
3930eae32dcSDimitry Andric /// \brief Validate the internal consistency of the cycle tree.
3940eae32dcSDimitry Andric ///
3950eae32dcSDimitry Andric /// Note that this does \em not check that cycles are really cycles in the CFG,
3960eae32dcSDimitry Andric /// or that the right set of cycles in the CFG were found.
3970eae32dcSDimitry Andric template <typename ContextT>
3980eae32dcSDimitry Andric bool GenericCycleInfo<ContextT>::validateTree() const {
3990eae32dcSDimitry Andric   DenseSet<BlockT *> Blocks;
4000eae32dcSDimitry Andric   DenseSet<BlockT *> Entries;
4010eae32dcSDimitry Andric 
4020eae32dcSDimitry Andric   auto reportError = [](const char *File, int Line, const char *Cond) {
4030eae32dcSDimitry Andric     errs() << File << ':' << Line
4040eae32dcSDimitry Andric            << ": GenericCycleInfo::validateTree: " << Cond << '\n';
4050eae32dcSDimitry Andric   };
4060eae32dcSDimitry Andric #define check(cond)                                                            \
4070eae32dcSDimitry Andric   do {                                                                         \
4080eae32dcSDimitry Andric     if (!(cond)) {                                                             \
4090eae32dcSDimitry Andric       reportError(__FILE__, __LINE__, #cond);                                  \
4100eae32dcSDimitry Andric       return false;                                                            \
4110eae32dcSDimitry Andric     }                                                                          \
4120eae32dcSDimitry Andric   } while (false)
4130eae32dcSDimitry Andric 
4140eae32dcSDimitry Andric   for (const auto *TLC : toplevel_cycles()) {
4150eae32dcSDimitry Andric     for (const CycleT *Cycle : depth_first(TLC)) {
4160eae32dcSDimitry Andric       if (Cycle->ParentCycle)
4170eae32dcSDimitry Andric         check(is_contained(Cycle->ParentCycle->children(), Cycle));
4180eae32dcSDimitry Andric 
4190eae32dcSDimitry Andric       for (BlockT *Block : Cycle->Blocks) {
4200eae32dcSDimitry Andric         auto MapIt = BlockMap.find(Block);
4210eae32dcSDimitry Andric         check(MapIt != BlockMap.end());
4220eae32dcSDimitry Andric         check(Cycle->contains(MapIt->second));
4230eae32dcSDimitry Andric         check(Blocks.insert(Block).second); // duplicates in block list?
4240eae32dcSDimitry Andric       }
4250eae32dcSDimitry Andric       Blocks.clear();
4260eae32dcSDimitry Andric 
4270eae32dcSDimitry Andric       check(!Cycle->Entries.empty());
4280eae32dcSDimitry Andric       for (BlockT *Entry : Cycle->Entries) {
4290eae32dcSDimitry Andric         check(Entries.insert(Entry).second); // duplicate entry?
4300eae32dcSDimitry Andric         check(is_contained(Cycle->Blocks, Entry));
4310eae32dcSDimitry Andric       }
4320eae32dcSDimitry Andric       Entries.clear();
4330eae32dcSDimitry Andric 
4340eae32dcSDimitry Andric       unsigned ChildDepth = 0;
4350eae32dcSDimitry Andric       for (const CycleT *Child : Cycle->children()) {
4360eae32dcSDimitry Andric         check(Child->Depth > Cycle->Depth);
4370eae32dcSDimitry Andric         if (!ChildDepth) {
4380eae32dcSDimitry Andric           ChildDepth = Child->Depth;
4390eae32dcSDimitry Andric         } else {
4400eae32dcSDimitry Andric           check(ChildDepth == Child->Depth);
4410eae32dcSDimitry Andric         }
4420eae32dcSDimitry Andric       }
4430eae32dcSDimitry Andric     }
4440eae32dcSDimitry Andric   }
4450eae32dcSDimitry Andric 
4460eae32dcSDimitry Andric   for (const auto &Entry : BlockMap) {
4470eae32dcSDimitry Andric     BlockT *Block = Entry.first;
4480eae32dcSDimitry Andric     for (const CycleT *Cycle = Entry.second; Cycle;
4490eae32dcSDimitry Andric          Cycle = Cycle->ParentCycle) {
4500eae32dcSDimitry Andric       check(is_contained(Cycle->Blocks, Block));
4510eae32dcSDimitry Andric     }
4520eae32dcSDimitry Andric   }
4530eae32dcSDimitry Andric 
4540eae32dcSDimitry Andric #undef check
4550eae32dcSDimitry Andric 
4560eae32dcSDimitry Andric   return true;
4570eae32dcSDimitry Andric }
45881ad6265SDimitry Andric #endif
4590eae32dcSDimitry Andric 
4600eae32dcSDimitry Andric /// \brief Print the cycle info.
4610eae32dcSDimitry Andric template <typename ContextT>
4620eae32dcSDimitry Andric void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const {
4630eae32dcSDimitry Andric   for (const auto *TLC : toplevel_cycles()) {
4640eae32dcSDimitry Andric     for (const CycleT *Cycle : depth_first(TLC)) {
4650eae32dcSDimitry Andric       for (unsigned I = 0; I < Cycle->Depth; ++I)
4660eae32dcSDimitry Andric         Out << "    ";
4670eae32dcSDimitry Andric 
4680eae32dcSDimitry Andric       Out << Cycle->print(Context) << '\n';
4690eae32dcSDimitry Andric     }
4700eae32dcSDimitry Andric   }
4710eae32dcSDimitry Andric }
4720eae32dcSDimitry Andric 
4730eae32dcSDimitry Andric } // namespace llvm
4740eae32dcSDimitry Andric 
4750eae32dcSDimitry Andric #undef DEBUG_TYPE
4760eae32dcSDimitry Andric 
4770eae32dcSDimitry Andric #endif // LLVM_ADT_GENERICCYCLEIMPL_H
478