1*950a13cfSDan Gohman //===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===// 2*950a13cfSDan Gohman // 3*950a13cfSDan Gohman // The LLVM Compiler Infrastructure 4*950a13cfSDan Gohman // 5*950a13cfSDan Gohman // This file is distributed under the University of Illinois Open Source 6*950a13cfSDan Gohman // License. See LICENSE.TXT for details. 7*950a13cfSDan Gohman // 8*950a13cfSDan Gohman //===----------------------------------------------------------------------===// 9*950a13cfSDan Gohman /// 10*950a13cfSDan Gohman /// \file 11*950a13cfSDan Gohman /// \brief This file implements a CFG stacking pass. 12*950a13cfSDan Gohman /// 13*950a13cfSDan Gohman /// This pass reorders the blocks in a function to put them into a reverse 14*950a13cfSDan Gohman /// post-order [0], with special care to keep the order as similar as possible 15*950a13cfSDan Gohman /// to the original order, and to keep loops contiguous even in the case of 16*950a13cfSDan Gohman /// split backedges. 17*950a13cfSDan Gohman /// 18*950a13cfSDan Gohman /// Then, it inserts BLOCK and LOOP markers to mark the start of scopes, since 19*950a13cfSDan Gohman /// scope boundaries serve as the labels for WebAssembly's control transfers. 20*950a13cfSDan Gohman /// 21*950a13cfSDan Gohman /// This is sufficient to convert arbitrary CFGs into a form that works on 22*950a13cfSDan Gohman /// WebAssembly, provided that all loops are single-entry. 23*950a13cfSDan Gohman /// 24*950a13cfSDan Gohman /// [0] https://en.wikipedia.org/wiki/Depth-first_search#Vertex_orderings 25*950a13cfSDan Gohman /// 26*950a13cfSDan Gohman //===----------------------------------------------------------------------===// 27*950a13cfSDan Gohman 28*950a13cfSDan Gohman #include "WebAssembly.h" 29*950a13cfSDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 30*950a13cfSDan Gohman #include "WebAssemblySubtarget.h" 31*950a13cfSDan Gohman #include "llvm/ADT/SCCIterator.h" 32*950a13cfSDan Gohman #include "llvm/CodeGen/MachineFunction.h" 33*950a13cfSDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h" 34*950a13cfSDan Gohman #include "llvm/CodeGen/MachineLoopInfo.h" 35*950a13cfSDan Gohman #include "llvm/CodeGen/Passes.h" 36*950a13cfSDan Gohman #include "llvm/Support/Debug.h" 37*950a13cfSDan Gohman #include "llvm/Support/raw_ostream.h" 38*950a13cfSDan Gohman using namespace llvm; 39*950a13cfSDan Gohman 40*950a13cfSDan Gohman #define DEBUG_TYPE "wasm-cfg-stackify" 41*950a13cfSDan Gohman 42*950a13cfSDan Gohman namespace { 43*950a13cfSDan Gohman class WebAssemblyCFGStackify final : public MachineFunctionPass { 44*950a13cfSDan Gohman const char *getPassName() const override { 45*950a13cfSDan Gohman return "WebAssembly CFG Stackify"; 46*950a13cfSDan Gohman } 47*950a13cfSDan Gohman 48*950a13cfSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override { 49*950a13cfSDan Gohman AU.setPreservesCFG(); 50*950a13cfSDan Gohman AU.addRequired<MachineLoopInfo>(); 51*950a13cfSDan Gohman AU.addPreserved<MachineLoopInfo>(); 52*950a13cfSDan Gohman MachineFunctionPass::getAnalysisUsage(AU); 53*950a13cfSDan Gohman } 54*950a13cfSDan Gohman 55*950a13cfSDan Gohman bool runOnMachineFunction(MachineFunction &MF) override; 56*950a13cfSDan Gohman 57*950a13cfSDan Gohman public: 58*950a13cfSDan Gohman static char ID; // Pass identification, replacement for typeid 59*950a13cfSDan Gohman WebAssemblyCFGStackify() : MachineFunctionPass(ID) {} 60*950a13cfSDan Gohman }; 61*950a13cfSDan Gohman } // end anonymous namespace 62*950a13cfSDan Gohman 63*950a13cfSDan Gohman char WebAssemblyCFGStackify::ID = 0; 64*950a13cfSDan Gohman FunctionPass *llvm::createWebAssemblyCFGStackify() { 65*950a13cfSDan Gohman return new WebAssemblyCFGStackify(); 66*950a13cfSDan Gohman } 67*950a13cfSDan Gohman 68*950a13cfSDan Gohman static void EliminateMultipleEntryLoops(MachineFunction &MF, 69*950a13cfSDan Gohman const MachineLoopInfo &MLI) { 70*950a13cfSDan Gohman SmallPtrSet<MachineBasicBlock *, 8> InSet; 71*950a13cfSDan Gohman for (scc_iterator<MachineFunction *> I = scc_begin(&MF), E = scc_end(&MF); 72*950a13cfSDan Gohman I != E; ++I) { 73*950a13cfSDan Gohman const std::vector<MachineBasicBlock *> &CurrentSCC = *I; 74*950a13cfSDan Gohman 75*950a13cfSDan Gohman // Skip trivial SCCs. 76*950a13cfSDan Gohman if (CurrentSCC.size() == 1) 77*950a13cfSDan Gohman continue; 78*950a13cfSDan Gohman 79*950a13cfSDan Gohman InSet.insert(CurrentSCC.begin(), CurrentSCC.end()); 80*950a13cfSDan Gohman MachineBasicBlock *Header = nullptr; 81*950a13cfSDan Gohman for (MachineBasicBlock *MBB : CurrentSCC) { 82*950a13cfSDan Gohman for (MachineBasicBlock *Pred : MBB->predecessors()) { 83*950a13cfSDan Gohman if (InSet.count(Pred)) 84*950a13cfSDan Gohman continue; 85*950a13cfSDan Gohman if (!Header) { 86*950a13cfSDan Gohman Header = MBB; 87*950a13cfSDan Gohman break; 88*950a13cfSDan Gohman } 89*950a13cfSDan Gohman // TODO: Implement multiple-entry loops. 90*950a13cfSDan Gohman report_fatal_error("multiple-entry loops are not supported yet"); 91*950a13cfSDan Gohman } 92*950a13cfSDan Gohman } 93*950a13cfSDan Gohman assert(MLI.isLoopHeader(Header)); 94*950a13cfSDan Gohman 95*950a13cfSDan Gohman InSet.clear(); 96*950a13cfSDan Gohman } 97*950a13cfSDan Gohman } 98*950a13cfSDan Gohman 99*950a13cfSDan Gohman namespace { 100*950a13cfSDan Gohman /// Post-order traversal stack entry. 101*950a13cfSDan Gohman struct POStackEntry { 102*950a13cfSDan Gohman MachineBasicBlock *MBB; 103*950a13cfSDan Gohman SmallVector<MachineBasicBlock *, 0> Succs; 104*950a13cfSDan Gohman 105*950a13cfSDan Gohman POStackEntry(MachineBasicBlock *MBB, MachineFunction &MF, 106*950a13cfSDan Gohman const MachineLoopInfo &MLI); 107*950a13cfSDan Gohman }; 108*950a13cfSDan Gohman } // end anonymous namespace 109*950a13cfSDan Gohman 110*950a13cfSDan Gohman POStackEntry::POStackEntry(MachineBasicBlock *MBB, MachineFunction &MF, 111*950a13cfSDan Gohman const MachineLoopInfo &MLI) 112*950a13cfSDan Gohman : MBB(MBB), Succs(MBB->successors()) { 113*950a13cfSDan Gohman // RPO is not a unique form, since at every basic block with multiple 114*950a13cfSDan Gohman // successors, the DFS has to pick which order to visit the successors in. 115*950a13cfSDan Gohman // Sort them strategically (see below). 116*950a13cfSDan Gohman MachineLoop *Loop = MLI.getLoopFor(MBB); 117*950a13cfSDan Gohman MachineFunction::iterator Next = next(MachineFunction::iterator(MBB)); 118*950a13cfSDan Gohman MachineBasicBlock *LayoutSucc = Next == MF.end() ? nullptr : &*Next; 119*950a13cfSDan Gohman std::stable_sort( 120*950a13cfSDan Gohman Succs.begin(), Succs.end(), 121*950a13cfSDan Gohman [=, &MLI](const MachineBasicBlock *A, const MachineBasicBlock *B) { 122*950a13cfSDan Gohman if (A == B) 123*950a13cfSDan Gohman return false; 124*950a13cfSDan Gohman 125*950a13cfSDan Gohman // Keep loops contiguous by preferring the block that's in the same 126*950a13cfSDan Gohman // loop. 127*950a13cfSDan Gohman MachineLoop *LoopA = MLI.getLoopFor(A); 128*950a13cfSDan Gohman MachineLoop *LoopB = MLI.getLoopFor(B); 129*950a13cfSDan Gohman if (LoopA == Loop && LoopB != Loop) 130*950a13cfSDan Gohman return true; 131*950a13cfSDan Gohman if (LoopA != Loop && LoopB == Loop) 132*950a13cfSDan Gohman return false; 133*950a13cfSDan Gohman 134*950a13cfSDan Gohman // Minimize perturbation by preferring the block which is the immediate 135*950a13cfSDan Gohman // layout successor. 136*950a13cfSDan Gohman if (A == LayoutSucc) 137*950a13cfSDan Gohman return true; 138*950a13cfSDan Gohman if (B == LayoutSucc) 139*950a13cfSDan Gohman return false; 140*950a13cfSDan Gohman 141*950a13cfSDan Gohman // TODO: More sophisticated orderings may be profitable here. 142*950a13cfSDan Gohman 143*950a13cfSDan Gohman return false; 144*950a13cfSDan Gohman }); 145*950a13cfSDan Gohman } 146*950a13cfSDan Gohman 147*950a13cfSDan Gohman /// Sort the blocks in RPO, taking special care to make sure that loops are 148*950a13cfSDan Gohman /// contiguous even in the case of split backedges. 149*950a13cfSDan Gohman static void SortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI) { 150*950a13cfSDan Gohman // Note that we do our own RPO rather than using 151*950a13cfSDan Gohman // "llvm/ADT/PostOrderIterator.h" because we want control over the order that 152*950a13cfSDan Gohman // successors are visited in (see above). Also, we can sort the blocks in the 153*950a13cfSDan Gohman // MachineFunction as we go. 154*950a13cfSDan Gohman SmallPtrSet<MachineBasicBlock *, 16> Visited; 155*950a13cfSDan Gohman SmallVector<POStackEntry, 16> Stack; 156*950a13cfSDan Gohman 157*950a13cfSDan Gohman MachineBasicBlock *Entry = MF.begin(); 158*950a13cfSDan Gohman Visited.insert(Entry); 159*950a13cfSDan Gohman Stack.push_back(POStackEntry(Entry, MF, MLI)); 160*950a13cfSDan Gohman 161*950a13cfSDan Gohman for (;;) { 162*950a13cfSDan Gohman POStackEntry &Entry = Stack.back(); 163*950a13cfSDan Gohman SmallVectorImpl<MachineBasicBlock *> &Succs = Entry.Succs; 164*950a13cfSDan Gohman if (!Succs.empty()) { 165*950a13cfSDan Gohman MachineBasicBlock *Succ = Succs.pop_back_val(); 166*950a13cfSDan Gohman if (Visited.insert(Succ).second) 167*950a13cfSDan Gohman Stack.push_back(POStackEntry(Succ, MF, MLI)); 168*950a13cfSDan Gohman continue; 169*950a13cfSDan Gohman } 170*950a13cfSDan Gohman 171*950a13cfSDan Gohman // Put the block in its position in the MachineFunction. 172*950a13cfSDan Gohman MachineBasicBlock &MBB = *Entry.MBB; 173*950a13cfSDan Gohman MBB.moveBefore(MF.begin()); 174*950a13cfSDan Gohman 175*950a13cfSDan Gohman // Branch instructions may utilize a fallthrough, so update them if a 176*950a13cfSDan Gohman // fallthrough has been added or removed. 177*950a13cfSDan Gohman if (!MBB.empty() && MBB.back().isTerminator() && !MBB.back().isBranch() && 178*950a13cfSDan Gohman !MBB.back().isBarrier()) 179*950a13cfSDan Gohman report_fatal_error( 180*950a13cfSDan Gohman "Non-branch terminator with fallthrough cannot yet be rewritten"); 181*950a13cfSDan Gohman if (MBB.empty() || !MBB.back().isTerminator() || MBB.back().isBranch()) 182*950a13cfSDan Gohman MBB.updateTerminator(); 183*950a13cfSDan Gohman 184*950a13cfSDan Gohman Stack.pop_back(); 185*950a13cfSDan Gohman if (Stack.empty()) 186*950a13cfSDan Gohman break; 187*950a13cfSDan Gohman } 188*950a13cfSDan Gohman 189*950a13cfSDan Gohman // Now that we've sorted the blocks in RPO, renumber them. 190*950a13cfSDan Gohman MF.RenumberBlocks(); 191*950a13cfSDan Gohman 192*950a13cfSDan Gohman #ifndef NDEBUG 193*950a13cfSDan Gohman for (auto &MBB : MF) 194*950a13cfSDan Gohman if (MachineLoop *Loop = MLI.getLoopFor(&MBB)) { 195*950a13cfSDan Gohman // Assert that loops are contiguous. 196*950a13cfSDan Gohman assert(Loop->getHeader() == Loop->getTopBlock()); 197*950a13cfSDan Gohman assert(Loop->getHeader() == &MBB || 198*950a13cfSDan Gohman MLI.getLoopFor(prev(MachineFunction::iterator(&MBB))) == Loop); 199*950a13cfSDan Gohman } else { 200*950a13cfSDan Gohman // Assert that non-loops have no backedge predecessors. 201*950a13cfSDan Gohman for (auto Pred : MBB.predecessors()) 202*950a13cfSDan Gohman assert(Pred->getNumber() < MBB.getNumber() && 203*950a13cfSDan Gohman "CFG still has multiple-entry loops"); 204*950a13cfSDan Gohman } 205*950a13cfSDan Gohman #endif 206*950a13cfSDan Gohman } 207*950a13cfSDan Gohman 208*950a13cfSDan Gohman /// Insert BLOCK markers at appropriate places. 209*950a13cfSDan Gohman static void PlaceBlockMarkers(MachineBasicBlock &MBB, MachineBasicBlock &Succ, 210*950a13cfSDan Gohman MachineFunction &MF, const MachineLoopInfo &MLI, 211*950a13cfSDan Gohman const WebAssemblyInstrInfo &TII) { 212*950a13cfSDan Gohman // Backward branches are loop backedges, and we place the LOOP markers 213*950a13cfSDan Gohman // separately. So only consider forward branches here. 214*950a13cfSDan Gohman if (Succ.getNumber() <= MBB.getNumber()) 215*950a13cfSDan Gohman return; 216*950a13cfSDan Gohman 217*950a13cfSDan Gohman // Place the BLOCK for a forward branch. For simplicity, we just insert 218*950a13cfSDan Gohman // blocks immediately inside loop boundaries. 219*950a13cfSDan Gohman MachineLoop *Loop = MLI.getLoopFor(&Succ); 220*950a13cfSDan Gohman MachineBasicBlock &Header = *(Loop ? Loop->getHeader() : &MF.front()); 221*950a13cfSDan Gohman MachineBasicBlock::iterator InsertPos = Header.begin(), End = Header.end(); 222*950a13cfSDan Gohman if (InsertPos != End) { 223*950a13cfSDan Gohman if (InsertPos->getOpcode() == WebAssembly::LOOP) 224*950a13cfSDan Gohman ++InsertPos; 225*950a13cfSDan Gohman int SuccNumber = Succ.getNumber(); 226*950a13cfSDan Gohman // Position the BLOCK in nesting order. 227*950a13cfSDan Gohman for (; InsertPos != End && InsertPos->getOpcode() == WebAssembly::BLOCK; 228*950a13cfSDan Gohman ++InsertPos) { 229*950a13cfSDan Gohman int N = InsertPos->getOperand(0).getMBB()->getNumber(); 230*950a13cfSDan Gohman if (N < SuccNumber) 231*950a13cfSDan Gohman break; 232*950a13cfSDan Gohman // If there's already a BLOCK for Succ, we don't need another. 233*950a13cfSDan Gohman if (N == SuccNumber) 234*950a13cfSDan Gohman return; 235*950a13cfSDan Gohman } 236*950a13cfSDan Gohman } 237*950a13cfSDan Gohman 238*950a13cfSDan Gohman BuildMI(Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK)) 239*950a13cfSDan Gohman .addMBB(&Succ); 240*950a13cfSDan Gohman } 241*950a13cfSDan Gohman 242*950a13cfSDan Gohman /// Insert LOOP and BLOCK markers at appropriate places. 243*950a13cfSDan Gohman static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI, 244*950a13cfSDan Gohman const WebAssemblyInstrInfo &TII) { 245*950a13cfSDan Gohman for (auto &MBB : MF) { 246*950a13cfSDan Gohman // Place the LOOP for loops. 247*950a13cfSDan Gohman if (MachineLoop *Loop = MLI.getLoopFor(&MBB)) 248*950a13cfSDan Gohman if (Loop->getHeader() == &MBB) 249*950a13cfSDan Gohman BuildMI(MBB, MBB.begin(), DebugLoc(), TII.get(WebAssembly::LOOP)) 250*950a13cfSDan Gohman .addMBB(Loop->getBottomBlock()); 251*950a13cfSDan Gohman 252*950a13cfSDan Gohman // Check for forward branches and switches that need BLOCKS placed. 253*950a13cfSDan Gohman for (auto &Term : MBB.terminators()) 254*950a13cfSDan Gohman for (auto &MO : Term.operands()) 255*950a13cfSDan Gohman if (MO.isMBB()) 256*950a13cfSDan Gohman PlaceBlockMarkers(MBB, *MO.getMBB(), MF, MLI, TII); 257*950a13cfSDan Gohman } 258*950a13cfSDan Gohman } 259*950a13cfSDan Gohman 260*950a13cfSDan Gohman bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 261*950a13cfSDan Gohman DEBUG(dbgs() << "********** CFG Stackifying **********\n" 262*950a13cfSDan Gohman "********** Function: " 263*950a13cfSDan Gohman << MF.getName() << '\n'); 264*950a13cfSDan Gohman 265*950a13cfSDan Gohman const auto &MLI = getAnalysis<MachineLoopInfo>(); 266*950a13cfSDan Gohman const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 267*950a13cfSDan Gohman 268*950a13cfSDan Gohman // RPO sorting needs all loops to be single-entry. 269*950a13cfSDan Gohman EliminateMultipleEntryLoops(MF, MLI); 270*950a13cfSDan Gohman 271*950a13cfSDan Gohman // Sort the blocks in RPO, with contiguous loops. 272*950a13cfSDan Gohman SortBlocks(MF, MLI); 273*950a13cfSDan Gohman 274*950a13cfSDan Gohman // Place the BLOCK and LOOP markers to indicate the beginnings of scopes. 275*950a13cfSDan Gohman PlaceMarkers(MF, MLI, TII); 276*950a13cfSDan Gohman 277*950a13cfSDan Gohman return true; 278*950a13cfSDan Gohman } 279