[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