xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleImpl.h (revision 0eae32dcef82f6f06de6419a0d623d7def0cc8f6)
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