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 | |
30 | #define DEBUG_TYPE "generic-cycle-impl" |
31 | |
32 | namespace llvm { |
33 | |
34 | template <typename ContextT> |
35 | bool GenericCycle<ContextT>::contains(const GenericCycle *C) const { |
36 | if (!C) |
37 | return false; |
38 | |
39 | if (Depth > C->Depth) |
40 | return false; |
41 | while (Depth < C->Depth) |
42 | C = C->ParentCycle; |
43 | return this == C; |
44 | } |
45 | |
46 | template <typename ContextT> |
47 | void GenericCycle<ContextT>::getExitBlocks( |
48 | SmallVectorImpl<BlockT *> &TmpStorage) const { |
49 | TmpStorage.clear(); |
50 | |
51 | size_t NumExitBlocks = 0; |
52 | for (BlockT *Block : blocks()) { |
53 | llvm::append_range(TmpStorage, successors(Block)); |
54 | |
55 | for (size_t Idx = NumExitBlocks, End = TmpStorage.size(); Idx < End; |
56 | ++Idx) { |
57 | BlockT *Succ = TmpStorage[Idx]; |
58 | if (!contains(Succ)) { |
59 | auto ExitEndIt = TmpStorage.begin() + NumExitBlocks; |
60 | if (std::find(TmpStorage.begin(), ExitEndIt, Succ) == ExitEndIt) |
61 | TmpStorage[NumExitBlocks++] = Succ; |
62 | } |
63 | } |
64 | |
65 | TmpStorage.resize(NumExitBlocks); |
66 | } |
67 | } |
68 | |
69 | template <typename ContextT> |
70 | auto GenericCycle<ContextT>::() const -> BlockT * { |
71 | BlockT *Predecessor = getCyclePredecessor(); |
72 | if (!Predecessor) |
73 | return nullptr; |
74 | |
75 | assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!" ); |
76 | |
77 | if (succ_size(Predecessor) != 1) |
78 | return nullptr; |
79 | |
80 | // Make sure we are allowed to hoist instructions into the predecessor. |
81 | if (!Predecessor->isLegalToHoistInto()) |
82 | return nullptr; |
83 | |
84 | return Predecessor; |
85 | } |
86 | |
87 | template <typename ContextT> |
88 | auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * { |
89 | if (!isReducible()) |
90 | return nullptr; |
91 | |
92 | BlockT *Out = nullptr; |
93 | |
94 | // Loop over the predecessors of the header node... |
95 | BlockT * = getHeader(); |
96 | for (const auto Pred : predecessors(Header)) { |
97 | if (!contains(Pred)) { |
98 | if (Out && Out != Pred) |
99 | return nullptr; |
100 | Out = Pred; |
101 | } |
102 | } |
103 | |
104 | return Out; |
105 | } |
106 | |
107 | /// \brief Helper class for computing cycle information. |
108 | template <typename ContextT> class GenericCycleInfoCompute { |
109 | using BlockT = typename ContextT::BlockT; |
110 | using CycleInfoT = GenericCycleInfo<ContextT>; |
111 | using CycleT = typename CycleInfoT::CycleT; |
112 | |
113 | CycleInfoT &Info; |
114 | |
115 | struct DFSInfo { |
116 | unsigned Start = 0; // DFS start; positive if block is found |
117 | unsigned End = 0; // DFS end |
118 | |
119 | DFSInfo() = default; |
120 | explicit DFSInfo(unsigned Start) : Start(Start) {} |
121 | |
122 | /// Whether this node is an ancestor (or equal to) the node \p Other |
123 | /// in the DFS tree. |
124 | bool isAncestorOf(const DFSInfo &Other) const { |
125 | return Start <= Other.Start && Other.End <= End; |
126 | } |
127 | }; |
128 | |
129 | DenseMap<BlockT *, DFSInfo> BlockDFSInfo; |
130 | SmallVector<BlockT *, 8> BlockPreorder; |
131 | |
132 | GenericCycleInfoCompute(const GenericCycleInfoCompute &) = delete; |
133 | GenericCycleInfoCompute &operator=(const GenericCycleInfoCompute &) = delete; |
134 | |
135 | public: |
136 | GenericCycleInfoCompute(CycleInfoT &Info) : Info(Info) {} |
137 | |
138 | void run(BlockT *EntryBlock); |
139 | |
140 | static void updateDepth(CycleT *SubTree); |
141 | |
142 | private: |
143 | void dfs(BlockT *EntryBlock); |
144 | }; |
145 | |
146 | template <typename ContextT> |
147 | auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(BlockT *Block) |
148 | -> CycleT * { |
149 | auto Cycle = BlockMapTopLevel.find(Block); |
150 | if (Cycle != BlockMapTopLevel.end()) |
151 | return Cycle->second; |
152 | |
153 | auto MapIt = BlockMap.find(Block); |
154 | if (MapIt == BlockMap.end()) |
155 | return nullptr; |
156 | |
157 | auto *C = MapIt->second; |
158 | while (C->ParentCycle) |
159 | C = C->ParentCycle; |
160 | BlockMapTopLevel.try_emplace(Block, C); |
161 | return C; |
162 | } |
163 | |
164 | template <typename ContextT> |
165 | void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent, |
166 | CycleT *Child) { |
167 | assert((!Child->ParentCycle && !NewParent->ParentCycle) && |
168 | "NewParent and Child must be both top level cycle!\n" ); |
169 | auto &CurrentContainer = |
170 | Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles; |
171 | auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool { |
172 | return Child == Ptr.get(); |
173 | }); |
174 | assert(Pos != CurrentContainer.end()); |
175 | NewParent->Children.push_back(std::move(*Pos)); |
176 | *Pos = std::move(CurrentContainer.back()); |
177 | CurrentContainer.pop_back(); |
178 | Child->ParentCycle = NewParent; |
179 | |
180 | NewParent->Blocks.insert(Child->block_begin(), Child->block_end()); |
181 | |
182 | for (auto &It : BlockMapTopLevel) |
183 | if (It.second == Child) |
184 | It.second = NewParent; |
185 | } |
186 | |
187 | template <typename ContextT> |
188 | void GenericCycleInfo<ContextT>::addBlockToCycle(BlockT *Block, CycleT *Cycle) { |
189 | // FixMe: Appending NewBlock is fine as a set of blocks in a cycle. When |
190 | // printing, cycle NewBlock is at the end of list but it should be in the |
191 | // middle to represent actual traversal of a cycle. |
192 | Cycle->appendBlock(Block); |
193 | BlockMap.try_emplace(Block, Cycle); |
194 | |
195 | CycleT *ParentCycle = Cycle->getParentCycle(); |
196 | while (ParentCycle) { |
197 | Cycle = ParentCycle; |
198 | Cycle->appendBlock(Block); |
199 | ParentCycle = Cycle->getParentCycle(); |
200 | } |
201 | |
202 | BlockMapTopLevel.try_emplace(Block, Cycle); |
203 | } |
204 | |
205 | /// \brief Main function of the cycle info computations. |
206 | template <typename ContextT> |
207 | void GenericCycleInfoCompute<ContextT>::run(BlockT *EntryBlock) { |
208 | LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock) |
209 | << "\n" ); |
210 | dfs(EntryBlock); |
211 | |
212 | SmallVector<BlockT *, 8> Worklist; |
213 | |
214 | for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) { |
215 | const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate); |
216 | |
217 | for (BlockT *Pred : predecessors(HeaderCandidate)) { |
218 | const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred); |
219 | if (CandidateInfo.isAncestorOf(PredDFSInfo)) |
220 | Worklist.push_back(Pred); |
221 | } |
222 | if (Worklist.empty()) { |
223 | continue; |
224 | } |
225 | |
226 | // Found a cycle with the candidate as its header. |
227 | LLVM_DEBUG(errs() << "Found cycle for header: " |
228 | << Info.Context.print(HeaderCandidate) << "\n" ); |
229 | std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>(); |
230 | NewCycle->appendEntry(HeaderCandidate); |
231 | NewCycle->appendBlock(HeaderCandidate); |
232 | Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get()); |
233 | |
234 | // Helper function to process (non-back-edge) predecessors of a discovered |
235 | // block and either add them to the worklist or recognize that the given |
236 | // block is an additional cycle entry. |
237 | auto ProcessPredecessors = [&](BlockT *Block) { |
238 | LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": " ); |
239 | |
240 | bool IsEntry = false; |
241 | for (BlockT *Pred : predecessors(Block)) { |
242 | const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred); |
243 | if (CandidateInfo.isAncestorOf(PredDFSInfo)) { |
244 | Worklist.push_back(Pred); |
245 | } else { |
246 | IsEntry = true; |
247 | } |
248 | } |
249 | if (IsEntry) { |
250 | assert(!NewCycle->isEntry(Block)); |
251 | LLVM_DEBUG(errs() << "append as entry\n" ); |
252 | NewCycle->appendEntry(Block); |
253 | } else { |
254 | LLVM_DEBUG(errs() << "append as child\n" ); |
255 | } |
256 | }; |
257 | |
258 | do { |
259 | BlockT *Block = Worklist.pop_back_val(); |
260 | if (Block == HeaderCandidate) |
261 | continue; |
262 | |
263 | // If the block has already been discovered by some cycle |
264 | // (possibly by ourself), then the outermost cycle containing it |
265 | // should become our child. |
266 | if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) { |
267 | LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": " ); |
268 | |
269 | if (BlockParent != NewCycle.get()) { |
270 | LLVM_DEBUG(errs() |
271 | << "discovered child cycle " |
272 | << Info.Context.print(BlockParent->getHeader()) << "\n" ); |
273 | // Make BlockParent the child of NewCycle. |
274 | Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent); |
275 | |
276 | for (auto *ChildEntry : BlockParent->entries()) |
277 | ProcessPredecessors(ChildEntry); |
278 | } else { |
279 | LLVM_DEBUG(errs() |
280 | << "known child cycle " |
281 | << Info.Context.print(BlockParent->getHeader()) << "\n" ); |
282 | } |
283 | } else { |
284 | Info.BlockMap.try_emplace(Block, NewCycle.get()); |
285 | assert(!is_contained(NewCycle->Blocks, Block)); |
286 | NewCycle->Blocks.insert(Block); |
287 | ProcessPredecessors(Block); |
288 | Info.BlockMapTopLevel.try_emplace(Block, NewCycle.get()); |
289 | } |
290 | } while (!Worklist.empty()); |
291 | |
292 | Info.TopLevelCycles.push_back(std::move(NewCycle)); |
293 | } |
294 | |
295 | // Fix top-level cycle links and compute cycle depths. |
296 | for (auto *TLC : Info.toplevel_cycles()) { |
297 | LLVM_DEBUG(errs() << "top-level cycle: " |
298 | << Info.Context.print(TLC->getHeader()) << "\n" ); |
299 | |
300 | TLC->ParentCycle = nullptr; |
301 | updateDepth(SubTree: TLC); |
302 | } |
303 | } |
304 | |
305 | /// \brief Recompute depth values of \p SubTree and all descendants. |
306 | template <typename ContextT> |
307 | void GenericCycleInfoCompute<ContextT>::updateDepth(CycleT *SubTree) { |
308 | for (CycleT *Cycle : depth_first(SubTree)) |
309 | Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1; |
310 | } |
311 | |
312 | /// \brief Compute a DFS of basic blocks starting at the function entry. |
313 | /// |
314 | /// Fills BlockDFSInfo with start/end counters and BlockPreorder. |
315 | template <typename ContextT> |
316 | void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) { |
317 | SmallVector<unsigned, 8> DFSTreeStack; |
318 | SmallVector<BlockT *, 8> TraverseStack; |
319 | unsigned Counter = 0; |
320 | TraverseStack.emplace_back(EntryBlock); |
321 | |
322 | do { |
323 | BlockT *Block = TraverseStack.back(); |
324 | LLVM_DEBUG(errs() << "DFS visiting block: " << Info.Context.print(Block) |
325 | << "\n" ); |
326 | if (!BlockDFSInfo.count(Block)) { |
327 | // We're visiting the block for the first time. Open its DFSInfo, add |
328 | // successors to the traversal stack, and remember the traversal stack |
329 | // depth at which the block was opened, so that we can correctly record |
330 | // its end time. |
331 | LLVM_DEBUG(errs() << " first encountered at depth " |
332 | << TraverseStack.size() << "\n" ); |
333 | |
334 | DFSTreeStack.emplace_back(TraverseStack.size()); |
335 | llvm::append_range(TraverseStack, successors(Block)); |
336 | |
337 | bool Added = BlockDFSInfo.try_emplace(Block, ++Counter).second; |
338 | (void)Added; |
339 | assert(Added); |
340 | BlockPreorder.push_back(Block); |
341 | LLVM_DEBUG(errs() << " preorder number: " << Counter << "\n" ); |
342 | } else { |
343 | assert(!DFSTreeStack.empty()); |
344 | if (DFSTreeStack.back() == TraverseStack.size()) { |
345 | LLVM_DEBUG(errs() << " ended at " << Counter << "\n" ); |
346 | BlockDFSInfo.find(Block)->second.End = Counter; |
347 | DFSTreeStack.pop_back(); |
348 | } else { |
349 | LLVM_DEBUG(errs() << " already done\n" ); |
350 | } |
351 | TraverseStack.pop_back(); |
352 | } |
353 | } while (!TraverseStack.empty()); |
354 | assert(DFSTreeStack.empty()); |
355 | |
356 | LLVM_DEBUG( |
357 | errs() << "Preorder:\n" ; |
358 | for (int i = 0, e = BlockPreorder.size(); i != e; ++i) { |
359 | errs() << " " << Info.Context.print(BlockPreorder[i]) << ": " << i << "\n" ; |
360 | } |
361 | ); |
362 | } |
363 | |
364 | /// \brief Reset the object to its initial state. |
365 | template <typename ContextT> void GenericCycleInfo<ContextT>::clear() { |
366 | TopLevelCycles.clear(); |
367 | BlockMap.clear(); |
368 | BlockMapTopLevel.clear(); |
369 | } |
370 | |
371 | /// \brief Compute the cycle info for a function. |
372 | template <typename ContextT> |
373 | void GenericCycleInfo<ContextT>::compute(FunctionT &F) { |
374 | GenericCycleInfoCompute<ContextT> Compute(*this); |
375 | Context = ContextT(&F); |
376 | |
377 | LLVM_DEBUG(errs() << "Computing cycles for function: " << F.getName() |
378 | << "\n" ); |
379 | Compute.run(&F.front()); |
380 | |
381 | assert(validateTree()); |
382 | } |
383 | |
384 | template <typename ContextT> |
385 | void GenericCycleInfo<ContextT>::splitCriticalEdge(BlockT *Pred, BlockT *Succ, |
386 | BlockT *NewBlock) { |
387 | // Edge Pred-Succ is replaced by edges Pred-NewBlock and NewBlock-Succ, all |
388 | // cycles that had blocks Pred and Succ also get NewBlock. |
389 | CycleT *Cycle = getSmallestCommonCycle(A: getCycle(Block: Pred), B: getCycle(Block: Succ)); |
390 | if (!Cycle) |
391 | return; |
392 | |
393 | addBlockToCycle(Block: NewBlock, Cycle); |
394 | assert(validateTree()); |
395 | } |
396 | |
397 | /// \brief Find the innermost cycle containing a given block. |
398 | /// |
399 | /// \returns the innermost cycle containing \p Block or nullptr if |
400 | /// it is not contained in any cycle. |
401 | template <typename ContextT> |
402 | auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const |
403 | -> CycleT * { |
404 | return BlockMap.lookup(Block); |
405 | } |
406 | |
407 | /// \brief Find the innermost cycle containing both given cycles. |
408 | /// |
409 | /// \returns the innermost cycle containing both \p A and \p B |
410 | /// or nullptr if there is no such cycle. |
411 | template <typename ContextT> |
412 | auto GenericCycleInfo<ContextT>::getSmallestCommonCycle(CycleT *A, |
413 | CycleT *B) const |
414 | -> CycleT * { |
415 | if (!A || !B) |
416 | return nullptr; |
417 | |
418 | // If cycles A and B have different depth replace them with parent cycle |
419 | // until they have the same depth. |
420 | while (A->getDepth() > B->getDepth()) |
421 | A = A->getParentCycle(); |
422 | while (B->getDepth() > A->getDepth()) |
423 | B = B->getParentCycle(); |
424 | |
425 | // Cycles A and B are at same depth but may be disjoint, replace them with |
426 | // parent cycles until we find cycle that contains both or we run out of |
427 | // parent cycles. |
428 | while (A != B) { |
429 | A = A->getParentCycle(); |
430 | B = B->getParentCycle(); |
431 | } |
432 | |
433 | return A; |
434 | } |
435 | |
436 | /// \brief get the depth for the cycle which containing a given block. |
437 | /// |
438 | /// \returns the depth for the innermost cycle containing \p Block or 0 if it is |
439 | /// not contained in any cycle. |
440 | template <typename ContextT> |
441 | unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const { |
442 | CycleT *Cycle = getCycle(Block); |
443 | if (!Cycle) |
444 | return 0; |
445 | return Cycle->getDepth(); |
446 | } |
447 | |
448 | #ifndef NDEBUG |
449 | /// \brief Validate the internal consistency of the cycle tree. |
450 | /// |
451 | /// Note that this does \em not check that cycles are really cycles in the CFG, |
452 | /// or that the right set of cycles in the CFG were found. |
453 | template <typename ContextT> |
454 | bool GenericCycleInfo<ContextT>::validateTree() const { |
455 | DenseSet<BlockT *> Blocks; |
456 | DenseSet<BlockT *> Entries; |
457 | |
458 | auto reportError = [](const char *File, int Line, const char *Cond) { |
459 | errs() << File << ':' << Line |
460 | << ": GenericCycleInfo::validateTree: " << Cond << '\n'; |
461 | }; |
462 | #define check(cond) \ |
463 | do { \ |
464 | if (!(cond)) { \ |
465 | reportError(__FILE__, __LINE__, #cond); \ |
466 | return false; \ |
467 | } \ |
468 | } while (false) |
469 | |
470 | for (const auto *TLC : toplevel_cycles()) { |
471 | for (const CycleT *Cycle : depth_first(TLC)) { |
472 | if (Cycle->ParentCycle) |
473 | check(is_contained(Cycle->ParentCycle->children(), Cycle)); |
474 | |
475 | for (BlockT *Block : Cycle->Blocks) { |
476 | auto MapIt = BlockMap.find(Block); |
477 | check(MapIt != BlockMap.end()); |
478 | check(Cycle->contains(MapIt->second)); |
479 | check(Blocks.insert(Block).second); // duplicates in block list? |
480 | } |
481 | Blocks.clear(); |
482 | |
483 | check(!Cycle->Entries.empty()); |
484 | for (BlockT *Entry : Cycle->Entries) { |
485 | check(Entries.insert(Entry).second); // duplicate entry? |
486 | check(is_contained(Cycle->Blocks, Entry)); |
487 | } |
488 | Entries.clear(); |
489 | |
490 | unsigned ChildDepth = 0; |
491 | for (const CycleT *Child : Cycle->children()) { |
492 | check(Child->Depth > Cycle->Depth); |
493 | if (!ChildDepth) { |
494 | ChildDepth = Child->Depth; |
495 | } else { |
496 | check(ChildDepth == Child->Depth); |
497 | } |
498 | } |
499 | } |
500 | } |
501 | |
502 | for (const auto &Entry : BlockMap) { |
503 | BlockT *Block = Entry.first; |
504 | for (const CycleT *Cycle = Entry.second; Cycle; |
505 | Cycle = Cycle->ParentCycle) { |
506 | check(is_contained(Cycle->Blocks, Block)); |
507 | } |
508 | } |
509 | |
510 | #undef check |
511 | |
512 | return true; |
513 | } |
514 | #endif |
515 | |
516 | /// \brief Print the cycle info. |
517 | template <typename ContextT> |
518 | void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const { |
519 | for (const auto *TLC : toplevel_cycles()) { |
520 | for (const CycleT *Cycle : depth_first(TLC)) { |
521 | for (unsigned I = 0; I < Cycle->Depth; ++I) |
522 | Out << " " ; |
523 | |
524 | Out << Cycle->print(Context) << '\n'; |
525 | } |
526 | } |
527 | } |
528 | |
529 | } // namespace llvm |
530 | |
531 | #undef DEBUG_TYPE |
532 | |
533 | #endif // LLVM_ADT_GENERICCYCLEIMPL_H |
534 | |