1950a13cfSDan Gohman //===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===// 2950a13cfSDan Gohman // 3950a13cfSDan Gohman // The LLVM Compiler Infrastructure 4950a13cfSDan Gohman // 5950a13cfSDan Gohman // This file is distributed under the University of Illinois Open Source 6950a13cfSDan Gohman // License. See LICENSE.TXT for details. 7950a13cfSDan Gohman // 8950a13cfSDan Gohman //===----------------------------------------------------------------------===// 9950a13cfSDan Gohman /// 10950a13cfSDan Gohman /// \file 11950a13cfSDan Gohman /// \brief This file implements a CFG stacking pass. 12950a13cfSDan Gohman /// 13950a13cfSDan Gohman /// This pass reorders the blocks in a function to put them into a reverse 14950a13cfSDan Gohman /// post-order [0], with special care to keep the order as similar as possible 15950a13cfSDan Gohman /// to the original order, and to keep loops contiguous even in the case of 16950a13cfSDan Gohman /// split backedges. 17950a13cfSDan Gohman /// 18950a13cfSDan Gohman /// Then, it inserts BLOCK and LOOP markers to mark the start of scopes, since 19950a13cfSDan Gohman /// scope boundaries serve as the labels for WebAssembly's control transfers. 20950a13cfSDan Gohman /// 21950a13cfSDan Gohman /// This is sufficient to convert arbitrary CFGs into a form that works on 22950a13cfSDan Gohman /// WebAssembly, provided that all loops are single-entry. 23950a13cfSDan Gohman /// 24950a13cfSDan Gohman /// [0] https://en.wikipedia.org/wiki/Depth-first_search#Vertex_orderings 25950a13cfSDan Gohman /// 26950a13cfSDan Gohman //===----------------------------------------------------------------------===// 27950a13cfSDan Gohman 28950a13cfSDan Gohman #include "WebAssembly.h" 29950a13cfSDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 30950a13cfSDan Gohman #include "WebAssemblySubtarget.h" 31950a13cfSDan Gohman #include "llvm/ADT/SCCIterator.h" 32950a13cfSDan Gohman #include "llvm/CodeGen/MachineFunction.h" 33950a13cfSDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h" 34950a13cfSDan Gohman #include "llvm/CodeGen/MachineLoopInfo.h" 35950a13cfSDan Gohman #include "llvm/CodeGen/Passes.h" 36950a13cfSDan Gohman #include "llvm/Support/Debug.h" 37950a13cfSDan Gohman #include "llvm/Support/raw_ostream.h" 38950a13cfSDan Gohman using namespace llvm; 39950a13cfSDan Gohman 40950a13cfSDan Gohman #define DEBUG_TYPE "wasm-cfg-stackify" 41950a13cfSDan Gohman 42950a13cfSDan Gohman namespace { 43950a13cfSDan Gohman class WebAssemblyCFGStackify final : public MachineFunctionPass { 44950a13cfSDan Gohman const char *getPassName() const override { 45950a13cfSDan Gohman return "WebAssembly CFG Stackify"; 46950a13cfSDan Gohman } 47950a13cfSDan Gohman 48950a13cfSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override { 49950a13cfSDan Gohman AU.setPreservesCFG(); 50950a13cfSDan Gohman AU.addRequired<MachineLoopInfo>(); 51950a13cfSDan Gohman AU.addPreserved<MachineLoopInfo>(); 52950a13cfSDan Gohman MachineFunctionPass::getAnalysisUsage(AU); 53950a13cfSDan Gohman } 54950a13cfSDan Gohman 55950a13cfSDan Gohman bool runOnMachineFunction(MachineFunction &MF) override; 56950a13cfSDan Gohman 57950a13cfSDan Gohman public: 58950a13cfSDan Gohman static char ID; // Pass identification, replacement for typeid 59950a13cfSDan Gohman WebAssemblyCFGStackify() : MachineFunctionPass(ID) {} 60950a13cfSDan Gohman }; 61950a13cfSDan Gohman } // end anonymous namespace 62950a13cfSDan Gohman 63950a13cfSDan Gohman char WebAssemblyCFGStackify::ID = 0; 64950a13cfSDan Gohman FunctionPass *llvm::createWebAssemblyCFGStackify() { 65950a13cfSDan Gohman return new WebAssemblyCFGStackify(); 66950a13cfSDan Gohman } 67950a13cfSDan Gohman 68950a13cfSDan Gohman static void EliminateMultipleEntryLoops(MachineFunction &MF, 69950a13cfSDan Gohman const MachineLoopInfo &MLI) { 70950a13cfSDan Gohman SmallPtrSet<MachineBasicBlock *, 8> InSet; 71950a13cfSDan Gohman for (scc_iterator<MachineFunction *> I = scc_begin(&MF), E = scc_end(&MF); 72950a13cfSDan Gohman I != E; ++I) { 73950a13cfSDan Gohman const std::vector<MachineBasicBlock *> &CurrentSCC = *I; 74950a13cfSDan Gohman 75950a13cfSDan Gohman // Skip trivial SCCs. 76950a13cfSDan Gohman if (CurrentSCC.size() == 1) 77950a13cfSDan Gohman continue; 78950a13cfSDan Gohman 79950a13cfSDan Gohman InSet.insert(CurrentSCC.begin(), CurrentSCC.end()); 80950a13cfSDan Gohman MachineBasicBlock *Header = nullptr; 81950a13cfSDan Gohman for (MachineBasicBlock *MBB : CurrentSCC) { 82950a13cfSDan Gohman for (MachineBasicBlock *Pred : MBB->predecessors()) { 83950a13cfSDan Gohman if (InSet.count(Pred)) 84950a13cfSDan Gohman continue; 85950a13cfSDan Gohman if (!Header) { 86950a13cfSDan Gohman Header = MBB; 87950a13cfSDan Gohman break; 88950a13cfSDan Gohman } 89950a13cfSDan Gohman // TODO: Implement multiple-entry loops. 90950a13cfSDan Gohman report_fatal_error("multiple-entry loops are not supported yet"); 91950a13cfSDan Gohman } 92950a13cfSDan Gohman } 93950a13cfSDan Gohman assert(MLI.isLoopHeader(Header)); 94950a13cfSDan Gohman 95950a13cfSDan Gohman InSet.clear(); 96950a13cfSDan Gohman } 97950a13cfSDan Gohman } 98950a13cfSDan Gohman 99950a13cfSDan Gohman namespace { 100950a13cfSDan Gohman /// Post-order traversal stack entry. 101950a13cfSDan Gohman struct POStackEntry { 102950a13cfSDan Gohman MachineBasicBlock *MBB; 103950a13cfSDan Gohman SmallVector<MachineBasicBlock *, 0> Succs; 104950a13cfSDan Gohman 105950a13cfSDan Gohman POStackEntry(MachineBasicBlock *MBB, MachineFunction &MF, 106950a13cfSDan Gohman const MachineLoopInfo &MLI); 107950a13cfSDan Gohman }; 108950a13cfSDan Gohman } // end anonymous namespace 109950a13cfSDan Gohman 110950a13cfSDan Gohman POStackEntry::POStackEntry(MachineBasicBlock *MBB, MachineFunction &MF, 111950a13cfSDan Gohman const MachineLoopInfo &MLI) 112950a13cfSDan Gohman : MBB(MBB), Succs(MBB->successors()) { 113950a13cfSDan Gohman // RPO is not a unique form, since at every basic block with multiple 114950a13cfSDan Gohman // successors, the DFS has to pick which order to visit the successors in. 115950a13cfSDan Gohman // Sort them strategically (see below). 116950a13cfSDan Gohman MachineLoop *Loop = MLI.getLoopFor(MBB); 117950a13cfSDan Gohman MachineFunction::iterator Next = next(MachineFunction::iterator(MBB)); 118950a13cfSDan Gohman MachineBasicBlock *LayoutSucc = Next == MF.end() ? nullptr : &*Next; 119950a13cfSDan Gohman std::stable_sort( 120950a13cfSDan Gohman Succs.begin(), Succs.end(), 121950a13cfSDan Gohman [=, &MLI](const MachineBasicBlock *A, const MachineBasicBlock *B) { 122950a13cfSDan Gohman if (A == B) 123950a13cfSDan Gohman return false; 124950a13cfSDan Gohman 125950a13cfSDan Gohman // Keep loops contiguous by preferring the block that's in the same 126950a13cfSDan Gohman // loop. 127950a13cfSDan Gohman MachineLoop *LoopA = MLI.getLoopFor(A); 128950a13cfSDan Gohman MachineLoop *LoopB = MLI.getLoopFor(B); 129950a13cfSDan Gohman if (LoopA == Loop && LoopB != Loop) 130950a13cfSDan Gohman return true; 131950a13cfSDan Gohman if (LoopA != Loop && LoopB == Loop) 132950a13cfSDan Gohman return false; 133950a13cfSDan Gohman 134950a13cfSDan Gohman // Minimize perturbation by preferring the block which is the immediate 135950a13cfSDan Gohman // layout successor. 136950a13cfSDan Gohman if (A == LayoutSucc) 137950a13cfSDan Gohman return true; 138950a13cfSDan Gohman if (B == LayoutSucc) 139950a13cfSDan Gohman return false; 140950a13cfSDan Gohman 141950a13cfSDan Gohman // TODO: More sophisticated orderings may be profitable here. 142950a13cfSDan Gohman 143950a13cfSDan Gohman return false; 144950a13cfSDan Gohman }); 145950a13cfSDan Gohman } 146950a13cfSDan Gohman 147950a13cfSDan Gohman /// Sort the blocks in RPO, taking special care to make sure that loops are 148950a13cfSDan Gohman /// contiguous even in the case of split backedges. 149950a13cfSDan Gohman static void SortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI) { 150950a13cfSDan Gohman // Note that we do our own RPO rather than using 151950a13cfSDan Gohman // "llvm/ADT/PostOrderIterator.h" because we want control over the order that 152950a13cfSDan Gohman // successors are visited in (see above). Also, we can sort the blocks in the 153950a13cfSDan Gohman // MachineFunction as we go. 154950a13cfSDan Gohman SmallPtrSet<MachineBasicBlock *, 16> Visited; 155950a13cfSDan Gohman SmallVector<POStackEntry, 16> Stack; 156950a13cfSDan Gohman 157*00406472SNico Weber MachineBasicBlock *Entry = &*MF.begin(); 158950a13cfSDan Gohman Visited.insert(Entry); 159950a13cfSDan Gohman Stack.push_back(POStackEntry(Entry, MF, MLI)); 160950a13cfSDan Gohman 161950a13cfSDan Gohman for (;;) { 162950a13cfSDan Gohman POStackEntry &Entry = Stack.back(); 163950a13cfSDan Gohman SmallVectorImpl<MachineBasicBlock *> &Succs = Entry.Succs; 164950a13cfSDan Gohman if (!Succs.empty()) { 165950a13cfSDan Gohman MachineBasicBlock *Succ = Succs.pop_back_val(); 166950a13cfSDan Gohman if (Visited.insert(Succ).second) 167950a13cfSDan Gohman Stack.push_back(POStackEntry(Succ, MF, MLI)); 168950a13cfSDan Gohman continue; 169950a13cfSDan Gohman } 170950a13cfSDan Gohman 171950a13cfSDan Gohman // Put the block in its position in the MachineFunction. 172950a13cfSDan Gohman MachineBasicBlock &MBB = *Entry.MBB; 173*00406472SNico Weber MBB.moveBefore(&*MF.begin()); 174950a13cfSDan Gohman 175950a13cfSDan Gohman // Branch instructions may utilize a fallthrough, so update them if a 176950a13cfSDan Gohman // fallthrough has been added or removed. 177950a13cfSDan Gohman if (!MBB.empty() && MBB.back().isTerminator() && !MBB.back().isBranch() && 178950a13cfSDan Gohman !MBB.back().isBarrier()) 179950a13cfSDan Gohman report_fatal_error( 180950a13cfSDan Gohman "Non-branch terminator with fallthrough cannot yet be rewritten"); 181950a13cfSDan Gohman if (MBB.empty() || !MBB.back().isTerminator() || MBB.back().isBranch()) 182950a13cfSDan Gohman MBB.updateTerminator(); 183950a13cfSDan Gohman 184950a13cfSDan Gohman Stack.pop_back(); 185950a13cfSDan Gohman if (Stack.empty()) 186950a13cfSDan Gohman break; 187950a13cfSDan Gohman } 188950a13cfSDan Gohman 189950a13cfSDan Gohman // Now that we've sorted the blocks in RPO, renumber them. 190950a13cfSDan Gohman MF.RenumberBlocks(); 191950a13cfSDan Gohman 192950a13cfSDan Gohman #ifndef NDEBUG 193950a13cfSDan Gohman for (auto &MBB : MF) 194950a13cfSDan Gohman if (MachineLoop *Loop = MLI.getLoopFor(&MBB)) { 195950a13cfSDan Gohman // Assert that loops are contiguous. 196950a13cfSDan Gohman assert(Loop->getHeader() == Loop->getTopBlock()); 197e3e4a5ffSDan Gohman assert((Loop->getHeader() == &MBB || 198e3e4a5ffSDan Gohman Loop->contains( 199*00406472SNico Weber MLI.getLoopFor(&*prev(MachineFunction::iterator(&MBB))))) && 200e3e4a5ffSDan Gohman "Loop isn't contiguous"); 201950a13cfSDan Gohman } else { 202950a13cfSDan Gohman // Assert that non-loops have no backedge predecessors. 203950a13cfSDan Gohman for (auto Pred : MBB.predecessors()) 204950a13cfSDan Gohman assert(Pred->getNumber() < MBB.getNumber() && 205950a13cfSDan Gohman "CFG still has multiple-entry loops"); 206950a13cfSDan Gohman } 207950a13cfSDan Gohman #endif 208950a13cfSDan Gohman } 209950a13cfSDan Gohman 210950a13cfSDan Gohman /// Insert BLOCK markers at appropriate places. 211950a13cfSDan Gohman static void PlaceBlockMarkers(MachineBasicBlock &MBB, MachineBasicBlock &Succ, 212950a13cfSDan Gohman MachineFunction &MF, const MachineLoopInfo &MLI, 213950a13cfSDan Gohman const WebAssemblyInstrInfo &TII) { 214950a13cfSDan Gohman // Backward branches are loop backedges, and we place the LOOP markers 215950a13cfSDan Gohman // separately. So only consider forward branches here. 216950a13cfSDan Gohman if (Succ.getNumber() <= MBB.getNumber()) 217950a13cfSDan Gohman return; 218950a13cfSDan Gohman 219950a13cfSDan Gohman // Place the BLOCK for a forward branch. For simplicity, we just insert 220950a13cfSDan Gohman // blocks immediately inside loop boundaries. 221950a13cfSDan Gohman MachineLoop *Loop = MLI.getLoopFor(&Succ); 222950a13cfSDan Gohman MachineBasicBlock &Header = *(Loop ? Loop->getHeader() : &MF.front()); 223950a13cfSDan Gohman MachineBasicBlock::iterator InsertPos = Header.begin(), End = Header.end(); 224950a13cfSDan Gohman if (InsertPos != End) { 225950a13cfSDan Gohman if (InsertPos->getOpcode() == WebAssembly::LOOP) 226950a13cfSDan Gohman ++InsertPos; 227950a13cfSDan Gohman int SuccNumber = Succ.getNumber(); 228950a13cfSDan Gohman // Position the BLOCK in nesting order. 229950a13cfSDan Gohman for (; InsertPos != End && InsertPos->getOpcode() == WebAssembly::BLOCK; 230950a13cfSDan Gohman ++InsertPos) { 231950a13cfSDan Gohman int N = InsertPos->getOperand(0).getMBB()->getNumber(); 232950a13cfSDan Gohman if (N < SuccNumber) 233950a13cfSDan Gohman break; 234950a13cfSDan Gohman // If there's already a BLOCK for Succ, we don't need another. 235950a13cfSDan Gohman if (N == SuccNumber) 236950a13cfSDan Gohman return; 237950a13cfSDan Gohman } 238950a13cfSDan Gohman } 239950a13cfSDan Gohman 240950a13cfSDan Gohman BuildMI(Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK)) 241950a13cfSDan Gohman .addMBB(&Succ); 242950a13cfSDan Gohman } 243950a13cfSDan Gohman 244950a13cfSDan Gohman /// Insert LOOP and BLOCK markers at appropriate places. 245950a13cfSDan Gohman static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI, 246950a13cfSDan Gohman const WebAssemblyInstrInfo &TII) { 247950a13cfSDan Gohman for (auto &MBB : MF) { 248950a13cfSDan Gohman // Place the LOOP for loops. 249950a13cfSDan Gohman if (MachineLoop *Loop = MLI.getLoopFor(&MBB)) 250e3e4a5ffSDan Gohman if (Loop->getHeader() == &MBB) { 251e3e4a5ffSDan Gohman // The operand of a LOOP is the first block after the loop. If the loop 252e3e4a5ffSDan Gohman // is the bottom of the function, insert a dummy block at the end. 253e3e4a5ffSDan Gohman MachineBasicBlock *Bottom = Loop->getBottomBlock(); 254e3e4a5ffSDan Gohman auto Iter = next(MachineFunction::iterator(Bottom)); 255e3e4a5ffSDan Gohman if (Iter == MF.end()) { 256e3e4a5ffSDan Gohman MF.push_back(MF.CreateMachineBasicBlock()); 257e3e4a5ffSDan Gohman Iter = next(MachineFunction::iterator(Bottom)); 258e3e4a5ffSDan Gohman } 259950a13cfSDan Gohman BuildMI(MBB, MBB.begin(), DebugLoc(), TII.get(WebAssembly::LOOP)) 260*00406472SNico Weber .addMBB(&*Iter); 261e3e4a5ffSDan Gohman } 262950a13cfSDan Gohman 263950a13cfSDan Gohman // Check for forward branches and switches that need BLOCKS placed. 264950a13cfSDan Gohman for (auto &Term : MBB.terminators()) 265950a13cfSDan Gohman for (auto &MO : Term.operands()) 266950a13cfSDan Gohman if (MO.isMBB()) 267950a13cfSDan Gohman PlaceBlockMarkers(MBB, *MO.getMBB(), MF, MLI, TII); 268950a13cfSDan Gohman } 269950a13cfSDan Gohman } 270950a13cfSDan Gohman 271950a13cfSDan Gohman bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 272950a13cfSDan Gohman DEBUG(dbgs() << "********** CFG Stackifying **********\n" 273950a13cfSDan Gohman "********** Function: " 274950a13cfSDan Gohman << MF.getName() << '\n'); 275950a13cfSDan Gohman 276950a13cfSDan Gohman const auto &MLI = getAnalysis<MachineLoopInfo>(); 277950a13cfSDan Gohman const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 278950a13cfSDan Gohman 279950a13cfSDan Gohman // RPO sorting needs all loops to be single-entry. 280950a13cfSDan Gohman EliminateMultipleEntryLoops(MF, MLI); 281950a13cfSDan Gohman 282950a13cfSDan Gohman // Sort the blocks in RPO, with contiguous loops. 283950a13cfSDan Gohman SortBlocks(MF, MLI); 284950a13cfSDan Gohman 285950a13cfSDan Gohman // Place the BLOCK and LOOP markers to indicate the beginnings of scopes. 286950a13cfSDan Gohman PlaceMarkers(MF, MLI, TII); 287950a13cfSDan Gohman 288950a13cfSDan Gohman return true; 289950a13cfSDan Gohman } 290