File indexing completed on 2026-05-10 08:43:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #ifndef LLVM_ADT_GENERICCYCLEIMPL_H
0024 #define LLVM_ADT_GENERICCYCLEIMPL_H
0025
0026 #include "llvm/ADT/DenseSet.h"
0027 #include "llvm/ADT/DepthFirstIterator.h"
0028 #include "llvm/ADT/GenericCycleInfo.h"
0029 #include "llvm/ADT/StringExtras.h"
0030
0031 #define DEBUG_TYPE "generic-cycle-impl"
0032
0033 namespace llvm {
0034
0035 template <typename ContextT>
0036 bool GenericCycle<ContextT>::contains(const GenericCycle *C) const {
0037 if (!C)
0038 return false;
0039
0040 if (Depth > C->Depth)
0041 return false;
0042 while (Depth < C->Depth)
0043 C = C->ParentCycle;
0044 return this == C;
0045 }
0046
0047 template <typename ContextT>
0048 void GenericCycle<ContextT>::getExitBlocks(
0049 SmallVectorImpl<BlockT *> &TmpStorage) const {
0050 if (!ExitBlocksCache.empty()) {
0051 TmpStorage = ExitBlocksCache;
0052 return;
0053 }
0054
0055 TmpStorage.clear();
0056
0057 size_t NumExitBlocks = 0;
0058 for (BlockT *Block : blocks()) {
0059 llvm::append_range(TmpStorage, successors(Block));
0060
0061 for (size_t Idx = NumExitBlocks, End = TmpStorage.size(); Idx < End;
0062 ++Idx) {
0063 BlockT *Succ = TmpStorage[Idx];
0064 if (!contains(Succ)) {
0065 auto ExitEndIt = TmpStorage.begin() + NumExitBlocks;
0066 if (std::find(TmpStorage.begin(), ExitEndIt, Succ) == ExitEndIt)
0067 TmpStorage[NumExitBlocks++] = Succ;
0068 }
0069 }
0070
0071 TmpStorage.resize(NumExitBlocks);
0072 }
0073 ExitBlocksCache.append(TmpStorage.begin(), TmpStorage.end());
0074 }
0075
0076 template <typename ContextT>
0077 void GenericCycle<ContextT>::getExitingBlocks(
0078 SmallVectorImpl<BlockT *> &TmpStorage) const {
0079 TmpStorage.clear();
0080
0081 for (BlockT *Block : blocks()) {
0082 for (BlockT *Succ : successors(Block)) {
0083 if (!contains(Succ)) {
0084 TmpStorage.push_back(Block);
0085 break;
0086 }
0087 }
0088 }
0089 }
0090
0091 template <typename ContextT>
0092 auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * {
0093 BlockT *Predecessor = getCyclePredecessor();
0094 if (!Predecessor)
0095 return nullptr;
0096
0097 assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!");
0098
0099 if (succ_size(Predecessor) != 1)
0100 return nullptr;
0101
0102
0103 if (!Predecessor->isLegalToHoistInto())
0104 return nullptr;
0105
0106 return Predecessor;
0107 }
0108
0109 template <typename ContextT>
0110 auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * {
0111 if (!isReducible())
0112 return nullptr;
0113
0114 BlockT *Out = nullptr;
0115
0116
0117 BlockT *Header = getHeader();
0118 for (const auto Pred : predecessors(Header)) {
0119 if (!contains(Pred)) {
0120 if (Out && Out != Pred)
0121 return nullptr;
0122 Out = Pred;
0123 }
0124 }
0125
0126 return Out;
0127 }
0128
0129
0130 template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
0131 #ifndef NDEBUG
0132 assert(!Blocks.empty() && "Cycle cannot be empty.");
0133 DenseSet<BlockT *> Blocks;
0134 for (BlockT *BB : blocks()) {
0135 assert(Blocks.insert(BB).second);
0136 }
0137 assert(!Entries.empty() && "Cycle must have one or more entries.");
0138
0139 DenseSet<BlockT *> Entries;
0140 for (BlockT *Entry : entries()) {
0141 assert(Entries.insert(Entry).second);
0142 assert(contains(Entry));
0143 }
0144
0145
0146 SmallVector<BlockT *, 8> ExitBBs;
0147 getExitBlocks(ExitBBs);
0148 df_iterator_default_set<BlockT *> VisitSet;
0149 VisitSet.insert(ExitBBs.begin(), ExitBBs.end());
0150
0151
0152 SmallPtrSet<BlockT *, 8> VisitedBBs;
0153
0154
0155 for (BlockT *BB : depth_first_ext(getHeader(), VisitSet)) {
0156 assert(llvm::any_of(llvm::children<BlockT *>(BB),
0157 [&](BlockT *B) { return contains(B); }) &&
0158 "Cycle block has no in-cycle successors!");
0159
0160 assert(llvm::any_of(llvm::inverse_children<BlockT *>(BB),
0161 [&](BlockT *B) { return contains(B); }) &&
0162 "Cycle block has no in-cycle predecessors!");
0163
0164 DenseSet<BlockT *> OutsideCyclePreds;
0165 for (BlockT *B : llvm::inverse_children<BlockT *>(BB))
0166 if (!contains(B))
0167 OutsideCyclePreds.insert(B);
0168
0169 if (Entries.contains(BB)) {
0170 assert(!OutsideCyclePreds.empty() && "Entry is unreachable!");
0171 } else if (!OutsideCyclePreds.empty()) {
0172
0173
0174
0175 BlockT *EntryBB = &BB->getParent()->front();
0176 for (BlockT *CB : depth_first(EntryBB))
0177 assert(!OutsideCyclePreds.contains(CB) &&
0178 "Non-entry block reachable from outside!");
0179 }
0180 assert(BB != &getHeader()->getParent()->front() &&
0181 "Cycle contains function entry block!");
0182
0183 VisitedBBs.insert(BB);
0184 }
0185
0186 if (VisitedBBs.size() != getNumBlocks()) {
0187 dbgs() << "The following blocks are unreachable in the cycle:\n ";
0188 ListSeparator LS;
0189 for (auto *BB : Blocks) {
0190 if (!VisitedBBs.count(BB)) {
0191 dbgs() << LS;
0192 BB->printAsOperand(dbgs());
0193 }
0194 }
0195 dbgs() << "\n";
0196 llvm_unreachable("Unreachable block in cycle");
0197 }
0198
0199 verifyCycleNest();
0200 #endif
0201 }
0202
0203
0204
0205
0206 template <typename ContextT>
0207 void GenericCycle<ContextT>::verifyCycleNest() const {
0208 #ifndef NDEBUG
0209
0210 for (GenericCycle *Child : children()) {
0211
0212 for (BlockT *BB : Child->blocks()) {
0213 assert(contains(BB) &&
0214 "Cycle does not contain all the blocks of a subcycle!");
0215 }
0216 assert(Child->Depth == Depth + 1);
0217 }
0218
0219
0220 if (ParentCycle) {
0221 assert(is_contained(ParentCycle->children(), this) &&
0222 "Cycle is not a subcycle of its parent!");
0223 }
0224 #endif
0225 }
0226
0227
0228 template <typename ContextT> class GenericCycleInfoCompute {
0229 using BlockT = typename ContextT::BlockT;
0230 using CycleInfoT = GenericCycleInfo<ContextT>;
0231 using CycleT = typename CycleInfoT::CycleT;
0232
0233 CycleInfoT &Info;
0234
0235 struct DFSInfo {
0236 unsigned Start = 0;
0237 unsigned End = 0;
0238
0239 DFSInfo() = default;
0240 explicit DFSInfo(unsigned Start) : Start(Start) {}
0241
0242 explicit operator bool() const { return Start; }
0243
0244
0245
0246 bool isAncestorOf(const DFSInfo &Other) const {
0247 return Start <= Other.Start && Other.End <= End;
0248 }
0249 };
0250
0251 DenseMap<BlockT *, DFSInfo> BlockDFSInfo;
0252 SmallVector<BlockT *, 8> BlockPreorder;
0253
0254 GenericCycleInfoCompute(const GenericCycleInfoCompute &) = delete;
0255 GenericCycleInfoCompute &operator=(const GenericCycleInfoCompute &) = delete;
0256
0257 public:
0258 GenericCycleInfoCompute(CycleInfoT &Info) : Info(Info) {}
0259
0260 void run(BlockT *EntryBlock);
0261
0262 static void updateDepth(CycleT *SubTree);
0263
0264 private:
0265 void dfs(BlockT *EntryBlock);
0266 };
0267
0268 template <typename ContextT>
0269 auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(BlockT *Block)
0270 -> CycleT * {
0271 auto Cycle = BlockMapTopLevel.find(Block);
0272 if (Cycle != BlockMapTopLevel.end())
0273 return Cycle->second;
0274
0275 auto MapIt = BlockMap.find(Block);
0276 if (MapIt == BlockMap.end())
0277 return nullptr;
0278
0279 auto *C = MapIt->second;
0280 while (C->ParentCycle)
0281 C = C->ParentCycle;
0282 BlockMapTopLevel.try_emplace(Block, C);
0283 return C;
0284 }
0285
0286 template <typename ContextT>
0287 void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
0288 CycleT *Child) {
0289 assert((!Child->ParentCycle && !NewParent->ParentCycle) &&
0290 "NewParent and Child must be both top level cycle!\n");
0291 auto &CurrentContainer =
0292 Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles;
0293 auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool {
0294 return Child == Ptr.get();
0295 });
0296 assert(Pos != CurrentContainer.end());
0297 NewParent->Children.push_back(std::move(*Pos));
0298 *Pos = std::move(CurrentContainer.back());
0299 CurrentContainer.pop_back();
0300 Child->ParentCycle = NewParent;
0301
0302 NewParent->Blocks.insert(Child->block_begin(), Child->block_end());
0303
0304 for (auto &It : BlockMapTopLevel)
0305 if (It.second == Child)
0306 It.second = NewParent;
0307 NewParent->clearCache();
0308 Child->clearCache();
0309 }
0310
0311 template <typename ContextT>
0312 void GenericCycleInfo<ContextT>::addBlockToCycle(BlockT *Block, CycleT *Cycle) {
0313
0314
0315
0316 Cycle->appendBlock(Block);
0317 BlockMap.try_emplace(Block, Cycle);
0318
0319 CycleT *ParentCycle = Cycle->getParentCycle();
0320 while (ParentCycle) {
0321 Cycle = ParentCycle;
0322 Cycle->appendBlock(Block);
0323 ParentCycle = Cycle->getParentCycle();
0324 }
0325
0326 BlockMapTopLevel.try_emplace(Block, Cycle);
0327 Cycle->clearCache();
0328 }
0329
0330
0331 template <typename ContextT>
0332 void GenericCycleInfoCompute<ContextT>::run(BlockT *EntryBlock) {
0333 LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock)
0334 << "\n");
0335 dfs(EntryBlock);
0336
0337 SmallVector<BlockT *, 8> Worklist;
0338
0339 for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) {
0340 const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate);
0341
0342 for (BlockT *Pred : predecessors(HeaderCandidate)) {
0343 const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
0344
0345
0346 if (CandidateInfo.isAncestorOf(PredDFSInfo))
0347 Worklist.push_back(Pred);
0348 }
0349 if (Worklist.empty()) {
0350 continue;
0351 }
0352
0353
0354 LLVM_DEBUG(errs() << "Found cycle for header: "
0355 << Info.Context.print(HeaderCandidate) << "\n");
0356 std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
0357 NewCycle->appendEntry(HeaderCandidate);
0358 NewCycle->appendBlock(HeaderCandidate);
0359 Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get());
0360
0361
0362
0363
0364 auto ProcessPredecessors = [&](BlockT *Block) {
0365 LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": ");
0366
0367 bool IsEntry = false;
0368 for (BlockT *Pred : predecessors(Block)) {
0369 const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
0370 if (CandidateInfo.isAncestorOf(PredDFSInfo)) {
0371 Worklist.push_back(Pred);
0372 } else if (!PredDFSInfo) {
0373
0374
0375 LLVM_DEBUG(errs() << " skipped unreachable predecessor.\n");
0376 } else {
0377 IsEntry = true;
0378 }
0379 }
0380 if (IsEntry) {
0381 assert(!NewCycle->isEntry(Block));
0382 LLVM_DEBUG(errs() << "append as entry\n");
0383 NewCycle->appendEntry(Block);
0384 } else {
0385 LLVM_DEBUG(errs() << "append as child\n");
0386 }
0387 };
0388
0389 do {
0390 BlockT *Block = Worklist.pop_back_val();
0391 if (Block == HeaderCandidate)
0392 continue;
0393
0394
0395
0396
0397 if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) {
0398 LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": ");
0399
0400 if (BlockParent != NewCycle.get()) {
0401 LLVM_DEBUG(errs()
0402 << "discovered child cycle "
0403 << Info.Context.print(BlockParent->getHeader()) << "\n");
0404
0405 Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent);
0406
0407 for (auto *ChildEntry : BlockParent->entries())
0408 ProcessPredecessors(ChildEntry);
0409 } else {
0410 LLVM_DEBUG(errs()
0411 << "known child cycle "
0412 << Info.Context.print(BlockParent->getHeader()) << "\n");
0413 }
0414 } else {
0415 Info.BlockMap.try_emplace(Block, NewCycle.get());
0416 assert(!is_contained(NewCycle->Blocks, Block));
0417 NewCycle->Blocks.insert(Block);
0418 ProcessPredecessors(Block);
0419 Info.BlockMapTopLevel.try_emplace(Block, NewCycle.get());
0420 }
0421 } while (!Worklist.empty());
0422
0423 Info.TopLevelCycles.push_back(std::move(NewCycle));
0424 }
0425
0426
0427 for (auto *TLC : Info.toplevel_cycles()) {
0428 LLVM_DEBUG(errs() << "top-level cycle: "
0429 << Info.Context.print(TLC->getHeader()) << "\n");
0430
0431 TLC->ParentCycle = nullptr;
0432 updateDepth(TLC);
0433 }
0434 }
0435
0436
0437 template <typename ContextT>
0438 void GenericCycleInfoCompute<ContextT>::updateDepth(CycleT *SubTree) {
0439 for (CycleT *Cycle : depth_first(SubTree))
0440 Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1;
0441 }
0442
0443
0444
0445
0446 template <typename ContextT>
0447 void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) {
0448 SmallVector<unsigned, 8> DFSTreeStack;
0449 SmallVector<BlockT *, 8> TraverseStack;
0450 unsigned Counter = 0;
0451 TraverseStack.emplace_back(EntryBlock);
0452
0453 do {
0454 BlockT *Block = TraverseStack.back();
0455 LLVM_DEBUG(errs() << "DFS visiting block: " << Info.Context.print(Block)
0456 << "\n");
0457 if (!BlockDFSInfo.count(Block)) {
0458
0459
0460
0461
0462 LLVM_DEBUG(errs() << " first encountered at depth "
0463 << TraverseStack.size() << "\n");
0464
0465 DFSTreeStack.emplace_back(TraverseStack.size());
0466 llvm::append_range(TraverseStack, successors(Block));
0467
0468 bool Added = BlockDFSInfo.try_emplace(Block, ++Counter).second;
0469 (void)Added;
0470 assert(Added);
0471 BlockPreorder.push_back(Block);
0472 LLVM_DEBUG(errs() << " preorder number: " << Counter << "\n");
0473 } else {
0474 assert(!DFSTreeStack.empty());
0475 if (DFSTreeStack.back() == TraverseStack.size()) {
0476 LLVM_DEBUG(errs() << " ended at " << Counter << "\n");
0477 BlockDFSInfo.find(Block)->second.End = Counter;
0478 DFSTreeStack.pop_back();
0479 } else {
0480 LLVM_DEBUG(errs() << " already done\n");
0481 }
0482 TraverseStack.pop_back();
0483 }
0484 } while (!TraverseStack.empty());
0485 assert(DFSTreeStack.empty());
0486
0487 LLVM_DEBUG(
0488 errs() << "Preorder:\n";
0489 for (int i = 0, e = BlockPreorder.size(); i != e; ++i) {
0490 errs() << " " << Info.Context.print(BlockPreorder[i]) << ": " << i << "\n";
0491 }
0492 );
0493 }
0494
0495
0496 template <typename ContextT> void GenericCycleInfo<ContextT>::clear() {
0497 TopLevelCycles.clear();
0498 BlockMap.clear();
0499 BlockMapTopLevel.clear();
0500 }
0501
0502
0503 template <typename ContextT>
0504 void GenericCycleInfo<ContextT>::compute(FunctionT &F) {
0505 GenericCycleInfoCompute<ContextT> Compute(*this);
0506 Context = ContextT(&F);
0507
0508 LLVM_DEBUG(errs() << "Computing cycles for function: " << F.getName()
0509 << "\n");
0510 Compute.run(&F.front());
0511 }
0512
0513 template <typename ContextT>
0514 void GenericCycleInfo<ContextT>::splitCriticalEdge(BlockT *Pred, BlockT *Succ,
0515 BlockT *NewBlock) {
0516
0517
0518 CycleT *Cycle = getSmallestCommonCycle(getCycle(Pred), getCycle(Succ));
0519 if (!Cycle)
0520 return;
0521
0522 addBlockToCycle(NewBlock, Cycle);
0523 verifyCycleNest();
0524 }
0525
0526
0527
0528
0529
0530 template <typename ContextT>
0531 auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const
0532 -> CycleT * {
0533 return BlockMap.lookup(Block);
0534 }
0535
0536
0537
0538
0539
0540 template <typename ContextT>
0541 auto GenericCycleInfo<ContextT>::getSmallestCommonCycle(CycleT *A,
0542 CycleT *B) const
0543 -> CycleT * {
0544 if (!A || !B)
0545 return nullptr;
0546
0547
0548
0549 while (A->getDepth() > B->getDepth())
0550 A = A->getParentCycle();
0551 while (B->getDepth() > A->getDepth())
0552 B = B->getParentCycle();
0553
0554
0555
0556
0557 while (A != B) {
0558 A = A->getParentCycle();
0559 B = B->getParentCycle();
0560 }
0561
0562 return A;
0563 }
0564
0565
0566
0567
0568
0569 template <typename ContextT>
0570 unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const {
0571 CycleT *Cycle = getCycle(Block);
0572 if (!Cycle)
0573 return 0;
0574 return Cycle->getDepth();
0575 }
0576
0577
0578
0579
0580
0581 template <typename ContextT>
0582 void GenericCycleInfo<ContextT>::verifyCycleNest(bool VerifyFull) const {
0583 #ifndef NDEBUG
0584 DenseSet<BlockT *> CycleHeaders;
0585
0586 for (CycleT *TopCycle : toplevel_cycles()) {
0587 for (CycleT *Cycle : depth_first(TopCycle)) {
0588 BlockT *Header = Cycle->getHeader();
0589 assert(CycleHeaders.insert(Header).second);
0590 if (VerifyFull)
0591 Cycle->verifyCycle();
0592 else
0593 Cycle->verifyCycleNest();
0594
0595 for (BlockT *BB : Cycle->blocks()) {
0596 auto MapIt = BlockMap.find(BB);
0597 assert(MapIt != BlockMap.end());
0598 assert(Cycle->contains(MapIt->second));
0599 }
0600 }
0601 }
0602 #endif
0603 }
0604
0605
0606 template <typename ContextT> void GenericCycleInfo<ContextT>::verify() const {
0607 verifyCycleNest(true);
0608 }
0609
0610
0611 template <typename ContextT>
0612 void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const {
0613 for (const auto *TLC : toplevel_cycles()) {
0614 for (const CycleT *Cycle : depth_first(TLC)) {
0615 for (unsigned I = 0; I < Cycle->Depth; ++I)
0616 Out << " ";
0617
0618 Out << Cycle->print(Context) << '\n';
0619 }
0620 }
0621 }
0622
0623 }
0624
0625 #undef DEBUG_TYPE
0626
0627 #endif