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