[llvm] [WebAssembly] Replace Reachability with SCCs in Irreducible CFG Fixer (PR #179722)

Heejin Ahn via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 14 06:35:12 PST 2026


================
@@ -120,65 +113,138 @@ class ReachabilityGraph {
     assert(I != LoopEnterers.end());
     return I->second;
   }
+  unsigned getSCCId(MachineBasicBlock *MBB) const {
+    return SccId[getIndex(MBB)];
+  }
 
 private:
   MachineBasicBlock *Entry;
   const BlockSet &Blocks;
+  DenseMap<MachineBasicBlock *, unsigned> BlockIndex;
 
   BlockSet Loopers, LoopEntries;
   DenseMap<MachineBasicBlock *, BlockSet> LoopEnterers;
 
   bool inRegion(MachineBasicBlock *MBB) const { return Blocks.count(MBB); }
 
-  // Maps a block to all the other blocks it can reach.
-  DenseMap<MachineBasicBlock *, BlockSet> Reachable;
+  // Per-node adjacency in the region (excluding edges to Entry).
+  SmallVector<SmallVector<unsigned, 4>, 0> Succs;
+  SmallVector<bool, 0> SelfLoop;
+
+  // SCC = Strongly-connected component
+  // Map of an MBB's index (provided by `BlockIndex`) to it's assigned SCC
+  SmallVector<unsigned, 0> SccId; 
+  // The number of elements in each SCC
+  SmallVector<unsigned, 0> SccSize; 
+
+  unsigned getIndex(MachineBasicBlock *MBB) const {
+    auto It = BlockIndex.find(MBB);
+    assert(It != BlockIndex.end());
+    return It->second;
+  }
 
   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;
+    auto NumBlocks = Blocks.size();
+    Succs.assign(NumBlocks, {});
+    SelfLoop.assign(NumBlocks, false);
+
+    unsigned MMBIdx = 0;
+    BlockIndex.clear();
+    BlockIndex.reserve(NumBlocks);
+    for (auto *MBB : Blocks)
+      BlockIndex[MBB] = MMBIdx++;
 
     // Add all relevant direct branches.
+    MMBIdx = 0;
     for (auto *MBB : Blocks) {
       for (auto *Succ : MBB->successors()) {
         if (Succ != Entry && inRegion(Succ)) {
-          Reachable[MBB].insert(Succ);
-          WorkList.emplace_back(MBB, Succ);
+          if (Succ == MBB)
+            SelfLoop[MMBIdx] = true;
+          Succs[MMBIdx].push_back(getIndex(Succ));
         }
       }
+
+      ++MMBIdx;
     }
 
-    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);
+    // Tarjan SCC (iterative) on the region graph.
+    SccId.assign(NumBlocks, std::numeric_limits<unsigned>::max());
+    SccSize.clear();
+    SmallVector<int, 0> Index(NumBlocks, -1);
+    SmallVector<int, 0> Lowlink(NumBlocks, 0);
+    SmallVector<unsigned, 0> Stack;
+    SmallVector<bool, 0> OnStack(NumBlocks, false);
+    int NextIndex = 0;
+
+    struct Frame {
+      unsigned V;
+      unsigned NextSucc;
+    };
+    SmallVector<Frame, 0> DFS;
+
+    auto pushNode = [&](unsigned V) {
+      Index[V] = Lowlink[V] = NextIndex++;
+      Stack.push_back(V);
+      OnStack[V] = true;
+      DFS.push_back({V, 0});
+    };
+
+    for (unsigned V = 0; V < NumBlocks; ++V) {
+      if (Index[V] != -1)
+        continue;
+      pushNode(V);
+      while (!DFS.empty()) {
+        Frame &F = DFS.back();
+        unsigned Cur = F.V;
+        if (F.NextSucc < Succs[Cur].size()) {
+          unsigned W = Succs[Cur][F.NextSucc++];
+          if (Index[W] == -1) {
+            pushNode(W);
+          } else if (OnStack[W]) {
----------------
aheejin wrote:

```suggestion
          } else if (OnStack[W]) { // Successor is on the DFS stack
```

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


More information about the llvm-commits mailing list