[llvm] [CycleInfo] Move representation-dependent queries to GenericCycleInfo. NFC (PR #209665)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 14 19:50:12 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Fangrui Song (MaskRay)
<details>
<summary>Changes</summary>
With the Euler tour representation (#<!-- -->208614), blocks live in
GenericCycleInfo::BlockLayout and GenericCycle keeps a `CI` back-pointer just
so the out-of-line contains(BlockT *) and blocks() can reach it.
Adopt the design suggested by @<!-- -->aengelke, move the
representation-dependent queries to GenericCycleInfo, taking the cycle
as an argument (contains, getBlocks, getExitBlocks, getExitingBlocks,
getCyclePreheader, getCyclePredecessor, verifyCycle, verifyCycleNest,
and per-cycle print), and delete GenericCycle::CI.
- GenericCycleInfo's move operations become defaulted, dropping the
CI re-pointing walk, and sizeof(GenericCycle) shrinks by a pointer.
- isCycleInvariant gains a MachineCycleInfo parameter, and
GenericUniformityInfo gains getCycleInfo() for callers that only hold the
uniformity result.
Aided by Claude Fable 5
---
Patch is 48.36 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/209665.diff
15 Files Affected:
- (modified) llvm/include/llvm/ADT/GenericCycleImpl.h (+71-117)
- (modified) llvm/include/llvm/ADT/GenericCycleInfo.h (+73-85)
- (modified) llvm/include/llvm/ADT/GenericUniformityImpl.h (+46-35)
- (modified) llvm/include/llvm/ADT/GenericUniformityInfo.h (+3)
- (modified) llvm/include/llvm/CodeGen/MachineCycleAnalysis.h (+4-3)
- (modified) llvm/include/llvm/IR/GenericConvergenceVerifierImpl.h (+2-2)
- (modified) llvm/lib/Analysis/CFG.cpp (+1-1)
- (modified) llvm/lib/Analysis/UniformityAnalysis.cpp (+2-2)
- (modified) llvm/lib/CodeGen/MachineCycleAnalysis.cpp (+4-3)
- (modified) llvm/lib/CodeGen/MachineSink.cpp (+4-4)
- (modified) llvm/lib/CodeGen/MachineUniformityAnalysis.cpp (+2-2)
- (modified) llvm/lib/Target/AMDGPU/AMDGPUGlobalISelDivergenceLowering.cpp (+2-1)
- (modified) llvm/lib/Target/AMDGPU/SIInstrInfo.cpp (+1-1)
- (modified) llvm/lib/Transforms/IPO/AttributorAttributes.cpp (+1-1)
- (modified) llvm/lib/Transforms/Utils/FixIrreducible.cpp (+11-11)
``````````diff
diff --git a/llvm/include/llvm/ADT/GenericCycleImpl.h b/llvm/include/llvm/ADT/GenericCycleImpl.h
index dfeb479d764e5..02e6770f0aedd 100644
--- a/llvm/include/llvm/ADT/GenericCycleImpl.h
+++ b/llvm/include/llvm/ADT/GenericCycleImpl.h
@@ -34,60 +34,39 @@
namespace llvm {
template <typename ContextT>
-bool GenericCycle<ContextT>::contains(const GenericCycle *C) const {
- // Containment check using the Euler tour representation.
- return C && IdxBegin <= C->IdxBegin && C->IdxEnd <= IdxEnd;
-}
-
-template <typename ContextT>
-bool GenericCycle<ContextT>::contains(const BlockT *Block) const {
- return contains(CI->getCycle(Block));
-}
-
-template <typename ContextT>
-auto GenericCycle<ContextT>::block_begin() const -> const_block_iterator {
- return CI->BlockLayout.begin() + IdxBegin;
-}
-
-template <typename ContextT>
-auto GenericCycle<ContextT>::block_end() const -> const_block_iterator {
- return CI->BlockLayout.begin() + IdxEnd;
-}
-
-template <typename ContextT>
-void GenericCycle<ContextT>::getExitBlocks(
- SmallVectorImpl<BlockT *> &TmpStorage) const {
- if (!ExitBlocksCache.empty()) {
- TmpStorage.append(ExitBlocksCache.begin(), ExitBlocksCache.end());
+void GenericCycleInfo<ContextT>::getExitBlocks(
+ const CycleT &C, SmallVectorImpl<BlockT *> &TmpStorage) const {
+ if (!C.ExitBlocksCache.empty()) {
+ TmpStorage.append(C.ExitBlocksCache.begin(), C.ExitBlocksCache.end());
return;
}
size_t NumExitBlocks = 0;
- for (BlockT *Block : blocks()) {
- llvm::append_range(ExitBlocksCache, successors(Block));
+ for (BlockT *Block : getBlocks(C)) {
+ llvm::append_range(C.ExitBlocksCache, successors(Block));
- for (size_t Idx = NumExitBlocks, End = ExitBlocksCache.size(); Idx < End;
+ for (size_t Idx = NumExitBlocks, End = C.ExitBlocksCache.size(); Idx < End;
++Idx) {
- BlockT *Succ = ExitBlocksCache[Idx];
- if (!contains(Succ)) {
- auto ExitEndIt = ExitBlocksCache.begin() + NumExitBlocks;
- if (std::find(ExitBlocksCache.begin(), ExitEndIt, Succ) == ExitEndIt)
- ExitBlocksCache[NumExitBlocks++] = Succ;
+ BlockT *Succ = C.ExitBlocksCache[Idx];
+ if (!contains(&C, Succ)) {
+ auto ExitEndIt = C.ExitBlocksCache.begin() + NumExitBlocks;
+ if (std::find(C.ExitBlocksCache.begin(), ExitEndIt, Succ) == ExitEndIt)
+ C.ExitBlocksCache[NumExitBlocks++] = Succ;
}
}
- ExitBlocksCache.resize(NumExitBlocks);
+ C.ExitBlocksCache.resize(NumExitBlocks);
}
- TmpStorage.append(ExitBlocksCache.begin(), ExitBlocksCache.end());
+ TmpStorage.append(C.ExitBlocksCache.begin(), C.ExitBlocksCache.end());
}
template <typename ContextT>
-void GenericCycle<ContextT>::getExitingBlocks(
- SmallVectorImpl<BlockT *> &TmpStorage) const {
- for (BlockT *Block : blocks()) {
+void GenericCycleInfo<ContextT>::getExitingBlocks(
+ const CycleT &C, SmallVectorImpl<BlockT *> &TmpStorage) const {
+ for (BlockT *Block : getBlocks(C)) {
for (BlockT *Succ : successors(Block)) {
- if (!contains(Succ)) {
+ if (!contains(&C, Succ)) {
TmpStorage.push_back(Block);
break;
}
@@ -96,12 +75,13 @@ void GenericCycle<ContextT>::getExitingBlocks(
}
template <typename ContextT>
-auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * {
- BlockT *Predecessor = getCyclePredecessor();
+auto GenericCycleInfo<ContextT>::getCyclePreheader(const CycleT &C) const
+ -> BlockT * {
+ BlockT *Predecessor = getCyclePredecessor(C);
if (!Predecessor)
return nullptr;
- assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!");
+ assert(C.isReducible() && "Cycle Predecessor must be in a reducible cycle!");
if (succ_size(Predecessor) != 1)
return nullptr;
@@ -114,16 +94,17 @@ auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * {
}
template <typename ContextT>
-auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * {
- if (!isReducible())
+auto GenericCycleInfo<ContextT>::getCyclePredecessor(const CycleT &C) const
+ -> BlockT * {
+ if (!C.isReducible())
return nullptr;
BlockT *Out = nullptr;
// Loop over the predecessors of the header node...
- BlockT *Header = getHeader();
+ BlockT *Header = C.getHeader();
for (const auto Pred : predecessors(Header)) {
- if (!contains(Pred)) {
+ if (!contains(&C, Pred)) {
if (Out && Out != Pred)
return nullptr;
Out = Pred;
@@ -133,25 +114,25 @@ auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * {
return Out;
}
-/// \brief Verify that this is actually a well-formed cycle in the CFG.
-template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
+template <typename ContextT>
+void GenericCycleInfo<ContextT>::verifyCycle(const CycleT &C) const {
#ifndef NDEBUG
- assert(getNumBlocks() != 0 && "Cycle cannot be empty.");
+ assert(C.getNumBlocks() != 0 && "Cycle cannot be empty.");
DenseSet<BlockT *> Blocks;
- for (BlockT *BB : blocks()) {
+ for (BlockT *BB : getBlocks(C)) {
assert(Blocks.insert(BB).second); // duplicates in block list?
}
- assert(!Entries.empty() && "Cycle must have one or more entries.");
+ assert(!C.Entries.empty() && "Cycle must have one or more entries.");
DenseSet<BlockT *> Entries;
- for (BlockT *Entry : entries()) {
+ for (BlockT *Entry : C.entries()) {
assert(Entries.insert(Entry).second); // duplicate entry?
- assert(contains(Entry));
+ assert(contains(&C, Entry));
}
// Setup for using a depth-first iterator to visit every block in the cycle.
SmallVector<BlockT *, 8> ExitBBs;
- getExitBlocks(ExitBBs);
+ getExitBlocks(C, ExitBBs);
df_iterator_default_set<BlockT *> VisitSet;
VisitSet.insert(ExitBBs.begin(), ExitBBs.end());
@@ -159,18 +140,18 @@ template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
SmallPtrSet<BlockT *, 8> VisitedBBs;
// Check the individual blocks.
- for (BlockT *BB : depth_first_ext(getHeader(), VisitSet)) {
+ for (BlockT *BB : depth_first_ext(C.getHeader(), VisitSet)) {
assert(llvm::any_of(llvm::children<BlockT *>(BB),
- [&](BlockT *B) { return contains(B); }) &&
+ [&](BlockT *B) { return contains(&C, B); }) &&
"Cycle block has no in-cycle successors!");
assert(llvm::any_of(llvm::inverse_children<BlockT *>(BB),
- [&](BlockT *B) { return contains(B); }) &&
+ [&](BlockT *B) { return contains(&C, B); }) &&
"Cycle block has no in-cycle predecessors!");
DenseSet<BlockT *> OutsideCyclePreds;
for (BlockT *B : llvm::inverse_children<BlockT *>(BB))
- if (!contains(B))
+ if (!contains(&C, B))
OutsideCyclePreds.insert(B);
if (Entries.contains(BB)) {
@@ -184,13 +165,13 @@ template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
assert(!OutsideCyclePreds.contains(CB) &&
"Non-entry block reachable from outside!");
}
- assert(BB != &getHeader()->getParent()->front() &&
+ assert(BB != &C.getHeader()->getParent()->front() &&
"Cycle contains function entry block!");
VisitedBBs.insert(BB);
}
- if (VisitedBBs.size() != getNumBlocks()) {
+ if (VisitedBBs.size() != C.getNumBlocks()) {
dbgs() << "The following blocks are unreachable in the cycle:\n ";
ListSeparator LS;
for (auto *BB : Blocks) {
@@ -203,34 +184,31 @@ template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
llvm_unreachable("Unreachable block in cycle");
}
- verifyCycleNest();
+ verifyCycleNest(C);
#endif
}
-/// \brief Verify the parent-child relations of this cycle.
-///
-/// Note that this does \em not check that cycle is really a cycle in the CFG.
template <typename ContextT>
-void GenericCycle<ContextT>::verifyCycleNest() const {
+void GenericCycleInfo<ContextT>::verifyCycleNest(const CycleT &C) const {
#ifndef NDEBUG
// Check the subcycles.
- for (GenericCycle *Child : children()) {
+ for (CycleT *Child : C.children()) {
// Each block in each subcycle should be contained within this cycle.
- for (BlockT *BB : Child->blocks()) {
- assert(contains(BB) &&
+ for (BlockT *BB : getBlocks(*Child)) {
+ assert(contains(&C, BB) &&
"Cycle does not contain all the blocks of a subcycle!");
}
- assert(Child->Depth == Depth + 1);
+ assert(Child->Depth == C.Depth + 1);
}
// Check the parent cycle pointer.
- if (ParentCycle) {
- assert(is_contained(ParentCycle->children(), this) &&
+ if (C.ParentCycle) {
+ assert(is_contained(C.ParentCycle->children(), &C) &&
"Cycle is not a subcycle of its parent!");
- assert(ParentCycle->TopLevelCycle == TopLevelCycle &&
+ assert(C.ParentCycle->TopLevelCycle == C.TopLevelCycle &&
"Top level cycle of parent cycle must be the same");
} else {
- assert(TopLevelCycle == this &&
+ assert(C.TopLevelCycle == &C &&
"Cycle without parent must be top-level cycle");
}
#endif
@@ -289,13 +267,6 @@ template <typename ContextT> class GenericCycleInfoCompute {
void dfs(FunctionT *F, BlockT *EntryBlock);
};
-template <typename ContextT>
-auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(
- const BlockT *Block) const -> CycleT * {
- CycleT *Cycle = getCycle(Block);
- return Cycle ? Cycle->TopLevelCycle : nullptr;
-}
-
template <typename ContextT>
void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
CycleT *Child) {
@@ -320,14 +291,6 @@ void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
// range-dependent query is used.
}
-template <typename ContextT>
-void GenericCycleInfo<ContextT>::verifyBlockNumberEpoch(
- const FunctionT *Fn) const {
- assert(BlockNumberEpoch ==
- GraphTraits<const FunctionT *>::getNumberEpoch(Fn) &&
- "CycleInfo used with outdated block number epoch");
-}
-
template <typename ContextT>
void GenericCycleInfo<ContextT>::addToBlockMap(BlockT *Block, CycleT *Cycle) {
// The caller should ensure that BlockMap is large enough.
@@ -438,7 +401,6 @@ void GenericCycleInfoCompute<ContextT>::run(FunctionT *F) {
LLVM_DEBUG(errs() << "Found cycle for header: "
<< Info.Context.print(HeaderCandidate) << "\n");
std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
- NewCycle->CI = &Info;
NewCycle->appendEntry(HeaderCandidate);
Info.addToBlockMap(HeaderCandidate, NewCycle.get());
// The header is this cycle's first own block. Until layoutBlocks runs,
@@ -624,18 +586,6 @@ void GenericCycleInfo<ContextT>::splitCriticalEdge(BlockT *Pred, BlockT *Succ,
verifyCycleNest();
}
-/// \brief Find the innermost cycle containing a given block.
-///
-/// \returns the innermost cycle containing \p Block or nullptr if
-/// it is not contained in any cycle.
-template <typename ContextT>
-auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const
- -> CycleT * {
- verifyBlockNumberEpoch(Block->getParent());
- unsigned Number = GraphTraits<const BlockT *>::getNumber(Block);
- return Number < BlockMap.size() ? BlockMap[Number] : nullptr;
-}
-
/// \brief Find the innermost cycle containing both given cycles.
///
/// \returns the innermost cycle containing both \p A and \p B
@@ -676,18 +626,6 @@ auto GenericCycleInfo<ContextT>::getSmallestCommonCycle(BlockT *A,
return getSmallestCommonCycle(getCycle(A), getCycle(B));
}
-/// \brief get the depth for the cycle which containing a given block.
-///
-/// \returns the depth for the innermost cycle containing \p Block or 0 if it is
-/// not contained in any cycle.
-template <typename ContextT>
-unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const {
- CycleT *Cycle = getCycle(Block);
- if (!Cycle)
- return 0;
- return Cycle->getDepth();
-}
-
/// \brief Verify the internal consistency of the cycle tree.
///
/// Note that this does \em not check that cycles are really cycles in the CFG,
@@ -702,11 +640,11 @@ void GenericCycleInfo<ContextT>::verifyCycleNest(bool VerifyFull) const {
BlockT *Header = Cycle->getHeader();
assert(CycleHeaders.insert(Header).second);
if (VerifyFull)
- Cycle->verifyCycle();
+ verifyCycle(*Cycle);
else
- Cycle->verifyCycleNest();
+ verifyCycleNest(*Cycle);
// Check the block map entries for blocks contained in this cycle.
- for (BlockT *BB : Cycle->blocks()) {
+ for (BlockT *BB : getBlocks(*Cycle)) {
CycleT *CycleInBlockMap = getCycle(BB);
assert(CycleInBlockMap != nullptr);
assert(Cycle->contains(CycleInBlockMap));
@@ -729,11 +667,27 @@ void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const {
for (unsigned I = 0; I < Cycle->Depth; ++I)
Out << " ";
- Out << Cycle->print(Context) << '\n';
+ Out << print(Cycle) << '\n';
}
}
}
+/// \brief Print a single cycle: its depth, entries, and remaining blocks.
+template <typename ContextT>
+Printable GenericCycleInfo<ContextT>::print(const CycleT *Cycle) const {
+ return Printable([this, Cycle](raw_ostream &Out) {
+ Out << "depth=" << Cycle->Depth << ": entries("
+ << Cycle->printEntries(Context) << ')';
+
+ for (auto *Block : getBlocks(*Cycle)) {
+ if (Cycle->isEntry(Block))
+ continue;
+
+ Out << ' ' << Context.print(Block);
+ }
+ });
+}
+
} // namespace llvm
#undef DEBUG_TYPE
diff --git a/llvm/include/llvm/ADT/GenericCycleInfo.h b/llvm/include/llvm/ADT/GenericCycleInfo.h
index c3093d4cf83e5..d3ffafc7d0d39 100644
--- a/llvm/include/llvm/ADT/GenericCycleInfo.h
+++ b/llvm/include/llvm/ADT/GenericCycleInfo.h
@@ -82,9 +82,6 @@ template <typename ContextT> class GenericCycle {
/// always have the same depth.
unsigned Depth = 0;
- /// The cycle info that owns this cycle. Used by contains(BlockT*).
- const GenericCycleInfo<ContextT> *CI = nullptr;
-
/// Cache for the results of GetExitBlocks
mutable SmallVector<BlockT *, 4> ExitBlocksCache;
@@ -130,46 +127,24 @@ template <typename ContextT> class GenericCycle {
}
/// \brief Replace all entries with \p Block as single entry.
+ /// \p Block must be contained in the cycle.
void setSingleEntry(BlockT *Block) {
- assert(contains(Block));
Entries.clear();
Entries.push_back(Block);
clearCache();
}
- /// \brief Return whether \p Block is contained in the cycle. O(1).
- bool contains(const BlockT *Block) const;
-
/// \brief Returns true iff this cycle contains \p C. O(1). Non-strict, i.e.
/// returns true if C is the same cycle.
- bool contains(const GenericCycle *C) const;
+ bool contains(const GenericCycle *C) const {
+ return C && IdxBegin <= C->IdxBegin && C->IdxEnd <= IdxEnd;
+ }
const GenericCycle *getParentCycle() const { return ParentCycle; }
GenericCycle *getParentCycle() { return ParentCycle; }
unsigned getDepth() const { return Depth; }
- /// Return all of the successor blocks of this cycle.
- ///
- /// These are the blocks _outside of the current cycle_ which are
- /// branched to.
- void getExitBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
-
- /// Return all blocks of this cycle that have successor outside of this cycle.
- /// These blocks have cycle exit branch.
- void getExitingBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
-
- /// Return the preheader block for this cycle. Pre-header is well-defined for
- /// reducible cycle in docs/LoopTerminology.md as: the only one entering
- /// block and its only edge is to the entry block. Return null for irreducible
- /// cycles.
- BlockT *getCyclePreheader() const;
-
- /// If the cycle has exactly one entry with exactly one predecessor, return
- /// it, otherwise return nullptr.
- BlockT *getCyclePredecessor() const;
-
- void verifyCycle() const;
- void verifyCycleNest() const;
+ size_t getNumBlocks() const { return IdxEnd - IdxBegin; }
/// Iteration over child cycles.
//@{
@@ -200,19 +175,6 @@ template <typename ContextT> class GenericCycle {
}
//@}
- /// Iteration over blocks in the cycle (including entry blocks).
- //@{
- using const_block_iterator =
- typename SmallVector<BlockT *, 8>::const_iterator;
-
- const_block_iterator block_begin() const;
- const_block_iterator block_end() const;
- size_t getNumBlocks() const { return IdxEnd - IdxBegin; }
- iterator_range<const_block_iterator> blocks() const {
- return llvm::make_range(block_begin(), block_end());
- }
- //@}
-
/// Iteration over entry blocks.
//@{
using const_entry_iterator =
@@ -236,19 +198,6 @@ template <typename ContextT> class GenericCycle {
Out << LS << Ctx.print(Entry);
});
}
-
- Printable print(const ContextT &Ctx) const {
- return Printable([this, &Ctx](raw_ostream &Out) {
- Out << "depth=" << Depth << ": entries(" << printEntries(Ctx) << ')';
-
- for (auto *Block : blocks()) {
- if (isEntry(Block))
- continue;
-
- Out << ' ' << Ctx.print(Block);
- }
- });
- }
};
/// \brief Cycle information for a function.
@@ -257,7 +206,6 @@ template <typename ContextT> class GenericCycleInfo {
using BlockT = typename ContextT::BlockT;
using CycleT = GenericCycle<ContextT>;
using FunctionT = typename ContextT::FunctionT;
- template <typename> friend class GenericCycle;
template <typename> friend class GenericCycleInfoCompute;
private:
@@ -283,7 +231,11 @@ template <typename ContextT> class GenericCycleInfo {
/// the subtree.
void moveTopLevelCycleToNewParent(CycleT *NewParent, CycleT *Child);
- void verifyBlockNumberEpoch(const FunctionT *Fn) const;
+ void verifyBlockNumberEpoch(const FunctionT *Fn) const {
+ assert(BlockNumberEpoch ==
+ GraphTraits<const FunctionT *>::getNumberEpoch(Fn) &&
+ "CycleInfo used with outdated block number epoch");
+ }
void addToBlockMap(BlockT *Block, CycleT *Cycle);
/// Build BlockLayout and every cycle's [IdxBegin, IdxEnd) slice
@@ -292,29 +244,8 @@ template <typename ContextT> class GenericCycleInfo {
public:
GenericCycleInfo() = default;
- GenericCycleInfo(GenericCycleInfo &&Other) { *this = std::move(Other); }
- GenericCycleInfo &operator=(GenericCycleInfo &&Other) {
- if (this == &Other)
- return *this;
- Context = std::move(Other.Context);
- BlockNumberEpoch = Other.BlockNumberEpoch;
- BlockMap = std::move(Other.BlockMap);
- BlockLayout = std::move(Other.BlockLayout);
- TopLevelCycles = std::move(Other.TopLevelCycles);
- // The moved cycles carry a back-reference to their owning info (used by
- // GenericCycle::contains(BlockT*) and blocks()); re-point it at this
- // object.
- SmallVector<CycleT *, 8> Worklist;
- for (auto &TLC : TopLevelCycles)
- Worklist.push_back(TLC.get());
- while (!Worklist.empty()) {
- CycleT *C = Worklist.pop_back_val();
- C->CI = this;
- for (auto &Child : C->Children)
- Worklist.push_back(Child.get());
- }
- return *this;
- }
+ GenericCycleInfo(GenericCycleInfo &&) = default;
+ GenericCycleInfo &operator=(GenericCycleInfo &&) = default;
void clear();
void compute(FunctionT &F);
@@ -323,11 +254,68 @@ template <typename ContextT> class GenericCycleInfo {
const FunctionT *getFunction() const { return Context.getFunction(); }
const ContextT &getSSAContext() const { return Context; }
- CycleT *getCycle(const BlockT *Block) const;
+ /// \brief Find the innermost cycle containing \p Block.
+ ///
+ /// \returns the innermost cycle containing \p Block or nullptr if
+ /// it is not contained in any cycle.
+ CycleT *getCycle(const BlockT *Block) const {
+ verifyBlockNumberEpoch(Block->getParent());
+ unsigned Number = GraphTraits<const BlockT *>::getNumber(Block);
+ return Number < BlockMap.size() ? BlockMap[Number] : nullptr;
+ }
+
+ /// \brief Return whether \p Block is contained in \p C. O(1).
+ bool contains(const CycleT *C, const BlockT *Block) const {
+ return C && C->contains(getCycle(Block));
+ }
+
+ /// \brief Return the blocks of \p C, including th...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/209665
More information about the llvm-commits
mailing list