[llvm] [WebAssembly] Incorporate SCCs into WebAssemblyFixIrreducibleControlFlow (PR #181755)

Derek Schuff via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 20 11:47:28 PST 2026


================
@@ -98,137 +107,142 @@ class ReachabilityGraph {
     calculate();
   }
 
-  bool canReach(MachineBasicBlock *From, MachineBasicBlock *To) const {
-    assert(inRegion(From) && inRegion(To));
-    auto I = Reachable.find(From);
-    if (I == Reachable.end())
-      return false;
-    return I->second.count(To);
-  }
-
-  // "Loopers" are blocks that are in a loop. We detect these by finding blocks
-  // that can reach themselves.
-  const BlockSet &getLoopers() const { return Loopers; }
-
   // Get all blocks that are loop entries.
   const BlockSet &getLoopEntries() const { return LoopEntries; }
+  const BlockSet &getLoopEntriesForSCC(unsigned SCCId) const {
+    return LoopEntriesBySCC[SCCId];
+  }
 
-  // Get all blocks that enter a particular loop from outside.
-  const BlockSet &getLoopEnterers(MachineBasicBlock *LoopEntry) const {
-    assert(inRegion(LoopEntry));
-    auto I = LoopEnterers.find(LoopEntry);
-    assert(I != LoopEnterers.end());
-    return I->second;
+  unsigned getSCCId(MachineBasicBlock *MBB) const {
+    return getNode(MBB)->SCCId;
   }
 
+  friend struct GraphTraits<ReachabilityGraph *>;
+
 private:
   MachineBasicBlock *Entry;
   const BlockSet &Blocks;
 
-  BlockSet Loopers, LoopEntries;
-  DenseMap<MachineBasicBlock *, BlockSet> LoopEnterers;
+  BlockSet LoopEntries;
+  SmallVector<BlockSet, 0> LoopEntriesBySCC;
 
   bool inRegion(MachineBasicBlock *MBB) const { return Blocks.count(MBB); }
 
-  // Maps a block to all the other blocks it can reach.
-  DenseMap<MachineBasicBlock *, BlockSet> Reachable;
+  SmallVector<ReachabilityNode, 0> Nodes;
+  DenseMap<MachineBasicBlock *, ReachabilityNode *> MBBToNodeMap;
 
-  void calculate() {
-    // Reachability computation work list. Contains pairs of recent additions
-    // (A, B) where we just added a link A => B.
-    using BlockPair = std::pair<MachineBasicBlock *, MachineBasicBlock *>;
-    SmallVector<BlockPair, 4> WorkList;
+  ReachabilityNode *getNode(MachineBasicBlock *MBB) const {
+    return MBBToNodeMap.at(MBB);
+  }
 
-    // Add all relevant direct branches.
-    for (auto *MBB : Blocks) {
-      for (auto *Succ : MBB->successors()) {
-        if (Succ != Entry && inRegion(Succ)) {
-          Reachable[MBB].insert(Succ);
-          WorkList.emplace_back(MBB, Succ);
-        }
-      }
-    }
+  void calculate();
+};
+} // end anonymous namespace
 
-    while (!WorkList.empty()) {
-      MachineBasicBlock *MBB, *Succ;
-      std::tie(MBB, Succ) = WorkList.pop_back_val();
-      assert(inRegion(MBB) && Succ != Entry && inRegion(Succ));
-      if (MBB != Entry) {
-        // We recently added MBB => Succ, and that means we may have enabled
-        // Pred => MBB => Succ.
-        for (auto *Pred : MBB->predecessors()) {
-          if (Reachable[Pred].insert(Succ).second) {
-            WorkList.emplace_back(Pred, Succ);
-          }
-        }
-      }
-    }
+namespace llvm {
+template <> struct GraphTraits<ReachabilityGraph *> {
+  typedef ReachabilityNode NodeType;
+  typedef NodeType *NodeRef;
+  typedef SmallVectorImpl<NodeRef>::iterator ChildIteratorType;
 
-    // Blocks that can return to themselves are in a loop.
-    for (auto *MBB : Blocks) {
-      if (canReach(MBB, MBB)) {
-        Loopers.insert(MBB);
-      }
-    }
-    assert(!Loopers.count(Entry));
-
-    // Find the loop entries - loopers reachable from blocks not in that loop -
-    // and those outside blocks that reach them, the "loop enterers".
-    for (auto *Looper : Loopers) {
-      for (auto *Pred : Looper->predecessors()) {
-        // Pred can reach Looper. If Looper can reach Pred, it is in the loop;
-        // otherwise, it is a block that enters into the loop.
-        if (!canReach(Looper, Pred)) {
-          LoopEntries.insert(Looper);
-          LoopEnterers[Looper].insert(Pred);
-        }
-      }
-    }
+  static NodeRef getEntryNode(ReachabilityGraph *G) {
+    return G->getNode(G->Entry);
+  }
+
+  static inline ChildIteratorType child_begin(NodeRef N) {
+    return N->Succs.begin();
+  }
+
+  static inline ChildIteratorType child_end(NodeRef N) {
+    return N->Succs.end();
   }
 };
+} // end namespace llvm
 
-// Finds the blocks in a single-entry loop, given the loop entry and the
-// list of blocks that enter the loop.
-class LoopBlocks {
-public:
-  LoopBlocks(MachineBasicBlock *Entry, const BlockSet &Enterers)
-      : Entry(Entry), Enterers(Enterers) {
-    calculate();
+namespace {
+
+void ReachabilityGraph::calculate() {
+  auto NumBlocks = Blocks.size();
+  Nodes.assign(NumBlocks, {});
+
+  MBBToNodeMap.clear();
+  MBBToNodeMap.reserve(NumBlocks);
+
+  // Initialize mappings.
+  unsigned MBBIdx = 0;
+  for (auto *MBB : Blocks) {
+    auto &Node = Nodes[MBBIdx++];
+
+    Node.MBB = MBB;
+    MBBToNodeMap[MBB] = &Node;
   }
 
-  BlockSet &getBlocks() { return Blocks; }
+  // Add all relevant direct branches.
+  MBBIdx = 0;
+  for (auto *MBB : Blocks) {
+    auto &Node = Nodes[MBBIdx++];
 
-private:
-  MachineBasicBlock *Entry;
-  const BlockSet &Enterers;
+    for (auto *Succ : MBB->successors()) {
+      if (Succ != Entry && inRegion(Succ)) {
+        Node.Succs.push_back(getNode(Succ));
+      }
+    }
+  }
 
-  BlockSet Blocks;
+  unsigned CurrSCCIdx = 0;
+  for (auto &SCC : make_range(scc_begin(this), scc_end(this))) {
+    LoopEntriesBySCC.push_back({});
+    auto &SCCLoopEntries = LoopEntriesBySCC[CurrSCCIdx];
----------------
dschuff wrote:

nit: I think this would be clearer as `LoopEntriesBySCC.back()`

https://github.com/llvm/llvm-project/pull/181755


More information about the llvm-commits mailing list