File indexing completed on 2026-05-10 08:44:31
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 #ifndef LLVM_SUPPORT_GENERICLOOPINFO_H
0041 #define LLVM_SUPPORT_GENERICLOOPINFO_H
0042
0043 #include "llvm/ADT/DenseSet.h"
0044 #include "llvm/ADT/PostOrderIterator.h"
0045 #include "llvm/ADT/STLExtras.h"
0046 #include "llvm/ADT/SetOperations.h"
0047 #include "llvm/Support/Allocator.h"
0048 #include "llvm/Support/GenericDomTree.h"
0049
0050 namespace llvm {
0051
0052 template <class N, class M> class LoopInfoBase;
0053 template <class N, class M> class LoopBase;
0054
0055
0056
0057
0058
0059 template <class BlockT, class LoopT> class LoopBase {
0060 LoopT *ParentLoop;
0061
0062 std::vector<LoopT *> SubLoops;
0063
0064
0065 std::vector<BlockT *> Blocks;
0066
0067 SmallPtrSet<const BlockT *, 8> DenseBlockSet;
0068
0069 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
0070
0071 bool IsInvalid = false;
0072 #endif
0073
0074 LoopBase(const LoopBase<BlockT, LoopT> &) = delete;
0075 const LoopBase<BlockT, LoopT> &
0076 operator=(const LoopBase<BlockT, LoopT> &) = delete;
0077
0078 public:
0079
0080
0081
0082 unsigned getLoopDepth() const {
0083 assert(!isInvalid() && "Loop not in a valid state!");
0084 unsigned D = 1;
0085 for (const LoopT *CurLoop = ParentLoop; CurLoop;
0086 CurLoop = CurLoop->ParentLoop)
0087 ++D;
0088 return D;
0089 }
0090 BlockT *getHeader() const { return getBlocks().front(); }
0091
0092
0093
0094
0095
0096
0097
0098
0099 LoopT *getParentLoop() const { return ParentLoop; }
0100
0101
0102
0103 const LoopT *getOutermostLoop() const {
0104 const LoopT *L = static_cast<const LoopT *>(this);
0105 while (L->ParentLoop)
0106 L = L->ParentLoop;
0107 return L;
0108 }
0109
0110 LoopT *getOutermostLoop() {
0111 LoopT *L = static_cast<LoopT *>(this);
0112 while (L->ParentLoop)
0113 L = L->ParentLoop;
0114 return L;
0115 }
0116
0117
0118 void setParentLoop(LoopT *L) {
0119 assert(!isInvalid() && "Loop not in a valid state!");
0120 ParentLoop = L;
0121 }
0122
0123
0124 bool contains(const LoopT *L) const {
0125 assert(!isInvalid() && "Loop not in a valid state!");
0126 if (L == this)
0127 return true;
0128 if (!L)
0129 return false;
0130 return contains(L->getParentLoop());
0131 }
0132
0133
0134 bool contains(const BlockT *BB) const {
0135 assert(!isInvalid() && "Loop not in a valid state!");
0136 return DenseBlockSet.count(BB);
0137 }
0138
0139
0140 template <class InstT> bool contains(const InstT *Inst) const {
0141 return contains(Inst->getParent());
0142 }
0143
0144
0145 const std::vector<LoopT *> &getSubLoops() const {
0146 assert(!isInvalid() && "Loop not in a valid state!");
0147 return SubLoops;
0148 }
0149 std::vector<LoopT *> &getSubLoopsVector() {
0150 assert(!isInvalid() && "Loop not in a valid state!");
0151 return SubLoops;
0152 }
0153 typedef typename std::vector<LoopT *>::const_iterator iterator;
0154 typedef
0155 typename std::vector<LoopT *>::const_reverse_iterator reverse_iterator;
0156 iterator begin() const { return getSubLoops().begin(); }
0157 iterator end() const { return getSubLoops().end(); }
0158 reverse_iterator rbegin() const { return getSubLoops().rbegin(); }
0159 reverse_iterator rend() const { return getSubLoops().rend(); }
0160
0161
0162
0163
0164
0165
0166
0167 bool isInnermost() const { return getSubLoops().empty(); }
0168
0169
0170 bool isOutermost() const { return getParentLoop() == nullptr; }
0171
0172
0173 ArrayRef<BlockT *> getBlocks() const {
0174 assert(!isInvalid() && "Loop not in a valid state!");
0175 return Blocks;
0176 }
0177 typedef typename ArrayRef<BlockT *>::const_iterator block_iterator;
0178 block_iterator block_begin() const { return getBlocks().begin(); }
0179 block_iterator block_end() const { return getBlocks().end(); }
0180 inline iterator_range<block_iterator> blocks() const {
0181 assert(!isInvalid() && "Loop not in a valid state!");
0182 return make_range(block_begin(), block_end());
0183 }
0184
0185
0186
0187 unsigned getNumBlocks() const {
0188 assert(!isInvalid() && "Loop not in a valid state!");
0189 return Blocks.size();
0190 }
0191
0192
0193
0194 std::vector<BlockT *> &getBlocksVector() {
0195 assert(!isInvalid() && "Loop not in a valid state!");
0196 return Blocks;
0197 }
0198
0199
0200 SmallPtrSetImpl<const BlockT *> &getBlocksSet() {
0201 assert(!isInvalid() && "Loop not in a valid state!");
0202 return DenseBlockSet;
0203 }
0204
0205
0206 const SmallPtrSetImpl<const BlockT *> &getBlocksSet() const {
0207 assert(!isInvalid() && "Loop not in a valid state!");
0208 return DenseBlockSet;
0209 }
0210
0211
0212
0213
0214
0215
0216
0217 bool isInvalid() const {
0218 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
0219 return IsInvalid;
0220 #else
0221 return false;
0222 #endif
0223 }
0224
0225
0226
0227 bool isLoopExiting(const BlockT *BB) const {
0228 assert(!isInvalid() && "Loop not in a valid state!");
0229 assert(contains(BB) && "Exiting block must be part of the loop");
0230 for (const auto *Succ : children<const BlockT *>(BB)) {
0231 if (!contains(Succ))
0232 return true;
0233 }
0234 return false;
0235 }
0236
0237
0238
0239
0240
0241 bool isLoopLatch(const BlockT *BB) const {
0242 assert(!isInvalid() && "Loop not in a valid state!");
0243 assert(contains(BB) && "block does not belong to the loop");
0244 return llvm::is_contained(inverse_children<BlockT *>(getHeader()), BB);
0245 }
0246
0247
0248 unsigned getNumBackEdges() const {
0249 assert(!isInvalid() && "Loop not in a valid state!");
0250 return llvm::count_if(inverse_children<BlockT *>(getHeader()),
0251 [&](BlockT *Pred) { return contains(Pred); });
0252 }
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 void getExitingBlocks(SmallVectorImpl<BlockT *> &ExitingBlocks) const;
0266
0267
0268
0269 BlockT *getExitingBlock() const;
0270
0271
0272
0273 void getExitBlocks(SmallVectorImpl<BlockT *> &ExitBlocks) const;
0274
0275
0276
0277 BlockT *getExitBlock() const;
0278
0279
0280
0281 bool hasDedicatedExits() const;
0282
0283
0284
0285 void getUniqueExitBlocks(SmallVectorImpl<BlockT *> &ExitBlocks) const;
0286
0287
0288
0289
0290
0291 void getUniqueNonLatchExitBlocks(SmallVectorImpl<BlockT *> &ExitBlocks) const;
0292
0293
0294
0295 BlockT *getUniqueExitBlock() const;
0296
0297
0298
0299 BlockT *getUniqueLatchExitBlock() const;
0300
0301
0302 bool hasNoExitBlocks() const;
0303
0304
0305 typedef std::pair<BlockT *, BlockT *> Edge;
0306
0307
0308 void getExitEdges(SmallVectorImpl<Edge> &ExitEdges) const;
0309
0310
0311
0312
0313
0314
0315
0316 BlockT *getLoopPreheader() const;
0317
0318
0319
0320
0321
0322 BlockT *getLoopPredecessor() const;
0323
0324
0325
0326 BlockT *getLoopLatch() const;
0327
0328
0329
0330 void getLoopLatches(SmallVectorImpl<BlockT *> &LoopLatches) const {
0331 assert(!isInvalid() && "Loop not in a valid state!");
0332 BlockT *H = getHeader();
0333 for (const auto Pred : inverse_children<BlockT *>(H))
0334 if (contains(Pred))
0335 LoopLatches.push_back(Pred);
0336 }
0337
0338
0339
0340 template <class Type>
0341 static void getInnerLoopsInPreorder(const LoopT &L,
0342 SmallVectorImpl<Type> &PreOrderLoops) {
0343 SmallVector<LoopT *, 4> PreOrderWorklist;
0344 PreOrderWorklist.append(L.rbegin(), L.rend());
0345
0346 while (!PreOrderWorklist.empty()) {
0347 LoopT *L = PreOrderWorklist.pop_back_val();
0348
0349
0350 PreOrderWorklist.append(L->rbegin(), L->rend());
0351 PreOrderLoops.push_back(L);
0352 }
0353 }
0354
0355
0356
0357 SmallVector<const LoopT *, 4> getLoopsInPreorder() const {
0358 SmallVector<const LoopT *, 4> PreOrderLoops;
0359 const LoopT *CurLoop = static_cast<const LoopT *>(this);
0360 PreOrderLoops.push_back(CurLoop);
0361 getInnerLoopsInPreorder(*CurLoop, PreOrderLoops);
0362 return PreOrderLoops;
0363 }
0364 SmallVector<LoopT *, 4> getLoopsInPreorder() {
0365 SmallVector<LoopT *, 4> PreOrderLoops;
0366 LoopT *CurLoop = static_cast<LoopT *>(this);
0367 PreOrderLoops.push_back(CurLoop);
0368 getInnerLoopsInPreorder(*CurLoop, PreOrderLoops);
0369 return PreOrderLoops;
0370 }
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381 void addBasicBlockToLoop(BlockT *NewBB, LoopInfoBase<BlockT, LoopT> &LI);
0382
0383
0384
0385
0386
0387 void replaceChildLoopWith(LoopT *OldChild, LoopT *NewChild);
0388
0389
0390
0391 void addChildLoop(LoopT *NewChild) {
0392 assert(!isInvalid() && "Loop not in a valid state!");
0393 assert(!NewChild->ParentLoop && "NewChild already has a parent!");
0394 NewChild->ParentLoop = static_cast<LoopT *>(this);
0395 SubLoops.push_back(NewChild);
0396 }
0397
0398
0399
0400 LoopT *removeChildLoop(iterator I) {
0401 assert(!isInvalid() && "Loop not in a valid state!");
0402 assert(I != SubLoops.end() && "Cannot remove end iterator!");
0403 LoopT *Child = *I;
0404 assert(Child->ParentLoop == this && "Child is not a child of this loop!");
0405 SubLoops.erase(SubLoops.begin() + (I - begin()));
0406 Child->ParentLoop = nullptr;
0407 return Child;
0408 }
0409
0410
0411
0412 LoopT *removeChildLoop(LoopT *Child) {
0413 return removeChildLoop(llvm::find(*this, Child));
0414 }
0415
0416
0417
0418
0419 void addBlockEntry(BlockT *BB) {
0420 assert(!isInvalid() && "Loop not in a valid state!");
0421 Blocks.push_back(BB);
0422 DenseBlockSet.insert(BB);
0423 }
0424
0425
0426 void reverseBlock(unsigned from) {
0427 assert(!isInvalid() && "Loop not in a valid state!");
0428 std::reverse(Blocks.begin() + from, Blocks.end());
0429 }
0430
0431
0432 void reserveBlocks(unsigned size) {
0433 assert(!isInvalid() && "Loop not in a valid state!");
0434 Blocks.reserve(size);
0435 }
0436
0437
0438
0439 void moveToHeader(BlockT *BB) {
0440 assert(!isInvalid() && "Loop not in a valid state!");
0441 if (Blocks[0] == BB)
0442 return;
0443 for (unsigned i = 0;; ++i) {
0444 assert(i != Blocks.size() && "Loop does not contain BB!");
0445 if (Blocks[i] == BB) {
0446 Blocks[i] = Blocks[0];
0447 Blocks[0] = BB;
0448 return;
0449 }
0450 }
0451 }
0452
0453
0454
0455
0456 void removeBlockFromLoop(BlockT *BB) {
0457 assert(!isInvalid() && "Loop not in a valid state!");
0458 auto I = find(Blocks, BB);
0459 assert(I != Blocks.end() && "N is not in this list!");
0460 Blocks.erase(I);
0461
0462 DenseBlockSet.erase(BB);
0463 }
0464
0465
0466 void verifyLoop() const;
0467
0468
0469 void verifyLoopNest(DenseSet<const LoopT *> *Loops) const;
0470
0471
0472
0473
0474
0475 bool isAnnotatedParallel() const { return false; }
0476
0477
0478 void print(raw_ostream &OS, bool Verbose = false, bool PrintNested = true,
0479 unsigned Depth = 0) const;
0480
0481 protected:
0482 friend class LoopInfoBase<BlockT, LoopT>;
0483
0484
0485 LoopBase() : ParentLoop(nullptr) {}
0486
0487 explicit LoopBase(BlockT *BB) : ParentLoop(nullptr) {
0488 Blocks.push_back(BB);
0489 DenseBlockSet.insert(BB);
0490 }
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501 ~LoopBase() {
0502 for (auto *SubLoop : SubLoops)
0503 SubLoop->~LoopT();
0504
0505 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
0506 IsInvalid = true;
0507 #endif
0508 SubLoops.clear();
0509 Blocks.clear();
0510 DenseBlockSet.clear();
0511 ParentLoop = nullptr;
0512 }
0513 };
0514
0515 template <class BlockT, class LoopT>
0516 raw_ostream &operator<<(raw_ostream &OS, const LoopBase<BlockT, LoopT> &Loop) {
0517 Loop.print(OS);
0518 return OS;
0519 }
0520
0521
0522
0523
0524
0525
0526 template <class BlockT, class LoopT> class LoopInfoBase {
0527
0528 DenseMap<const BlockT *, LoopT *> BBMap;
0529 std::vector<LoopT *> TopLevelLoops;
0530 BumpPtrAllocator LoopAllocator;
0531
0532 friend class LoopBase<BlockT, LoopT>;
0533 friend class LoopInfo;
0534
0535 void operator=(const LoopInfoBase &) = delete;
0536 LoopInfoBase(const LoopInfoBase &) = delete;
0537
0538 public:
0539 LoopInfoBase() = default;
0540 ~LoopInfoBase() { releaseMemory(); }
0541
0542 LoopInfoBase(LoopInfoBase &&Arg)
0543 : BBMap(std::move(Arg.BBMap)),
0544 TopLevelLoops(std::move(Arg.TopLevelLoops)),
0545 LoopAllocator(std::move(Arg.LoopAllocator)) {
0546
0547 Arg.TopLevelLoops.clear();
0548 }
0549 LoopInfoBase &operator=(LoopInfoBase &&RHS) {
0550 BBMap = std::move(RHS.BBMap);
0551
0552 for (auto *L : TopLevelLoops)
0553 L->~LoopT();
0554
0555 TopLevelLoops = std::move(RHS.TopLevelLoops);
0556 LoopAllocator = std::move(RHS.LoopAllocator);
0557 RHS.TopLevelLoops.clear();
0558 return *this;
0559 }
0560
0561 void releaseMemory() {
0562 BBMap.clear();
0563
0564 for (auto *L : TopLevelLoops)
0565 L->~LoopT();
0566 TopLevelLoops.clear();
0567 LoopAllocator.Reset();
0568 }
0569
0570 template <typename... ArgsTy> LoopT *AllocateLoop(ArgsTy &&...Args) {
0571 LoopT *Storage = LoopAllocator.Allocate<LoopT>();
0572 return new (Storage) LoopT(std::forward<ArgsTy>(Args)...);
0573 }
0574
0575
0576
0577
0578 typedef typename std::vector<LoopT *>::const_iterator iterator;
0579 typedef
0580 typename std::vector<LoopT *>::const_reverse_iterator reverse_iterator;
0581 iterator begin() const { return TopLevelLoops.begin(); }
0582 iterator end() const { return TopLevelLoops.end(); }
0583 reverse_iterator rbegin() const { return TopLevelLoops.rbegin(); }
0584 reverse_iterator rend() const { return TopLevelLoops.rend(); }
0585 bool empty() const { return TopLevelLoops.empty(); }
0586
0587
0588
0589
0590
0591
0592 SmallVector<LoopT *, 4> getLoopsInPreorder() const;
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602 SmallVector<LoopT *, 4> getLoopsInReverseSiblingPreorder() const;
0603
0604
0605
0606 LoopT *getLoopFor(const BlockT *BB) const { return BBMap.lookup(BB); }
0607
0608
0609 const LoopT *operator[](const BlockT *BB) const { return getLoopFor(BB); }
0610
0611
0612
0613 unsigned getLoopDepth(const BlockT *BB) const {
0614 const LoopT *L = getLoopFor(BB);
0615 return L ? L->getLoopDepth() : 0;
0616 }
0617
0618
0619 bool isLoopHeader(const BlockT *BB) const {
0620 const LoopT *L = getLoopFor(BB);
0621 return L && L->getHeader() == BB;
0622 }
0623
0624
0625 const std::vector<LoopT *> &getTopLevelLoops() const { return TopLevelLoops; }
0626
0627
0628 std::vector<LoopT *> &getTopLevelLoopsVector() { return TopLevelLoops; }
0629
0630
0631
0632
0633 LoopT *removeLoop(iterator I) {
0634 assert(I != end() && "Cannot remove end iterator!");
0635 LoopT *L = *I;
0636 assert(L->isOutermost() && "Not a top-level loop!");
0637 TopLevelLoops.erase(TopLevelLoops.begin() + (I - begin()));
0638 return L;
0639 }
0640
0641
0642
0643
0644 void changeLoopFor(BlockT *BB, LoopT *L) {
0645 if (!L) {
0646 BBMap.erase(BB);
0647 return;
0648 }
0649 BBMap[BB] = L;
0650 }
0651
0652
0653
0654 void changeTopLevelLoop(LoopT *OldLoop, LoopT *NewLoop) {
0655 auto I = find(TopLevelLoops, OldLoop);
0656 assert(I != TopLevelLoops.end() && "Old loop not at top level!");
0657 *I = NewLoop;
0658 assert(!NewLoop->ParentLoop && !OldLoop->ParentLoop &&
0659 "Loops already embedded into a subloop!");
0660 }
0661
0662
0663 void addTopLevelLoop(LoopT *New) {
0664 assert(New->isOutermost() && "Loop already in subloop!");
0665 TopLevelLoops.push_back(New);
0666 }
0667
0668
0669
0670
0671 void removeBlock(BlockT *BB) {
0672 auto I = BBMap.find(BB);
0673 if (I != BBMap.end()) {
0674 for (LoopT *L = I->second; L; L = L->getParentLoop())
0675 L->removeBlockFromLoop(BB);
0676
0677 BBMap.erase(I);
0678 }
0679 }
0680
0681
0682
0683 static bool isNotAlreadyContainedIn(const LoopT *SubLoop,
0684 const LoopT *ParentLoop) {
0685 if (!SubLoop)
0686 return true;
0687 if (SubLoop == ParentLoop)
0688 return false;
0689 return isNotAlreadyContainedIn(SubLoop->getParentLoop(), ParentLoop);
0690 }
0691
0692
0693 void analyze(const DominatorTreeBase<BlockT, false> &DomTree);
0694
0695
0696 void print(raw_ostream &OS) const;
0697
0698 void verify(const DominatorTreeBase<BlockT, false> &DomTree) const;
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710 void destroy(LoopT *L) {
0711 L->~LoopT();
0712
0713
0714
0715 LoopAllocator.Deallocate(L);
0716 }
0717 };
0718
0719 }
0720
0721 #endif