[llvm] [CycleAnalysis] Methods to verify cycles and their nesting. (PR #102300)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 16 05:11:50 PDT 2024
================
@@ -119,6 +119,101 @@ 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 {
+#ifndef NDEBUG
+ assert(!Blocks.empty() && "Cycle cannot be empty.");
+ DenseSet<BlockT *> Blocks;
+ for (BlockT *BB : blocks()) {
+ assert(Blocks.insert(BB).second); // duplicates in block list?
+ }
+ assert(!Entries.empty() && "Cycle must have one or more entries.");
+
+ DenseSet<BlockT *> Entries;
+ for (BlockT *Entry : entries()) {
+ assert(Entries.insert(Entry).second); // duplicate entry?
+ assert(contains(Entry));
+ }
+
+ // Setup for using a depth-first iterator to visit every block in the cycle.
+ SmallVector<BlockT *, 8> ExitBBs;
+ getExitBlocks(ExitBBs);
+ df_iterator_default_set<BlockT *> VisitSet;
+ VisitSet.insert(ExitBBs.begin(), ExitBBs.end());
+
+ // Keep track of the BBs visited.
+ SmallPtrSet<BlockT *, 8> VisitedBBs;
+
+ // Check the individual blocks.
+ for (BlockT *BB : depth_first_ext(getHeader(), VisitSet)) {
+ assert(llvm::any_of(llvm::children<BlockT *>(BB),
+ [&](BlockT *B) { return contains(B); }) &&
+ "Cycle block has no in-cycle successors!");
+
+ assert(llvm::any_of(llvm::inverse_children<BlockT *>(BB),
+ [&](BlockT *B) { return contains(B); }) &&
+ "Cycle block has no in-cycle predecessors!");
+
+ DenseSet<BlockT *> OutsideCyclePreds;
+ for (BlockT *B : llvm::inverse_children<BlockT *>(BB))
+ if (!contains(B))
+ OutsideCyclePreds.insert(B);
+
+ if (Entries.contains(BB)) {
+ assert(!OutsideCyclePreds.empty() && "Entry is unreachable!");
+ } else if (!OutsideCyclePreds.empty()) {
+ // A non-entry block shouldn't be reachable from outside the cycle,
+ // though it is permitted if the predecessor is not itself actually
+ // reachable.
+ BlockT *EntryBB = &BB->getParent()->front();
+ for (BlockT *CB : depth_first(EntryBB))
+ assert(!OutsideCyclePreds.contains(CB) &&
+ "Non-entry block reachable from outside!");
+ }
+ assert(BB != &getHeader()->getParent()->front() &&
+ "Cycle contains function entry block!");
+
+ VisitedBBs.insert(BB);
+ }
+
+ if (VisitedBBs.size() != getNumBlocks()) {
+ dbgs() << "The following blocks are unreachable in the cycle: ";
+ for (auto *BB : Blocks) {
+ if (!VisitedBBs.count(BB)) {
+ dbgs() << *BB << "\n";
+ }
+ }
+ assert(false && "Unreachable block in cycle");
----------------
arsenm wrote:
It's always a stylistic choice, and llvm_unreachable is nicer
https://github.com/llvm/llvm-project/pull/102300
More information about the llvm-commits
mailing list