1 | //===- GenericCycleImpl.h -------------------------------------*- C++ -*---===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// |
9 | /// \file |
10 | /// This template implementation resides in a separate file so that it |
11 | /// does not get injected into every .cpp file that includes the |
12 | /// generic header. |
13 | /// |
14 | /// DO NOT INCLUDE THIS FILE WHEN MERELY USING CYCLEINFO. |
15 | /// |
16 | /// This file should only be included by files that implement a |
17 | /// specialization of the relevant templates. Currently these are: |
18 | /// - llvm/lib/IR/CycleInfo.cpp |
19 | /// - llvm/lib/CodeGen/MachineCycleAnalysis.cpp |
20 | /// |
21 | //===----------------------------------------------------------------------===// |
22 | |
23 | #ifndef LLVM_ADT_GENERICCYCLEIMPL_H |
24 | #define LLVM_ADT_GENERICCYCLEIMPL_H |
25 | |
26 | #include "llvm/ADT/DenseSet.h" |
27 | #include "llvm/ADT/DepthFirstIterator.h" |
28 | #include "llvm/ADT/GenericCycleInfo.h" |
29 | #include "llvm/ADT/StringExtras.h" |
30 | |
31 | #define DEBUG_TYPE "generic-cycle-impl" |
32 | |
33 | namespace llvm { |
34 | |
35 | template <typename ContextT> |
36 | bool GenericCycle<ContextT>::contains(const GenericCycle *C) const { |
37 | if (!C) |
38 | return false; |
39 | |
40 | if (Depth > C->Depth) |
41 | return false; |
42 | while (Depth < C->Depth) |
43 | C = C->ParentCycle; |
44 | return this == C; |
45 | } |
46 | |
47 | template <typename ContextT> |
48 | void GenericCycle<ContextT>::getExitBlocks( |
49 | SmallVectorImpl<BlockT *> &TmpStorage) const { |
50 | if (!ExitBlocksCache.empty()) { |
51 | TmpStorage = ExitBlocksCache; |
52 | return; |
53 | } |
54 | |
55 | TmpStorage.clear(); |
56 | |
57 | size_t NumExitBlocks = 0; |
58 | for (BlockT *Block : blocks()) { |
59 | llvm::append_range(TmpStorage, successors(Block)); |
60 | |
61 | for (size_t Idx = NumExitBlocks, End = TmpStorage.size(); Idx < End; |
62 | ++Idx) { |
63 | BlockT *Succ = TmpStorage[Idx]; |
64 | if (!contains(Succ)) { |
65 | auto ExitEndIt = TmpStorage.begin() + NumExitBlocks; |
66 | if (std::find(TmpStorage.begin(), ExitEndIt, Succ) == ExitEndIt) |
67 | TmpStorage[NumExitBlocks++] = Succ; |
68 | } |
69 | } |
70 | |
71 | TmpStorage.resize(NumExitBlocks); |
72 | } |
73 | ExitBlocksCache.append(TmpStorage.begin(), TmpStorage.end()); |
74 | } |
75 | |
76 | template <typename ContextT> |
77 | void GenericCycle<ContextT>::getExitingBlocks( |
78 | SmallVectorImpl<BlockT *> &TmpStorage) const { |
79 | TmpStorage.clear(); |
80 | |
81 | for (BlockT *Block : blocks()) { |
82 | for (BlockT *Succ : successors(Block)) { |
83 | if (!contains(Succ)) { |
84 | TmpStorage.push_back(Block); |
85 | break; |
86 | } |
87 | } |
88 | } |
89 | } |
90 | |
91 | template <typename ContextT> |
92 | auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * { |
93 | BlockT *Predecessor = getCyclePredecessor(); |
94 | if (!Predecessor) |
95 | return nullptr; |
96 | |
97 | assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!"); |
98 | |
99 | if (succ_size(Predecessor) != 1) |
100 | return nullptr; |
101 | |
102 | // Make sure we are allowed to hoist instructions into the predecessor. |
103 | if (!Predecessor->isLegalToHoistInto()) |
104 | return nullptr; |
105 | |
106 | return Predecessor; |
107 | } |
108 | |
109 | template <typename ContextT> |
110 | auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * { |
111 | if (!isReducible()) |
112 | return nullptr; |
113 | |
114 | BlockT *Out = nullptr; |
115 | |
116 | // Loop over the predecessors of the header node... |
117 | BlockT *Header = getHeader(); |
118 | for (const auto Pred : predecessors(Header)) { |
119 | if (!contains(Pred)) { |
120 | if (Out && Out != Pred) |
121 | return nullptr; |
122 | Out = Pred; |
123 | } |
124 | } |
125 | |
126 | return Out; |
127 | } |
128 | |
129 | /// \brief Verify that this is actually a well-formed cycle in the CFG. |
130 | template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const { |
131 | #ifndef NDEBUG |
132 | assert(!Blocks.empty() && "Cycle cannot be empty."); |
133 | DenseSet<BlockT *> Blocks; |
134 | for (BlockT *BB : blocks()) { |
135 | assert(Blocks.insert(BB).second); // duplicates in block list? |
136 | } |
137 | assert(!Entries.empty() && "Cycle must have one or more entries."); |
138 | |
139 | DenseSet<BlockT *> Entries; |
140 | for (BlockT *Entry : entries()) { |
141 | assert(Entries.insert(Entry).second); // duplicate entry? |
142 | assert(contains(Entry)); |
143 | } |
144 | |
145 | // Setup for using a depth-first iterator to visit every block in the cycle. |
146 | SmallVector<BlockT *, 8> ExitBBs; |
147 | getExitBlocks(TmpStorage&: ExitBBs); |
148 | df_iterator_default_set<BlockT *> VisitSet; |
149 | VisitSet.insert(ExitBBs.begin(), ExitBBs.end()); |
150 | |
151 | // Keep track of the BBs visited. |
152 | SmallPtrSet<BlockT *, 8> VisitedBBs; |
153 | |
154 | // Check the individual blocks. |
155 | for (BlockT *BB : depth_first_ext(getHeader(), VisitSet)) { |
156 | assert(llvm::any_of(llvm::children<BlockT *>(BB), |
157 | [&](BlockT *B) { return contains(B); }) && |
158 | "Cycle block has no in-cycle successors!"); |
159 | |
160 | assert(llvm::any_of(llvm::inverse_children<BlockT *>(BB), |
161 | [&](BlockT *B) { return contains(B); }) && |
162 | "Cycle block has no in-cycle predecessors!"); |
163 | |
164 | DenseSet<BlockT *> OutsideCyclePreds; |
165 | for (BlockT *B : llvm::inverse_children<BlockT *>(BB)) |
166 | if (!contains(B)) |
167 | OutsideCyclePreds.insert(B); |
168 | |
169 | if (Entries.contains(BB)) { |
170 | assert(!OutsideCyclePreds.empty() && "Entry is unreachable!"); |
171 | } else if (!OutsideCyclePreds.empty()) { |
172 | // A non-entry block shouldn't be reachable from outside the cycle, |
173 | // though it is permitted if the predecessor is not itself actually |
174 | // reachable. |
175 | BlockT *EntryBB = &BB->getParent()->front(); |
176 | for (BlockT *CB : depth_first(EntryBB)) |
177 | assert(!OutsideCyclePreds.contains(CB) && |
178 | "Non-entry block reachable from outside!"); |
179 | } |
180 | assert(BB != &getHeader()->getParent()->front() && |
181 | "Cycle contains function entry block!"); |
182 | |
183 | VisitedBBs.insert(BB); |
184 | } |
185 | |
186 | if (VisitedBBs.size() != getNumBlocks()) { |
187 | dbgs() << "The following blocks are unreachable in the cycle:\n "; |
188 | ListSeparator LS; |
189 | for (auto *BB : Blocks) { |
190 | if (!VisitedBBs.count(BB)) { |
191 | dbgs() << LS; |
192 | BB->printAsOperand(dbgs()); |
193 | } |
194 | } |
195 | dbgs() << "\n"; |
196 | llvm_unreachable("Unreachable block in cycle"); |
197 | } |
198 | |
199 | verifyCycleNest(); |
200 | #endif |
201 | } |
202 | |
203 | /// \brief Verify the parent-child relations of this cycle. |
204 | /// |
205 | /// Note that this does \em not check that cycle is really a cycle in the CFG. |
206 | template <typename ContextT> |
207 | void GenericCycle<ContextT>::verifyCycleNest() const { |
208 | #ifndef NDEBUG |
209 | // Check the subcycles. |
210 | for (GenericCycle *Child : children()) { |
211 | // Each block in each subcycle should be contained within this cycle. |
212 | for (BlockT *BB : Child->blocks()) { |
213 | assert(contains(BB) && |
214 | "Cycle does not contain all the blocks of a subcycle!"); |
215 | } |
216 | assert(Child->Depth == Depth + 1); |
217 | } |
218 | |
219 | // Check the parent cycle pointer. |
220 | if (ParentCycle) { |
221 | assert(is_contained(ParentCycle->children(), this) && |
222 | "Cycle is not a subcycle of its parent!"); |
223 | } |
224 | #endif |
225 | } |
226 | |
227 | /// \brief Helper class for computing cycle information. |
228 | template <typename ContextT> class GenericCycleInfoCompute { |
229 | using BlockT = typename ContextT::BlockT; |
230 | using CycleInfoT = GenericCycleInfo<ContextT>; |
231 | using CycleT = typename CycleInfoT::CycleT; |
232 | |
233 | CycleInfoT &Info; |
234 | |
235 | struct DFSInfo { |
236 | unsigned Start = 0; // DFS start; positive if block is found |
237 | unsigned End = 0; // DFS end |
238 | |
239 | DFSInfo() = default; |
240 | explicit DFSInfo(unsigned Start) : Start(Start) {} |
241 | |
242 | explicit operator bool() const { return Start; } |
243 | |
244 | /// Whether this node is an ancestor (or equal to) the node \p Other |
245 | /// in the DFS tree. |
246 | bool isAncestorOf(const DFSInfo &Other) const { |
247 | return Start <= Other.Start && Other.End <= End; |
248 | } |
249 | }; |
250 | |
251 | DenseMap<BlockT *, DFSInfo> BlockDFSInfo; |
252 | SmallVector<BlockT *, 8> BlockPreorder; |
253 | |
254 | GenericCycleInfoCompute(const GenericCycleInfoCompute &) = delete; |
255 | GenericCycleInfoCompute &operator=(const GenericCycleInfoCompute &) = delete; |
256 | |
257 | public: |
258 | GenericCycleInfoCompute(CycleInfoT &Info) : Info(Info) {} |
259 | |
260 | void run(BlockT *EntryBlock); |
261 | |
262 | static void updateDepth(CycleT *SubTree); |
263 | |
264 | private: |
265 | void dfs(BlockT *EntryBlock); |
266 | }; |
267 | |
268 | template <typename ContextT> |
269 | auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(BlockT *Block) |
270 | -> CycleT * { |
271 | auto Cycle = BlockMapTopLevel.find(Block); |
272 | if (Cycle != BlockMapTopLevel.end()) |
273 | return Cycle->second; |
274 | |
275 | auto MapIt = BlockMap.find(Block); |
276 | if (MapIt == BlockMap.end()) |
277 | return nullptr; |
278 | |
279 | auto *C = MapIt->second; |
280 | while (C->ParentCycle) |
281 | C = C->ParentCycle; |
282 | BlockMapTopLevel.try_emplace(Block, C); |
283 | return C; |
284 | } |
285 | |
286 | template <typename ContextT> |
287 | void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent, |
288 | CycleT *Child) { |
289 | assert((!Child->ParentCycle && !NewParent->ParentCycle) && |
290 | "NewParent and Child must be both top level cycle!\n"); |
291 | auto &CurrentContainer = |
292 | Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles; |
293 | auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool { |
294 | return Child == Ptr.get(); |
295 | }); |
296 | assert(Pos != CurrentContainer.end()); |
297 | NewParent->Children.push_back(std::move(*Pos)); |
298 | *Pos = std::move(CurrentContainer.back()); |
299 | CurrentContainer.pop_back(); |
300 | Child->ParentCycle = NewParent; |
301 | |
302 | NewParent->Blocks.insert_range(Child->blocks()); |
303 | |
304 | for (auto &It : BlockMapTopLevel) |
305 | if (It.second == Child) |
306 | It.second = NewParent; |
307 | NewParent->clearCache(); |
308 | Child->clearCache(); |
309 | } |
310 | |
311 | template <typename ContextT> |
312 | void GenericCycleInfo<ContextT>::addBlockToCycle(BlockT *Block, CycleT *Cycle) { |
313 | // FixMe: Appending NewBlock is fine as a set of blocks in a cycle. When |
314 | // printing, cycle NewBlock is at the end of list but it should be in the |
315 | // middle to represent actual traversal of a cycle. |
316 | Cycle->appendBlock(Block); |
317 | BlockMap.try_emplace(Block, Cycle); |
318 | |
319 | CycleT *ParentCycle = Cycle->getParentCycle(); |
320 | while (ParentCycle) { |
321 | Cycle = ParentCycle; |
322 | Cycle->appendBlock(Block); |
323 | ParentCycle = Cycle->getParentCycle(); |
324 | } |
325 | |
326 | BlockMapTopLevel.try_emplace(Block, Cycle); |
327 | Cycle->clearCache(); |
328 | } |
329 | |
330 | /// \brief Main function of the cycle info computations. |
331 | template <typename ContextT> |
332 | void GenericCycleInfoCompute<ContextT>::run(BlockT *EntryBlock) { |
333 | LLVM_DEBUG(errs() << "Entry block: "<< Info.Context.print(EntryBlock) |
334 | << "\n"); |
335 | dfs(EntryBlock); |
336 | |
337 | SmallVector<BlockT *, 8> Worklist; |
338 | |
339 | for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) { |
340 | const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate); |
341 | |
342 | for (BlockT *Pred : predecessors(HeaderCandidate)) { |
343 | const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred); |
344 | // This automatically ignores unreachable predecessors since they have |
345 | // zeros in their DFSInfo. |
346 | if (CandidateInfo.isAncestorOf(PredDFSInfo)) |
347 | Worklist.push_back(Pred); |
348 | } |
349 | if (Worklist.empty()) { |
350 | continue; |
351 | } |
352 | |
353 | // Found a cycle with the candidate as its header. |
354 | LLVM_DEBUG(errs() << "Found cycle for header: " |
355 | << Info.Context.print(HeaderCandidate) << "\n"); |
356 | std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>(); |
357 | NewCycle->appendEntry(HeaderCandidate); |
358 | NewCycle->appendBlock(HeaderCandidate); |
359 | Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get()); |
360 | |
361 | // Helper function to process (non-back-edge) predecessors of a discovered |
362 | // block and either add them to the worklist or recognize that the given |
363 | // block is an additional cycle entry. |
364 | auto ProcessPredecessors = [&](BlockT *Block) { |
365 | LLVM_DEBUG(errs() << " block "<< Info.Context.print(Block) << ": "); |
366 | |
367 | bool IsEntry = false; |
368 | for (BlockT *Pred : predecessors(Block)) { |
369 | const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred); |
370 | if (CandidateInfo.isAncestorOf(PredDFSInfo)) { |
371 | Worklist.push_back(Pred); |
372 | } else if (!PredDFSInfo) { |
373 | // Ignore an unreachable predecessor. It will will incorrectly cause |
374 | // Block to be treated as a cycle entry. |
375 | LLVM_DEBUG(errs() << " skipped unreachable predecessor.\n"); |
376 | } else { |
377 | IsEntry = true; |
378 | } |
379 | } |
380 | if (IsEntry) { |
381 | assert(!NewCycle->isEntry(Block)); |
382 | LLVM_DEBUG(errs() << "append as entry\n"); |
383 | NewCycle->appendEntry(Block); |
384 | } else { |
385 | LLVM_DEBUG(errs() << "append as child\n"); |
386 | } |
387 | }; |
388 | |
389 | do { |
390 | BlockT *Block = Worklist.pop_back_val(); |
391 | if (Block == HeaderCandidate) |
392 | continue; |
393 | |
394 | // If the block has already been discovered by some cycle |
395 | // (possibly by ourself), then the outermost cycle containing it |
396 | // should become our child. |
397 | if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) { |
398 | LLVM_DEBUG(errs() << " block "<< Info.Context.print(Block) << ": "); |
399 | |
400 | if (BlockParent != NewCycle.get()) { |
401 | LLVM_DEBUG(errs() |
402 | << "discovered child cycle " |
403 | << Info.Context.print(BlockParent->getHeader()) << "\n"); |
404 | // Make BlockParent the child of NewCycle. |
405 | Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent); |
406 | |
407 | for (auto *ChildEntry : BlockParent->entries()) |
408 | ProcessPredecessors(ChildEntry); |
409 | } else { |
410 | LLVM_DEBUG(errs() |
411 | << "known child cycle " |
412 | << Info.Context.print(BlockParent->getHeader()) << "\n"); |
413 | } |
414 | } else { |
415 | Info.BlockMap.try_emplace(Block, NewCycle.get()); |
416 | assert(!is_contained(NewCycle->Blocks, Block)); |
417 | NewCycle->Blocks.insert(Block); |
418 | ProcessPredecessors(Block); |
419 | Info.BlockMapTopLevel.try_emplace(Block, NewCycle.get()); |
420 | } |
421 | } while (!Worklist.empty()); |
422 | |
423 | Info.TopLevelCycles.push_back(std::move(NewCycle)); |
424 | } |
425 | |
426 | // Fix top-level cycle links and compute cycle depths. |
427 | for (auto *TLC : Info.toplevel_cycles()) { |
428 | LLVM_DEBUG(errs() << "top-level cycle: " |
429 | << Info.Context.print(TLC->getHeader()) << "\n"); |
430 | |
431 | TLC->ParentCycle = nullptr; |
432 | updateDepth(SubTree: TLC); |
433 | } |
434 | } |
435 | |
436 | /// \brief Recompute depth values of \p SubTree and all descendants. |
437 | template <typename ContextT> |
438 | void GenericCycleInfoCompute<ContextT>::updateDepth(CycleT *SubTree) { |
439 | for (CycleT *Cycle : depth_first(SubTree)) |
440 | Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1; |
441 | } |
442 | |
443 | /// \brief Compute a DFS of basic blocks starting at the function entry. |
444 | /// |
445 | /// Fills BlockDFSInfo with start/end counters and BlockPreorder. |
446 | template <typename ContextT> |
447 | void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) { |
448 | SmallVector<unsigned, 8> DFSTreeStack; |
449 | SmallVector<BlockT *, 8> TraverseStack; |
450 | unsigned Counter = 0; |
451 | TraverseStack.emplace_back(EntryBlock); |
452 | |
453 | do { |
454 | BlockT *Block = TraverseStack.back(); |
455 | LLVM_DEBUG(errs() << "DFS visiting block: "<< Info.Context.print(Block) |
456 | << "\n"); |
457 | if (BlockDFSInfo.try_emplace(Block, Counter + 1).second) { |
458 | ++Counter; |
459 | |
460 | // We're visiting the block for the first time. Open its DFSInfo, add |
461 | // successors to the traversal stack, and remember the traversal stack |
462 | // depth at which the block was opened, so that we can correctly record |
463 | // its end time. |
464 | LLVM_DEBUG(errs() << " first encountered at depth " |
465 | << TraverseStack.size() << "\n"); |
466 | |
467 | DFSTreeStack.emplace_back(TraverseStack.size()); |
468 | llvm::append_range(TraverseStack, successors(Block)); |
469 | |
470 | BlockPreorder.push_back(Block); |
471 | LLVM_DEBUG(errs() << " preorder number: "<< Counter << "\n"); |
472 | } else { |
473 | assert(!DFSTreeStack.empty()); |
474 | if (DFSTreeStack.back() == TraverseStack.size()) { |
475 | LLVM_DEBUG(errs() << " ended at "<< Counter << "\n"); |
476 | BlockDFSInfo.find(Block)->second.End = Counter; |
477 | DFSTreeStack.pop_back(); |
478 | } else { |
479 | LLVM_DEBUG(errs() << " already done\n"); |
480 | } |
481 | TraverseStack.pop_back(); |
482 | } |
483 | } while (!TraverseStack.empty()); |
484 | assert(DFSTreeStack.empty()); |
485 | |
486 | LLVM_DEBUG( |
487 | errs() << "Preorder:\n"; |
488 | for (int i = 0, e = BlockPreorder.size(); i != e; ++i) { |
489 | errs() << " "<< Info.Context.print(BlockPreorder[i]) << ": "<< i << "\n"; |
490 | } |
491 | ); |
492 | } |
493 | |
494 | /// \brief Reset the object to its initial state. |
495 | template <typename ContextT> void GenericCycleInfo<ContextT>::clear() { |
496 | TopLevelCycles.clear(); |
497 | BlockMap.clear(); |
498 | BlockMapTopLevel.clear(); |
499 | } |
500 | |
501 | /// \brief Compute the cycle info for a function. |
502 | template <typename ContextT> |
503 | void GenericCycleInfo<ContextT>::compute(FunctionT &F) { |
504 | GenericCycleInfoCompute<ContextT> Compute(*this); |
505 | Context = ContextT(&F); |
506 | |
507 | LLVM_DEBUG(errs() << "Computing cycles for function: "<< F.getName() |
508 | << "\n"); |
509 | Compute.run(&F.front()); |
510 | } |
511 | |
512 | template <typename ContextT> |
513 | void GenericCycleInfo<ContextT>::splitCriticalEdge(BlockT *Pred, BlockT *Succ, |
514 | BlockT *NewBlock) { |
515 | // Edge Pred-Succ is replaced by edges Pred-NewBlock and NewBlock-Succ, all |
516 | // cycles that had blocks Pred and Succ also get NewBlock. |
517 | CycleT *Cycle = getSmallestCommonCycle(A: getCycle(Block: Pred), B: getCycle(Block: Succ)); |
518 | if (!Cycle) |
519 | return; |
520 | |
521 | addBlockToCycle(Block: NewBlock, Cycle); |
522 | verifyCycleNest(); |
523 | } |
524 | |
525 | /// \brief Find the innermost cycle containing a given block. |
526 | /// |
527 | /// \returns the innermost cycle containing \p Block or nullptr if |
528 | /// it is not contained in any cycle. |
529 | template <typename ContextT> |
530 | auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const |
531 | -> CycleT * { |
532 | return BlockMap.lookup(Block); |
533 | } |
534 | |
535 | /// \brief Find the innermost cycle containing both given cycles. |
536 | /// |
537 | /// \returns the innermost cycle containing both \p A and \p B |
538 | /// or nullptr if there is no such cycle. |
539 | template <typename ContextT> |
540 | auto GenericCycleInfo<ContextT>::getSmallestCommonCycle(CycleT *A, |
541 | CycleT *B) const |
542 | -> CycleT * { |
543 | if (!A || !B) |
544 | return nullptr; |
545 | |
546 | // If cycles A and B have different depth replace them with parent cycle |
547 | // until they have the same depth. |
548 | while (A->getDepth() > B->getDepth()) |
549 | A = A->getParentCycle(); |
550 | while (B->getDepth() > A->getDepth()) |
551 | B = B->getParentCycle(); |
552 | |
553 | // Cycles A and B are at same depth but may be disjoint, replace them with |
554 | // parent cycles until we find cycle that contains both or we run out of |
555 | // parent cycles. |
556 | while (A != B) { |
557 | A = A->getParentCycle(); |
558 | B = B->getParentCycle(); |
559 | } |
560 | |
561 | return A; |
562 | } |
563 | |
564 | /// \brief get the depth for the cycle which containing a given block. |
565 | /// |
566 | /// \returns the depth for the innermost cycle containing \p Block or 0 if it is |
567 | /// not contained in any cycle. |
568 | template <typename ContextT> |
569 | unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const { |
570 | CycleT *Cycle = getCycle(Block); |
571 | if (!Cycle) |
572 | return 0; |
573 | return Cycle->getDepth(); |
574 | } |
575 | |
576 | /// \brief Verify the internal consistency of the cycle tree. |
577 | /// |
578 | /// Note that this does \em not check that cycles are really cycles in the CFG, |
579 | /// or that the right set of cycles in the CFG were found. |
580 | template <typename ContextT> |
581 | void GenericCycleInfo<ContextT>::verifyCycleNest(bool VerifyFull) const { |
582 | #ifndef NDEBUG |
583 | DenseSet<BlockT *> CycleHeaders; |
584 | |
585 | for (CycleT *TopCycle : toplevel_cycles()) { |
586 | for (CycleT *Cycle : depth_first(TopCycle)) { |
587 | BlockT *Header = Cycle->getHeader(); |
588 | assert(CycleHeaders.insert(Header).second); |
589 | if (VerifyFull) |
590 | Cycle->verifyCycle(); |
591 | else |
592 | Cycle->verifyCycleNest(); |
593 | // Check the block map entries for blocks contained in this cycle. |
594 | for (BlockT *BB : Cycle->blocks()) { |
595 | auto MapIt = BlockMap.find(BB); |
596 | assert(MapIt != BlockMap.end()); |
597 | assert(Cycle->contains(MapIt->second)); |
598 | } |
599 | } |
600 | } |
601 | #endif |
602 | } |
603 | |
604 | /// \brief Verify that the entire cycle tree well-formed. |
605 | template <typename ContextT> void GenericCycleInfo<ContextT>::verify() const { |
606 | verifyCycleNest(/*VerifyFull=*/VerifyFull: true); |
607 | } |
608 | |
609 | /// \brief Print the cycle info. |
610 | template <typename ContextT> |
611 | void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const { |
612 | for (const auto *TLC : toplevel_cycles()) { |
613 | for (const CycleT *Cycle : depth_first(TLC)) { |
614 | for (unsigned I = 0; I < Cycle->Depth; ++I) |
615 | Out << " "; |
616 | |
617 | Out << Cycle->print(Context) << '\n'; |
618 | } |
619 | } |
620 | } |
621 | |
622 | } // namespace llvm |
623 | |
624 | #undef DEBUG_TYPE |
625 | |
626 | #endif // LLVM_ADT_GENERICCYCLEIMPL_H |
627 |
Definitions
- contains
- getExitBlocks
- getExitingBlocks
- getCyclePreheader
- getCyclePredecessor
- verifyCycle
- verifyCycleNest
- GenericCycleInfoCompute
- DFSInfo
- DFSInfo
- DFSInfo
- operator bool
- isAncestorOf
- GenericCycleInfoCompute
- operator=
- GenericCycleInfoCompute
- getTopLevelParentCycle
- moveTopLevelCycleToNewParent
- addBlockToCycle
- run
- updateDepth
- dfs
- clear
- compute
- splitCriticalEdge
- getCycle
- getSmallestCommonCycle
- getCycleDepth
- verifyCycleNest
- verify
Improve your Profiling and Debugging skills
Find out more