Index: lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp +++ lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp @@ -228,7 +228,7 @@ MachineFunction &MF); void makeSingleEntryLoop(BlockSet &Entries, BlockSet &Blocks, - MachineFunction &MF); + MachineFunction &MF, const ReachabilityGraph &Graph); public: static char ID; // Pass identification, replacement for typeid @@ -277,7 +277,7 @@ } if (MutualLoopEntries.size() > 1) { - makeSingleEntryLoop(MutualLoopEntries, Blocks, MF); + makeSingleEntryLoop(MutualLoopEntries, Blocks, MF, Graph); FoundIrreducibility = true; Changed = true; break; @@ -313,9 +313,12 @@ // Given a set of entries to a single loop, create a single entry for that // loop by creating a dispatch block for them, routing control flow using // a helper variable. Also updates Blocks with any new blocks created, so -// that we properly track all the blocks in the region. +// that we properly track all the blocks in the region. But this does not update +// ReachabilityGraph; this will be updated in the caller of this function as +// needed. void WebAssemblyFixIrreducibleControlFlow::makeSingleEntryLoop( - BlockSet &Entries, BlockSet &Blocks, MachineFunction &MF) { + BlockSet &Entries, BlockSet &Blocks, MachineFunction &MF, + const ReachabilityGraph &Graph) { assert(Entries.size() >= 2); // Sort the entries to ensure a deterministic build. @@ -383,36 +386,72 @@ } } - for (MachineBasicBlock *Pred : AllPreds) { - DenseMap Map; + // This set stores predecessors within this loop. + DenseSet InLoop; + for (auto *Pred : AllPreds) { for (auto *Entry : Pred->successors()) { - if (!Entries.count(Entry)) { + if (!Entries.count(Entry)) continue; + if (Graph.canReach(Entry, Pred)) { + InLoop.insert(Pred); + break; } + } + } + + // We need to create at most two routing blocks per entry: one for + // predecessors outside the loop and one for predecessors inside the loop. + // This map stores + // <, routing block> + std::map, MachineBasicBlock *> Map; + for (auto *Pred : AllPreds) { + for (auto *Entry : Pred->successors()) { + if (!Entries.count(Entry) || + Map.count(std::make_pair(InLoop.count(Pred), Entry))) + continue; // This is a successor we need to rewrite. - MachineBasicBlock *Split = MF.CreateMachineBasicBlock(); + MachineBasicBlock *Routing = MF.CreateMachineBasicBlock(); MF.insert(Pred->isLayoutSuccessor(Entry) ? MachineFunction::iterator(Entry) : MF.end(), - Split); - Blocks.insert(Split); + Routing); + Blocks.insert(Routing); // Set the jump table's register of the index of the block we wish to // jump to, and jump to the jump table. - BuildMI(Split, DebugLoc(), TII.get(WebAssembly::CONST_I32), Reg) + BuildMI(Routing, DebugLoc(), TII.get(WebAssembly::CONST_I32), Reg) .addImm(Indices[Entry]); - BuildMI(Split, DebugLoc(), TII.get(WebAssembly::BR)).addMBB(Dispatch); - Split->addSuccessor(Dispatch); - Map[Entry] = Split; + BuildMI(Routing, DebugLoc(), TII.get(WebAssembly::BR)).addMBB(Dispatch); + Routing->addSuccessor(Dispatch); + Map[std::make_pair(InLoop.count(Pred), Entry)] = Routing; } + } + + for (auto *Pred : AllPreds) { // Remap the terminator operands and the successor list. for (MachineInstr &Term : Pred->terminators()) for (auto &Op : Term.explicit_uses()) if (Op.isMBB() && Indices.count(Op.getMBB())) - Op.setMBB(Map[Op.getMBB()]); - for (auto Rewrite : Map) - Pred->replaceSuccessor(Rewrite.first, Rewrite.second); + Op.setMBB(Map[std::make_pair(InLoop.count(Pred), Op.getMBB())]); + + for (auto *Succ : Pred->successors()) { + if (!Entries.count(Succ)) + continue; + auto *Routing = Map[std::make_pair(InLoop.count(Pred), Succ)]; + Pred->replaceSuccessor(Succ, Routing); + + // In case the predecessor fell through to the successor in the original + // CFG and and the new routing block is not the predecessor's layout + // successor, we need to add a branch to the new routing block. + MachineBasicBlock *TBB = nullptr, *FBB = nullptr; + SmallVector Cond; + bool Analyzable = !TII.analyzeBranch(*Pred, TBB, FBB, Cond); + if (Analyzable && + ((Cond.empty() && !TBB && !FBB) || + (!Cond.empty() && !FBB && Pred->isLayoutSuccessor(Succ)))) + BuildMI(Pred, DebugLoc(), TII.get(WebAssembly::BR)).addMBB(Routing); + } } // Create a fake default label, because br_table requires one. Index: test/CodeGen/WebAssembly/irreducible-cfg.ll =================================================================== --- test/CodeGen/WebAssembly/irreducible-cfg.ll +++ test/CodeGen/WebAssembly/irreducible-cfg.ll @@ -93,12 +93,18 @@ ret void } -; A simple loop 2 blocks that are both entries. +; A simple loop 2 blocks that are both entries: A1 and A2. +; Even though A1 and A2 both have 3 predecessors (A0, A1, and A2), not 6 but +; only 4 new routing blocks to the dispatch block should be generated. ; CHECK-LABEL: test2: ; CHECK: br_if ; CHECK: i32.const $[[REG:[^,]+]]= +; CHECK: i32.const $[[REG]]= ; CHECK: br_table $[[REG]], +; CHECK: i32.const $[[REG]]= +; CHECK: i32.const $[[REG]]= +; CHECK-NOT: i32.const $[[REG]]= define i32 @test2(i32) { entry: br label %A0