1950a13cfSDan Gohman //===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===// 2950a13cfSDan Gohman // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6950a13cfSDan Gohman // 7950a13cfSDan Gohman //===----------------------------------------------------------------------===// 8950a13cfSDan Gohman /// 9950a13cfSDan Gohman /// \file 105f8f34e4SAdrian Prantl /// This file implements a CFG stacking pass. 11950a13cfSDan Gohman /// 12e76fa9ecSHeejin Ahn /// This pass inserts BLOCK, LOOP, and TRY markers to mark the start of scopes, 13e76fa9ecSHeejin Ahn /// since scope boundaries serve as the labels for WebAssembly's control 14e76fa9ecSHeejin Ahn /// transfers. 15950a13cfSDan Gohman /// 16950a13cfSDan Gohman /// This is sufficient to convert arbitrary CFGs into a form that works on 17950a13cfSDan Gohman /// WebAssembly, provided that all loops are single-entry. 18950a13cfSDan Gohman /// 19e76fa9ecSHeejin Ahn /// In case we use exceptions, this pass also fixes mismatches in unwind 20e76fa9ecSHeejin Ahn /// destinations created during transforming CFG into wasm structured format. 21e76fa9ecSHeejin Ahn /// 22950a13cfSDan Gohman //===----------------------------------------------------------------------===// 23950a13cfSDan Gohman 246bda14b3SChandler Carruth #include "WebAssembly.h" 25e76fa9ecSHeejin Ahn #include "WebAssemblyExceptionInfo.h" 26ed0f1138SDan Gohman #include "WebAssemblyMachineFunctionInfo.h" 27276f9e8cSHeejin Ahn #include "WebAssemblySortRegion.h" 28950a13cfSDan Gohman #include "WebAssemblySubtarget.h" 294fc4e42dSDan Gohman #include "WebAssemblyUtilities.h" 30c4ac74fbSHeejin Ahn #include "llvm/ADT/Statistic.h" 3132807932SDan Gohman #include "llvm/CodeGen/MachineDominators.h" 32950a13cfSDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h" 33904cd3e0SReid Kleckner #include "llvm/CodeGen/MachineLoopInfo.h" 34e76fa9ecSHeejin Ahn #include "llvm/MC/MCAsmInfo.h" 35fe0006c8SSimon Pilgrim #include "llvm/Target/TargetMachine.h" 36950a13cfSDan Gohman using namespace llvm; 37276f9e8cSHeejin Ahn using WebAssembly::SortRegionInfo; 38950a13cfSDan Gohman 39950a13cfSDan Gohman #define DEBUG_TYPE "wasm-cfg-stackify" 40950a13cfSDan Gohman 41c4ac74fbSHeejin Ahn STATISTIC(NumUnwindMismatches, "Number of EH pad unwind mismatches found"); 42c4ac74fbSHeejin Ahn 43950a13cfSDan Gohman namespace { 44950a13cfSDan Gohman class WebAssemblyCFGStackify final : public MachineFunctionPass { 45117296c0SMehdi Amini StringRef getPassName() const override { return "WebAssembly CFG Stackify"; } 46950a13cfSDan Gohman 47950a13cfSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override { 4832807932SDan Gohman AU.addRequired<MachineDominatorTree>(); 49950a13cfSDan Gohman AU.addRequired<MachineLoopInfo>(); 50e76fa9ecSHeejin Ahn AU.addRequired<WebAssemblyExceptionInfo>(); 51950a13cfSDan Gohman MachineFunctionPass::getAnalysisUsage(AU); 52950a13cfSDan Gohman } 53950a13cfSDan Gohman 54950a13cfSDan Gohman bool runOnMachineFunction(MachineFunction &MF) override; 55950a13cfSDan Gohman 56e76fa9ecSHeejin Ahn // For each block whose label represents the end of a scope, record the block 57e76fa9ecSHeejin Ahn // which holds the beginning of the scope. This will allow us to quickly skip 58e76fa9ecSHeejin Ahn // over scoped regions when walking blocks. 59e76fa9ecSHeejin Ahn SmallVector<MachineBasicBlock *, 8> ScopeTops; 60e76fa9ecSHeejin Ahn 61c4ac74fbSHeejin Ahn // Placing markers. 62e76fa9ecSHeejin Ahn void placeMarkers(MachineFunction &MF); 63e76fa9ecSHeejin Ahn void placeBlockMarker(MachineBasicBlock &MBB); 64e76fa9ecSHeejin Ahn void placeLoopMarker(MachineBasicBlock &MBB); 65e76fa9ecSHeejin Ahn void placeTryMarker(MachineBasicBlock &MBB); 66cf699b45SHeejin Ahn void removeUnnecessaryInstrs(MachineFunction &MF); 67c4ac74fbSHeejin Ahn bool fixUnwindMismatches(MachineFunction &MF); 68e76fa9ecSHeejin Ahn void rewriteDepthImmediates(MachineFunction &MF); 69e76fa9ecSHeejin Ahn void fixEndsAtEndOfFunction(MachineFunction &MF); 70e76fa9ecSHeejin Ahn 71e76fa9ecSHeejin Ahn // For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY). 72e76fa9ecSHeejin Ahn DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd; 73e76fa9ecSHeejin Ahn // For each END_(BLOCK|LOOP|TRY), the corresponding BLOCK|LOOP|TRY. 74e76fa9ecSHeejin Ahn DenseMap<const MachineInstr *, MachineInstr *> EndToBegin; 75e76fa9ecSHeejin Ahn // <TRY marker, EH pad> map 76e76fa9ecSHeejin Ahn DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad; 77e76fa9ecSHeejin Ahn // <EH pad, TRY marker> map 78e76fa9ecSHeejin Ahn DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry; 79e76fa9ecSHeejin Ahn 80c4ac74fbSHeejin Ahn // There can be an appendix block at the end of each function, shared for: 81c4ac74fbSHeejin Ahn // - creating a correct signature for fallthrough returns 82c4ac74fbSHeejin Ahn // - target for rethrows that need to unwind to the caller, but are trapped 83c4ac74fbSHeejin Ahn // inside another try/catch 84c4ac74fbSHeejin Ahn MachineBasicBlock *AppendixBB = nullptr; 85c4ac74fbSHeejin Ahn MachineBasicBlock *getAppendixBlock(MachineFunction &MF) { 86c4ac74fbSHeejin Ahn if (!AppendixBB) { 87c4ac74fbSHeejin Ahn AppendixBB = MF.CreateMachineBasicBlock(); 88c4ac74fbSHeejin Ahn // Give it a fake predecessor so that AsmPrinter prints its label. 89c4ac74fbSHeejin Ahn AppendixBB->addSuccessor(AppendixBB); 90c4ac74fbSHeejin Ahn MF.push_back(AppendixBB); 91c4ac74fbSHeejin Ahn } 92c4ac74fbSHeejin Ahn return AppendixBB; 93c4ac74fbSHeejin Ahn } 94c4ac74fbSHeejin Ahn 95cf699b45SHeejin Ahn // Helper functions to register / unregister scope information created by 96cf699b45SHeejin Ahn // marker instructions. 97e76fa9ecSHeejin Ahn void registerScope(MachineInstr *Begin, MachineInstr *End); 98e76fa9ecSHeejin Ahn void registerTryScope(MachineInstr *Begin, MachineInstr *End, 99e76fa9ecSHeejin Ahn MachineBasicBlock *EHPad); 100cf699b45SHeejin Ahn void unregisterScope(MachineInstr *Begin); 101e76fa9ecSHeejin Ahn 102950a13cfSDan Gohman public: 103950a13cfSDan Gohman static char ID; // Pass identification, replacement for typeid 104950a13cfSDan Gohman WebAssemblyCFGStackify() : MachineFunctionPass(ID) {} 105e76fa9ecSHeejin Ahn ~WebAssemblyCFGStackify() override { releaseMemory(); } 106e76fa9ecSHeejin Ahn void releaseMemory() override; 107950a13cfSDan Gohman }; 108950a13cfSDan Gohman } // end anonymous namespace 109950a13cfSDan Gohman 110950a13cfSDan Gohman char WebAssemblyCFGStackify::ID = 0; 11140926451SJacob Gravelle INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE, 112c4ac74fbSHeejin Ahn "Insert BLOCK/LOOP/TRY markers for WebAssembly scopes", false, 113f208f631SHeejin Ahn false) 11440926451SJacob Gravelle 115950a13cfSDan Gohman FunctionPass *llvm::createWebAssemblyCFGStackify() { 116950a13cfSDan Gohman return new WebAssemblyCFGStackify(); 117950a13cfSDan Gohman } 118950a13cfSDan Gohman 119b3aa1ecaSDan Gohman /// Test whether Pred has any terminators explicitly branching to MBB, as 120b3aa1ecaSDan Gohman /// opposed to falling through. Note that it's possible (eg. in unoptimized 121b3aa1ecaSDan Gohman /// code) for a branch instruction to both branch to a block and fallthrough 122b3aa1ecaSDan Gohman /// to it, so we check the actual branch operands to see if there are any 123b3aa1ecaSDan Gohman /// explicit mentions. 12418c56a07SHeejin Ahn static bool explicitlyBranchesTo(MachineBasicBlock *Pred, 12535e4a289SDan Gohman MachineBasicBlock *MBB) { 126b3aa1ecaSDan Gohman for (MachineInstr &MI : Pred->terminators()) 127b3aa1ecaSDan Gohman for (MachineOperand &MO : MI.explicit_operands()) 128b3aa1ecaSDan Gohman if (MO.isMBB() && MO.getMBB() == MBB) 129b3aa1ecaSDan Gohman return true; 130b3aa1ecaSDan Gohman return false; 131b3aa1ecaSDan Gohman } 132b3aa1ecaSDan Gohman 133e76fa9ecSHeejin Ahn // Returns an iterator to the earliest position possible within the MBB, 134e76fa9ecSHeejin Ahn // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 135e76fa9ecSHeejin Ahn // contains instructions that should go before the marker, and AfterSet contains 136e76fa9ecSHeejin Ahn // ones that should go after the marker. In this function, AfterSet is only 137e76fa9ecSHeejin Ahn // used for sanity checking. 138e76fa9ecSHeejin Ahn static MachineBasicBlock::iterator 13918c56a07SHeejin Ahn getEarliestInsertPos(MachineBasicBlock *MBB, 140e76fa9ecSHeejin Ahn const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 141e76fa9ecSHeejin Ahn const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 142e76fa9ecSHeejin Ahn auto InsertPos = MBB->end(); 143e76fa9ecSHeejin Ahn while (InsertPos != MBB->begin()) { 144e76fa9ecSHeejin Ahn if (BeforeSet.count(&*std::prev(InsertPos))) { 145e76fa9ecSHeejin Ahn #ifndef NDEBUG 146e76fa9ecSHeejin Ahn // Sanity check 147e76fa9ecSHeejin Ahn for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos) 148e76fa9ecSHeejin Ahn assert(!AfterSet.count(&*std::prev(Pos))); 149e76fa9ecSHeejin Ahn #endif 150e76fa9ecSHeejin Ahn break; 151e76fa9ecSHeejin Ahn } 152e76fa9ecSHeejin Ahn --InsertPos; 153e76fa9ecSHeejin Ahn } 154e76fa9ecSHeejin Ahn return InsertPos; 155e76fa9ecSHeejin Ahn } 156e76fa9ecSHeejin Ahn 157e76fa9ecSHeejin Ahn // Returns an iterator to the latest position possible within the MBB, 158e76fa9ecSHeejin Ahn // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 159e76fa9ecSHeejin Ahn // contains instructions that should go before the marker, and AfterSet contains 160e76fa9ecSHeejin Ahn // ones that should go after the marker. In this function, BeforeSet is only 161e76fa9ecSHeejin Ahn // used for sanity checking. 162e76fa9ecSHeejin Ahn static MachineBasicBlock::iterator 16318c56a07SHeejin Ahn getLatestInsertPos(MachineBasicBlock *MBB, 164e76fa9ecSHeejin Ahn const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 165e76fa9ecSHeejin Ahn const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 166e76fa9ecSHeejin Ahn auto InsertPos = MBB->begin(); 167e76fa9ecSHeejin Ahn while (InsertPos != MBB->end()) { 168e76fa9ecSHeejin Ahn if (AfterSet.count(&*InsertPos)) { 169e76fa9ecSHeejin Ahn #ifndef NDEBUG 170e76fa9ecSHeejin Ahn // Sanity check 171e76fa9ecSHeejin Ahn for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos) 172e76fa9ecSHeejin Ahn assert(!BeforeSet.count(&*Pos)); 173e76fa9ecSHeejin Ahn #endif 174e76fa9ecSHeejin Ahn break; 175e76fa9ecSHeejin Ahn } 176e76fa9ecSHeejin Ahn ++InsertPos; 177e76fa9ecSHeejin Ahn } 178e76fa9ecSHeejin Ahn return InsertPos; 179e76fa9ecSHeejin Ahn } 180e76fa9ecSHeejin Ahn 181d25c17f3SHeejin Ahn // Find a catch instruction and its destination register within an EH pad. 182d25c17f3SHeejin Ahn static MachineInstr *findCatch(MachineBasicBlock *EHPad, Register &ExnReg) { 183d25c17f3SHeejin Ahn assert(EHPad->isEHPad()); 184d25c17f3SHeejin Ahn MachineInstr *Catch = nullptr; 185d25c17f3SHeejin Ahn for (auto &MI : *EHPad) { 186d25c17f3SHeejin Ahn switch (MI.getOpcode()) { 187d25c17f3SHeejin Ahn case WebAssembly::CATCH: 188d25c17f3SHeejin Ahn Catch = &MI; 189d25c17f3SHeejin Ahn ExnReg = Catch->getOperand(0).getReg(); 190d25c17f3SHeejin Ahn break; 191d25c17f3SHeejin Ahn } 192d25c17f3SHeejin Ahn } 193d25c17f3SHeejin Ahn assert(Catch && "EH pad does not have a catch"); 194d25c17f3SHeejin Ahn assert(ExnReg != 0 && "Invalid register"); 195d25c17f3SHeejin Ahn return Catch; 196d25c17f3SHeejin Ahn } 197d25c17f3SHeejin Ahn 198d25c17f3SHeejin Ahn static MachineInstr *findCatch(MachineBasicBlock *EHPad) { 199d25c17f3SHeejin Ahn Register Dummy; 200d25c17f3SHeejin Ahn return findCatch(EHPad, Dummy); 201d25c17f3SHeejin Ahn } 202d25c17f3SHeejin Ahn 203e76fa9ecSHeejin Ahn void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin, 204e76fa9ecSHeejin Ahn MachineInstr *End) { 205e76fa9ecSHeejin Ahn BeginToEnd[Begin] = End; 206e76fa9ecSHeejin Ahn EndToBegin[End] = Begin; 207e76fa9ecSHeejin Ahn } 208e76fa9ecSHeejin Ahn 209e76fa9ecSHeejin Ahn void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin, 210e76fa9ecSHeejin Ahn MachineInstr *End, 211e76fa9ecSHeejin Ahn MachineBasicBlock *EHPad) { 212e76fa9ecSHeejin Ahn registerScope(Begin, End); 213e76fa9ecSHeejin Ahn TryToEHPad[Begin] = EHPad; 214e76fa9ecSHeejin Ahn EHPadToTry[EHPad] = Begin; 215e76fa9ecSHeejin Ahn } 216e76fa9ecSHeejin Ahn 217cf699b45SHeejin Ahn void WebAssemblyCFGStackify::unregisterScope(MachineInstr *Begin) { 218cf699b45SHeejin Ahn assert(BeginToEnd.count(Begin)); 219cf699b45SHeejin Ahn MachineInstr *End = BeginToEnd[Begin]; 220cf699b45SHeejin Ahn assert(EndToBegin.count(End)); 221cf699b45SHeejin Ahn BeginToEnd.erase(Begin); 222cf699b45SHeejin Ahn EndToBegin.erase(End); 223cf699b45SHeejin Ahn MachineBasicBlock *EHPad = TryToEHPad.lookup(Begin); 224cf699b45SHeejin Ahn if (EHPad) { 225cf699b45SHeejin Ahn assert(EHPadToTry.count(EHPad)); 226cf699b45SHeejin Ahn TryToEHPad.erase(Begin); 227cf699b45SHeejin Ahn EHPadToTry.erase(EHPad); 228cf699b45SHeejin Ahn } 229cf699b45SHeejin Ahn } 230cf699b45SHeejin Ahn 23132807932SDan Gohman /// Insert a BLOCK marker for branches to MBB (if needed). 232c4ac74fbSHeejin Ahn // TODO Consider a more generalized way of handling block (and also loop and 233c4ac74fbSHeejin Ahn // try) signatures when we implement the multi-value proposal later. 234e76fa9ecSHeejin Ahn void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) { 23544a5a4b1SHeejin Ahn assert(!MBB.isEHPad()); 236e76fa9ecSHeejin Ahn MachineFunction &MF = *MBB.getParent(); 237e76fa9ecSHeejin Ahn auto &MDT = getAnalysis<MachineDominatorTree>(); 238e76fa9ecSHeejin Ahn const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 239e76fa9ecSHeejin Ahn const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 240e76fa9ecSHeejin Ahn 2418fe7e86bSDan Gohman // First compute the nearest common dominator of all forward non-fallthrough 2428fe7e86bSDan Gohman // predecessors so that we minimize the time that the BLOCK is on the stack, 2438fe7e86bSDan Gohman // which reduces overall stack height. 24432807932SDan Gohman MachineBasicBlock *Header = nullptr; 24532807932SDan Gohman bool IsBranchedTo = false; 246d6f48786SHeejin Ahn bool IsBrOnExn = false; 247d6f48786SHeejin Ahn MachineInstr *BrOnExn = nullptr; 24832807932SDan Gohman int MBBNumber = MBB.getNumber(); 249e76fa9ecSHeejin Ahn for (MachineBasicBlock *Pred : MBB.predecessors()) { 25032807932SDan Gohman if (Pred->getNumber() < MBBNumber) { 25132807932SDan Gohman Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 25218c56a07SHeejin Ahn if (explicitlyBranchesTo(Pred, &MBB)) { 25332807932SDan Gohman IsBranchedTo = true; 254d6f48786SHeejin Ahn if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) { 255d6f48786SHeejin Ahn IsBrOnExn = true; 256d6f48786SHeejin Ahn assert(!BrOnExn && "There should be only one br_on_exn per block"); 257d6f48786SHeejin Ahn BrOnExn = &*Pred->getFirstTerminator(); 258d6f48786SHeejin Ahn } 259d6f48786SHeejin Ahn } 26032807932SDan Gohman } 261e76fa9ecSHeejin Ahn } 26232807932SDan Gohman if (!Header) 26332807932SDan Gohman return; 26432807932SDan Gohman if (!IsBranchedTo) 26532807932SDan Gohman return; 26632807932SDan Gohman 2678fe7e86bSDan Gohman assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors"); 2685c644c9bSHeejin Ahn MachineBasicBlock *LayoutPred = MBB.getPrevNode(); 2698fe7e86bSDan Gohman 2708fe7e86bSDan Gohman // If the nearest common dominator is inside a more deeply nested context, 2718fe7e86bSDan Gohman // walk out to the nearest scope which isn't more deeply nested. 2728fe7e86bSDan Gohman for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 2738fe7e86bSDan Gohman if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 2748fe7e86bSDan Gohman if (ScopeTop->getNumber() > Header->getNumber()) { 2758fe7e86bSDan Gohman // Skip over an intervening scope. 2765c644c9bSHeejin Ahn I = std::next(ScopeTop->getIterator()); 2778fe7e86bSDan Gohman } else { 2788fe7e86bSDan Gohman // We found a scope level at an appropriate depth. 2798fe7e86bSDan Gohman Header = ScopeTop; 2808fe7e86bSDan Gohman break; 2818fe7e86bSDan Gohman } 2828fe7e86bSDan Gohman } 2838fe7e86bSDan Gohman } 2848fe7e86bSDan Gohman 2858fe7e86bSDan Gohman // Decide where in Header to put the BLOCK. 286e76fa9ecSHeejin Ahn 287e76fa9ecSHeejin Ahn // Instructions that should go before the BLOCK. 288e76fa9ecSHeejin Ahn SmallPtrSet<const MachineInstr *, 4> BeforeSet; 289e76fa9ecSHeejin Ahn // Instructions that should go after the BLOCK. 290e76fa9ecSHeejin Ahn SmallPtrSet<const MachineInstr *, 4> AfterSet; 291e76fa9ecSHeejin Ahn for (const auto &MI : *Header) { 29244a5a4b1SHeejin Ahn // If there is a previously placed LOOP marker and the bottom block of the 29344a5a4b1SHeejin Ahn // loop is above MBB, it should be after the BLOCK, because the loop is 29444a5a4b1SHeejin Ahn // nested in this BLOCK. Otherwise it should be before the BLOCK. 29544a5a4b1SHeejin Ahn if (MI.getOpcode() == WebAssembly::LOOP) { 29644a5a4b1SHeejin Ahn auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode(); 29744a5a4b1SHeejin Ahn if (MBB.getNumber() > LoopBottom->getNumber()) 298e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 299e76fa9ecSHeejin Ahn #ifndef NDEBUG 300e76fa9ecSHeejin Ahn else 301e76fa9ecSHeejin Ahn BeforeSet.insert(&MI); 302e76fa9ecSHeejin Ahn #endif 303e76fa9ecSHeejin Ahn } 304e76fa9ecSHeejin Ahn 305834debffSHeejin Ahn // If there is a previously placed BLOCK/TRY marker and its corresponding 306834debffSHeejin Ahn // END marker is before the current BLOCK's END marker, that should be 307834debffSHeejin Ahn // placed after this BLOCK. Otherwise it should be placed before this BLOCK 308834debffSHeejin Ahn // marker. 30944a5a4b1SHeejin Ahn if (MI.getOpcode() == WebAssembly::BLOCK || 310834debffSHeejin Ahn MI.getOpcode() == WebAssembly::TRY) { 311834debffSHeejin Ahn if (BeginToEnd[&MI]->getParent()->getNumber() <= MBB.getNumber()) 312e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 313834debffSHeejin Ahn #ifndef NDEBUG 314834debffSHeejin Ahn else 315834debffSHeejin Ahn BeforeSet.insert(&MI); 316834debffSHeejin Ahn #endif 317834debffSHeejin Ahn } 318e76fa9ecSHeejin Ahn 319e76fa9ecSHeejin Ahn #ifndef NDEBUG 320e76fa9ecSHeejin Ahn // All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK. 321e76fa9ecSHeejin Ahn if (MI.getOpcode() == WebAssembly::END_BLOCK || 322e76fa9ecSHeejin Ahn MI.getOpcode() == WebAssembly::END_LOOP || 323e76fa9ecSHeejin Ahn MI.getOpcode() == WebAssembly::END_TRY) 324e76fa9ecSHeejin Ahn BeforeSet.insert(&MI); 325e76fa9ecSHeejin Ahn #endif 326e76fa9ecSHeejin Ahn 327e76fa9ecSHeejin Ahn // Terminators should go after the BLOCK. 328e76fa9ecSHeejin Ahn if (MI.isTerminator()) 329e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 330e76fa9ecSHeejin Ahn } 331e76fa9ecSHeejin Ahn 332e76fa9ecSHeejin Ahn // Local expression tree should go after the BLOCK. 333e76fa9ecSHeejin Ahn for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 334e76fa9ecSHeejin Ahn --I) { 335409b4391SYury Delendik if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 336409b4391SYury Delendik continue; 337e76fa9ecSHeejin Ahn if (WebAssembly::isChild(*std::prev(I), MFI)) 338e76fa9ecSHeejin Ahn AfterSet.insert(&*std::prev(I)); 339e76fa9ecSHeejin Ahn else 340e76fa9ecSHeejin Ahn break; 34132807932SDan Gohman } 34232807932SDan Gohman 3438fe7e86bSDan Gohman // Add the BLOCK. 344d6f48786SHeejin Ahn 3459f96a58cSHeejin Ahn // 'br_on_exn' extracts exnref object and pushes variable number of values 346d6f48786SHeejin Ahn // depending on its tag. For C++ exception, its a single i32 value, and the 347d6f48786SHeejin Ahn // generated code will be in the form of: 348d6f48786SHeejin Ahn // block i32 349d6f48786SHeejin Ahn // br_on_exn 0, $__cpp_exception 350d6f48786SHeejin Ahn // rethrow 351d6f48786SHeejin Ahn // end_block 3522cb27072SThomas Lively WebAssembly::BlockType ReturnType = WebAssembly::BlockType::Void; 353d6f48786SHeejin Ahn if (IsBrOnExn) { 354d6f48786SHeejin Ahn const char *TagName = BrOnExn->getOperand(1).getSymbolName(); 355d6f48786SHeejin Ahn if (std::strcmp(TagName, "__cpp_exception") != 0) 356d6f48786SHeejin Ahn llvm_unreachable("Only C++ exception is supported"); 3572cb27072SThomas Lively ReturnType = WebAssembly::BlockType::I32; 358d6f48786SHeejin Ahn } 359d6f48786SHeejin Ahn 36018c56a07SHeejin Ahn auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 36192401cc1SHeejin Ahn MachineInstr *Begin = 36292401cc1SHeejin Ahn BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 3632726b88cSDan Gohman TII.get(WebAssembly::BLOCK)) 364d6f48786SHeejin Ahn .addImm(int64_t(ReturnType)); 3651d68e80fSDan Gohman 366e76fa9ecSHeejin Ahn // Decide where in Header to put the END_BLOCK. 367e76fa9ecSHeejin Ahn BeforeSet.clear(); 368e76fa9ecSHeejin Ahn AfterSet.clear(); 369e76fa9ecSHeejin Ahn for (auto &MI : MBB) { 370e76fa9ecSHeejin Ahn #ifndef NDEBUG 371e76fa9ecSHeejin Ahn // END_BLOCK should precede existing LOOP and TRY markers. 372e76fa9ecSHeejin Ahn if (MI.getOpcode() == WebAssembly::LOOP || 373e76fa9ecSHeejin Ahn MI.getOpcode() == WebAssembly::TRY) 374e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 375e76fa9ecSHeejin Ahn #endif 376e76fa9ecSHeejin Ahn 377e76fa9ecSHeejin Ahn // If there is a previously placed END_LOOP marker and the header of the 378e76fa9ecSHeejin Ahn // loop is above this block's header, the END_LOOP should be placed after 379e76fa9ecSHeejin Ahn // the BLOCK, because the loop contains this block. Otherwise the END_LOOP 380e76fa9ecSHeejin Ahn // should be placed before the BLOCK. The same for END_TRY. 381e76fa9ecSHeejin Ahn if (MI.getOpcode() == WebAssembly::END_LOOP || 382e76fa9ecSHeejin Ahn MI.getOpcode() == WebAssembly::END_TRY) { 383e76fa9ecSHeejin Ahn if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 384e76fa9ecSHeejin Ahn BeforeSet.insert(&MI); 385e76fa9ecSHeejin Ahn #ifndef NDEBUG 386e76fa9ecSHeejin Ahn else 387e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 388e76fa9ecSHeejin Ahn #endif 389e76fa9ecSHeejin Ahn } 390e76fa9ecSHeejin Ahn } 391e76fa9ecSHeejin Ahn 3921d68e80fSDan Gohman // Mark the end of the block. 39318c56a07SHeejin Ahn InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 39410b31358SDerek Schuff MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 3952726b88cSDan Gohman TII.get(WebAssembly::END_BLOCK)); 396e76fa9ecSHeejin Ahn registerScope(Begin, End); 3978fe7e86bSDan Gohman 3988fe7e86bSDan Gohman // Track the farthest-spanning scope that ends at this point. 3998fe7e86bSDan Gohman int Number = MBB.getNumber(); 4008fe7e86bSDan Gohman if (!ScopeTops[Number] || 4018fe7e86bSDan Gohman ScopeTops[Number]->getNumber() > Header->getNumber()) 4028fe7e86bSDan Gohman ScopeTops[Number] = Header; 403950a13cfSDan Gohman } 404950a13cfSDan Gohman 4058fe7e86bSDan Gohman /// Insert a LOOP marker for a loop starting at MBB (if it's a loop header). 406e76fa9ecSHeejin Ahn void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) { 407e76fa9ecSHeejin Ahn MachineFunction &MF = *MBB.getParent(); 408e76fa9ecSHeejin Ahn const auto &MLI = getAnalysis<MachineLoopInfo>(); 409276f9e8cSHeejin Ahn const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 410276f9e8cSHeejin Ahn SortRegionInfo SRI(MLI, WEI); 411e76fa9ecSHeejin Ahn const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 412e76fa9ecSHeejin Ahn 4138fe7e86bSDan Gohman MachineLoop *Loop = MLI.getLoopFor(&MBB); 4148fe7e86bSDan Gohman if (!Loop || Loop->getHeader() != &MBB) 4158fe7e86bSDan Gohman return; 4168fe7e86bSDan Gohman 4178fe7e86bSDan Gohman // The operand of a LOOP is the first block after the loop. If the loop is the 4188fe7e86bSDan Gohman // bottom of the function, insert a dummy block at the end. 419276f9e8cSHeejin Ahn MachineBasicBlock *Bottom = SRI.getBottom(Loop); 4205c644c9bSHeejin Ahn auto Iter = std::next(Bottom->getIterator()); 421e3e4a5ffSDan Gohman if (Iter == MF.end()) { 422c4ac74fbSHeejin Ahn getAppendixBlock(MF); 4235c644c9bSHeejin Ahn Iter = std::next(Bottom->getIterator()); 424e3e4a5ffSDan Gohman } 4258fe7e86bSDan Gohman MachineBasicBlock *AfterLoop = &*Iter; 426f6857223SDan Gohman 427e76fa9ecSHeejin Ahn // Decide where in Header to put the LOOP. 428e76fa9ecSHeejin Ahn SmallPtrSet<const MachineInstr *, 4> BeforeSet; 429e76fa9ecSHeejin Ahn SmallPtrSet<const MachineInstr *, 4> AfterSet; 430e76fa9ecSHeejin Ahn for (const auto &MI : MBB) { 431e76fa9ecSHeejin Ahn // LOOP marker should be after any existing loop that ends here. Otherwise 432e76fa9ecSHeejin Ahn // we assume the instruction belongs to the loop. 433e76fa9ecSHeejin Ahn if (MI.getOpcode() == WebAssembly::END_LOOP) 434e76fa9ecSHeejin Ahn BeforeSet.insert(&MI); 435e76fa9ecSHeejin Ahn #ifndef NDEBUG 436e76fa9ecSHeejin Ahn else 437e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 438e76fa9ecSHeejin Ahn #endif 439e76fa9ecSHeejin Ahn } 440e76fa9ecSHeejin Ahn 441e76fa9ecSHeejin Ahn // Mark the beginning of the loop. 44218c56a07SHeejin Ahn auto InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 44310b31358SDerek Schuff MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos), 4442726b88cSDan Gohman TII.get(WebAssembly::LOOP)) 4452cb27072SThomas Lively .addImm(int64_t(WebAssembly::BlockType::Void)); 4461d68e80fSDan Gohman 447e76fa9ecSHeejin Ahn // Decide where in Header to put the END_LOOP. 448e76fa9ecSHeejin Ahn BeforeSet.clear(); 449e76fa9ecSHeejin Ahn AfterSet.clear(); 450e76fa9ecSHeejin Ahn #ifndef NDEBUG 451e76fa9ecSHeejin Ahn for (const auto &MI : MBB) 452e76fa9ecSHeejin Ahn // Existing END_LOOP markers belong to parent loops of this loop 453e76fa9ecSHeejin Ahn if (MI.getOpcode() == WebAssembly::END_LOOP) 454e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 455e76fa9ecSHeejin Ahn #endif 456e76fa9ecSHeejin Ahn 457e76fa9ecSHeejin Ahn // Mark the end of the loop (using arbitrary debug location that branched to 458e76fa9ecSHeejin Ahn // the loop end as its location). 45918c56a07SHeejin Ahn InsertPos = getEarliestInsertPos(AfterLoop, BeforeSet, AfterSet); 46067f74aceSHeejin Ahn DebugLoc EndDL = AfterLoop->pred_empty() 46167f74aceSHeejin Ahn ? DebugLoc() 46267f74aceSHeejin Ahn : (*AfterLoop->pred_rbegin())->findBranchDebugLoc(); 463e76fa9ecSHeejin Ahn MachineInstr *End = 464e76fa9ecSHeejin Ahn BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP)); 465e76fa9ecSHeejin Ahn registerScope(Begin, End); 4668fe7e86bSDan Gohman 4678fe7e86bSDan Gohman assert((!ScopeTops[AfterLoop->getNumber()] || 4688fe7e86bSDan Gohman ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && 469442bfcecSDan Gohman "With block sorting the outermost loop for a block should be first."); 4708fe7e86bSDan Gohman if (!ScopeTops[AfterLoop->getNumber()]) 4718fe7e86bSDan Gohman ScopeTops[AfterLoop->getNumber()] = &MBB; 472e3e4a5ffSDan Gohman } 473950a13cfSDan Gohman 474e76fa9ecSHeejin Ahn void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) { 47544a5a4b1SHeejin Ahn assert(MBB.isEHPad()); 476e76fa9ecSHeejin Ahn MachineFunction &MF = *MBB.getParent(); 477e76fa9ecSHeejin Ahn auto &MDT = getAnalysis<MachineDominatorTree>(); 478e76fa9ecSHeejin Ahn const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 479276f9e8cSHeejin Ahn const auto &MLI = getAnalysis<MachineLoopInfo>(); 480e76fa9ecSHeejin Ahn const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 481276f9e8cSHeejin Ahn SortRegionInfo SRI(MLI, WEI); 482e76fa9ecSHeejin Ahn const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 483e76fa9ecSHeejin Ahn 484e76fa9ecSHeejin Ahn // Compute the nearest common dominator of all unwind predecessors 485e76fa9ecSHeejin Ahn MachineBasicBlock *Header = nullptr; 486e76fa9ecSHeejin Ahn int MBBNumber = MBB.getNumber(); 487e76fa9ecSHeejin Ahn for (auto *Pred : MBB.predecessors()) { 488e76fa9ecSHeejin Ahn if (Pred->getNumber() < MBBNumber) { 489e76fa9ecSHeejin Ahn Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 49018c56a07SHeejin Ahn assert(!explicitlyBranchesTo(Pred, &MBB) && 491e76fa9ecSHeejin Ahn "Explicit branch to an EH pad!"); 492e76fa9ecSHeejin Ahn } 493e76fa9ecSHeejin Ahn } 494e76fa9ecSHeejin Ahn if (!Header) 495e76fa9ecSHeejin Ahn return; 496e76fa9ecSHeejin Ahn 497e76fa9ecSHeejin Ahn // If this try is at the bottom of the function, insert a dummy block at the 498e76fa9ecSHeejin Ahn // end. 499e76fa9ecSHeejin Ahn WebAssemblyException *WE = WEI.getExceptionFor(&MBB); 500e76fa9ecSHeejin Ahn assert(WE); 501276f9e8cSHeejin Ahn MachineBasicBlock *Bottom = SRI.getBottom(WE); 502e76fa9ecSHeejin Ahn 5035c644c9bSHeejin Ahn auto Iter = std::next(Bottom->getIterator()); 504e76fa9ecSHeejin Ahn if (Iter == MF.end()) { 505c4ac74fbSHeejin Ahn getAppendixBlock(MF); 5065c644c9bSHeejin Ahn Iter = std::next(Bottom->getIterator()); 507e76fa9ecSHeejin Ahn } 50820cf0749SHeejin Ahn MachineBasicBlock *Cont = &*Iter; 509e76fa9ecSHeejin Ahn 51020cf0749SHeejin Ahn assert(Cont != &MF.front()); 5115c644c9bSHeejin Ahn MachineBasicBlock *LayoutPred = Cont->getPrevNode(); 512e76fa9ecSHeejin Ahn 513e76fa9ecSHeejin Ahn // If the nearest common dominator is inside a more deeply nested context, 514e76fa9ecSHeejin Ahn // walk out to the nearest scope which isn't more deeply nested. 515e76fa9ecSHeejin Ahn for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 516e76fa9ecSHeejin Ahn if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 517e76fa9ecSHeejin Ahn if (ScopeTop->getNumber() > Header->getNumber()) { 518e76fa9ecSHeejin Ahn // Skip over an intervening scope. 5195c644c9bSHeejin Ahn I = std::next(ScopeTop->getIterator()); 520e76fa9ecSHeejin Ahn } else { 521e76fa9ecSHeejin Ahn // We found a scope level at an appropriate depth. 522e76fa9ecSHeejin Ahn Header = ScopeTop; 523e76fa9ecSHeejin Ahn break; 524e76fa9ecSHeejin Ahn } 525e76fa9ecSHeejin Ahn } 526e76fa9ecSHeejin Ahn } 527e76fa9ecSHeejin Ahn 528e76fa9ecSHeejin Ahn // Decide where in Header to put the TRY. 529e76fa9ecSHeejin Ahn 53044a5a4b1SHeejin Ahn // Instructions that should go before the TRY. 531e76fa9ecSHeejin Ahn SmallPtrSet<const MachineInstr *, 4> BeforeSet; 53244a5a4b1SHeejin Ahn // Instructions that should go after the TRY. 533e76fa9ecSHeejin Ahn SmallPtrSet<const MachineInstr *, 4> AfterSet; 534e76fa9ecSHeejin Ahn for (const auto &MI : *Header) { 53544a5a4b1SHeejin Ahn // If there is a previously placed LOOP marker and the bottom block of the 53644a5a4b1SHeejin Ahn // loop is above MBB, it should be after the TRY, because the loop is nested 53744a5a4b1SHeejin Ahn // in this TRY. Otherwise it should be before the TRY. 538e76fa9ecSHeejin Ahn if (MI.getOpcode() == WebAssembly::LOOP) { 53944a5a4b1SHeejin Ahn auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode(); 54044a5a4b1SHeejin Ahn if (MBB.getNumber() > LoopBottom->getNumber()) 541e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 542e76fa9ecSHeejin Ahn #ifndef NDEBUG 543e76fa9ecSHeejin Ahn else 544e76fa9ecSHeejin Ahn BeforeSet.insert(&MI); 545e76fa9ecSHeejin Ahn #endif 546e76fa9ecSHeejin Ahn } 547e76fa9ecSHeejin Ahn 54844a5a4b1SHeejin Ahn // All previously inserted BLOCK/TRY markers should be after the TRY because 54944a5a4b1SHeejin Ahn // they are all nested trys. 55044a5a4b1SHeejin Ahn if (MI.getOpcode() == WebAssembly::BLOCK || 55144a5a4b1SHeejin Ahn MI.getOpcode() == WebAssembly::TRY) 552e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 553e76fa9ecSHeejin Ahn 554e76fa9ecSHeejin Ahn #ifndef NDEBUG 55544a5a4b1SHeejin Ahn // All END_(BLOCK/LOOP/TRY) markers should be before the TRY. 55644a5a4b1SHeejin Ahn if (MI.getOpcode() == WebAssembly::END_BLOCK || 55744a5a4b1SHeejin Ahn MI.getOpcode() == WebAssembly::END_LOOP || 558e76fa9ecSHeejin Ahn MI.getOpcode() == WebAssembly::END_TRY) 559e76fa9ecSHeejin Ahn BeforeSet.insert(&MI); 560e76fa9ecSHeejin Ahn #endif 561e76fa9ecSHeejin Ahn 562e76fa9ecSHeejin Ahn // Terminators should go after the TRY. 563e76fa9ecSHeejin Ahn if (MI.isTerminator()) 564e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 565e76fa9ecSHeejin Ahn } 566e76fa9ecSHeejin Ahn 5676a37c5d6SHeejin Ahn // If Header unwinds to MBB (= Header contains 'invoke'), the try block should 5686a37c5d6SHeejin Ahn // contain the call within it. So the call should go after the TRY. The 5696a37c5d6SHeejin Ahn // exception is when the header's terminator is a rethrow instruction, in 5706a37c5d6SHeejin Ahn // which case that instruction, not a call instruction before it, is gonna 5716a37c5d6SHeejin Ahn // throw. 5726a37c5d6SHeejin Ahn MachineInstr *ThrowingCall = nullptr; 5736a37c5d6SHeejin Ahn if (MBB.isPredecessor(Header)) { 5746a37c5d6SHeejin Ahn auto TermPos = Header->getFirstTerminator(); 5756a37c5d6SHeejin Ahn if (TermPos == Header->end() || 5766a37c5d6SHeejin Ahn TermPos->getOpcode() != WebAssembly::RETHROW) { 5776a37c5d6SHeejin Ahn for (auto &MI : reverse(*Header)) { 5786a37c5d6SHeejin Ahn if (MI.isCall()) { 5796a37c5d6SHeejin Ahn AfterSet.insert(&MI); 5806a37c5d6SHeejin Ahn ThrowingCall = &MI; 5816a37c5d6SHeejin Ahn // Possibly throwing calls are usually wrapped by EH_LABEL 5826a37c5d6SHeejin Ahn // instructions. We don't want to split them and the call. 5836a37c5d6SHeejin Ahn if (MI.getIterator() != Header->begin() && 5846a37c5d6SHeejin Ahn std::prev(MI.getIterator())->isEHLabel()) { 5856a37c5d6SHeejin Ahn AfterSet.insert(&*std::prev(MI.getIterator())); 5866a37c5d6SHeejin Ahn ThrowingCall = &*std::prev(MI.getIterator()); 5876a37c5d6SHeejin Ahn } 5886a37c5d6SHeejin Ahn break; 5896a37c5d6SHeejin Ahn } 5906a37c5d6SHeejin Ahn } 5916a37c5d6SHeejin Ahn } 5926a37c5d6SHeejin Ahn } 5936a37c5d6SHeejin Ahn 594e76fa9ecSHeejin Ahn // Local expression tree should go after the TRY. 5956a37c5d6SHeejin Ahn // For BLOCK placement, we start the search from the previous instruction of a 5966a37c5d6SHeejin Ahn // BB's terminator, but in TRY's case, we should start from the previous 5976a37c5d6SHeejin Ahn // instruction of a call that can throw, or a EH_LABEL that precedes the call, 5986a37c5d6SHeejin Ahn // because the return values of the call's previous instructions can be 5996a37c5d6SHeejin Ahn // stackified and consumed by the throwing call. 6006a37c5d6SHeejin Ahn auto SearchStartPt = ThrowingCall ? MachineBasicBlock::iterator(ThrowingCall) 6016a37c5d6SHeejin Ahn : Header->getFirstTerminator(); 6026a37c5d6SHeejin Ahn for (auto I = SearchStartPt, E = Header->begin(); I != E; --I) { 603409b4391SYury Delendik if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 604409b4391SYury Delendik continue; 605e76fa9ecSHeejin Ahn if (WebAssembly::isChild(*std::prev(I), MFI)) 606e76fa9ecSHeejin Ahn AfterSet.insert(&*std::prev(I)); 607e76fa9ecSHeejin Ahn else 608e76fa9ecSHeejin Ahn break; 609e76fa9ecSHeejin Ahn } 610e76fa9ecSHeejin Ahn 611e76fa9ecSHeejin Ahn // Add the TRY. 61218c56a07SHeejin Ahn auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 613e76fa9ecSHeejin Ahn MachineInstr *Begin = 614e76fa9ecSHeejin Ahn BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 615e76fa9ecSHeejin Ahn TII.get(WebAssembly::TRY)) 6162cb27072SThomas Lively .addImm(int64_t(WebAssembly::BlockType::Void)); 617e76fa9ecSHeejin Ahn 618e76fa9ecSHeejin Ahn // Decide where in Header to put the END_TRY. 619e76fa9ecSHeejin Ahn BeforeSet.clear(); 620e76fa9ecSHeejin Ahn AfterSet.clear(); 62120cf0749SHeejin Ahn for (const auto &MI : *Cont) { 622e76fa9ecSHeejin Ahn #ifndef NDEBUG 62344a5a4b1SHeejin Ahn // END_TRY should precede existing LOOP and BLOCK markers. 62444a5a4b1SHeejin Ahn if (MI.getOpcode() == WebAssembly::LOOP || 62544a5a4b1SHeejin Ahn MI.getOpcode() == WebAssembly::BLOCK) 626e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 627e76fa9ecSHeejin Ahn 628e76fa9ecSHeejin Ahn // All END_TRY markers placed earlier belong to exceptions that contains 629e76fa9ecSHeejin Ahn // this one. 630e76fa9ecSHeejin Ahn if (MI.getOpcode() == WebAssembly::END_TRY) 631e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 632e76fa9ecSHeejin Ahn #endif 633e76fa9ecSHeejin Ahn 634e76fa9ecSHeejin Ahn // If there is a previously placed END_LOOP marker and its header is after 635e76fa9ecSHeejin Ahn // where TRY marker is, this loop is contained within the 'catch' part, so 636e76fa9ecSHeejin Ahn // the END_TRY marker should go after that. Otherwise, the whole try-catch 637e76fa9ecSHeejin Ahn // is contained within this loop, so the END_TRY should go before that. 638e76fa9ecSHeejin Ahn if (MI.getOpcode() == WebAssembly::END_LOOP) { 639222718fdSHeejin Ahn // For a LOOP to be after TRY, LOOP's BB should be after TRY's BB; if they 640222718fdSHeejin Ahn // are in the same BB, LOOP is always before TRY. 641222718fdSHeejin Ahn if (EndToBegin[&MI]->getParent()->getNumber() > Header->getNumber()) 642e76fa9ecSHeejin Ahn BeforeSet.insert(&MI); 643e76fa9ecSHeejin Ahn #ifndef NDEBUG 644e76fa9ecSHeejin Ahn else 645e76fa9ecSHeejin Ahn AfterSet.insert(&MI); 646e76fa9ecSHeejin Ahn #endif 647e76fa9ecSHeejin Ahn } 64844a5a4b1SHeejin Ahn 64944a5a4b1SHeejin Ahn // It is not possible for an END_BLOCK to be already in this block. 650e76fa9ecSHeejin Ahn } 651e76fa9ecSHeejin Ahn 652e76fa9ecSHeejin Ahn // Mark the end of the TRY. 65320cf0749SHeejin Ahn InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet); 654e76fa9ecSHeejin Ahn MachineInstr *End = 65520cf0749SHeejin Ahn BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(), 656e76fa9ecSHeejin Ahn TII.get(WebAssembly::END_TRY)); 657e76fa9ecSHeejin Ahn registerTryScope(Begin, End, &MBB); 658e76fa9ecSHeejin Ahn 65982da1ffcSHeejin Ahn // Track the farthest-spanning scope that ends at this point. We create two 66082da1ffcSHeejin Ahn // mappings: (BB with 'end_try' -> BB with 'try') and (BB with 'catch' -> BB 66182da1ffcSHeejin Ahn // with 'try'). We need to create 'catch' -> 'try' mapping here too because 66282da1ffcSHeejin Ahn // markers should not span across 'catch'. For example, this should not 66382da1ffcSHeejin Ahn // happen: 66482da1ffcSHeejin Ahn // 66582da1ffcSHeejin Ahn // try 66682da1ffcSHeejin Ahn // block --| (X) 66782da1ffcSHeejin Ahn // catch | 66882da1ffcSHeejin Ahn // end_block --| 66982da1ffcSHeejin Ahn // end_try 67082da1ffcSHeejin Ahn for (int Number : {Cont->getNumber(), MBB.getNumber()}) { 671e76fa9ecSHeejin Ahn if (!ScopeTops[Number] || 672e76fa9ecSHeejin Ahn ScopeTops[Number]->getNumber() > Header->getNumber()) 673e76fa9ecSHeejin Ahn ScopeTops[Number] = Header; 674e76fa9ecSHeejin Ahn } 67582da1ffcSHeejin Ahn } 676e76fa9ecSHeejin Ahn 677cf699b45SHeejin Ahn void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) { 678cf699b45SHeejin Ahn const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 679cf699b45SHeejin Ahn 680cf699b45SHeejin Ahn // When there is an unconditional branch right before a catch instruction and 681cf699b45SHeejin Ahn // it branches to the end of end_try marker, we don't need the branch, because 682cf699b45SHeejin Ahn // it there is no exception, the control flow transfers to that point anyway. 683cf699b45SHeejin Ahn // bb0: 684cf699b45SHeejin Ahn // try 685cf699b45SHeejin Ahn // ... 686cf699b45SHeejin Ahn // br bb2 <- Not necessary 687cf699b45SHeejin Ahn // bb1: 688cf699b45SHeejin Ahn // catch 689cf699b45SHeejin Ahn // ... 690cf699b45SHeejin Ahn // bb2: 691cf699b45SHeejin Ahn // end 692cf699b45SHeejin Ahn for (auto &MBB : MF) { 693cf699b45SHeejin Ahn if (!MBB.isEHPad()) 694cf699b45SHeejin Ahn continue; 695cf699b45SHeejin Ahn 696cf699b45SHeejin Ahn MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 697cf699b45SHeejin Ahn SmallVector<MachineOperand, 4> Cond; 6985c644c9bSHeejin Ahn MachineBasicBlock *EHPadLayoutPred = MBB.getPrevNode(); 699cf699b45SHeejin Ahn MachineBasicBlock *Cont = BeginToEnd[EHPadToTry[&MBB]]->getParent(); 700cf699b45SHeejin Ahn bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond); 7013fe6ea46SHeejin Ahn // This condition means either 7023fe6ea46SHeejin Ahn // 1. This BB ends with a single unconditional branch whose destinaion is 7033fe6ea46SHeejin Ahn // Cont. 7043fe6ea46SHeejin Ahn // 2. This BB ends with a conditional branch followed by an unconditional 7053fe6ea46SHeejin Ahn // branch, and the unconditional branch's destination is Cont. 7063fe6ea46SHeejin Ahn // In both cases, we want to remove the last (= unconditional) branch. 707cf699b45SHeejin Ahn if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) || 7083fe6ea46SHeejin Ahn (!Cond.empty() && FBB && FBB == Cont))) { 7093fe6ea46SHeejin Ahn bool ErasedUncondBr = false; 710a5099ad9SHeejin Ahn (void)ErasedUncondBr; 7113fe6ea46SHeejin Ahn for (auto I = EHPadLayoutPred->end(), E = EHPadLayoutPred->begin(); 7123fe6ea46SHeejin Ahn I != E; --I) { 7133fe6ea46SHeejin Ahn auto PrevI = std::prev(I); 7143fe6ea46SHeejin Ahn if (PrevI->isTerminator()) { 7153fe6ea46SHeejin Ahn assert(PrevI->getOpcode() == WebAssembly::BR); 7163fe6ea46SHeejin Ahn PrevI->eraseFromParent(); 7173fe6ea46SHeejin Ahn ErasedUncondBr = true; 7183fe6ea46SHeejin Ahn break; 7193fe6ea46SHeejin Ahn } 7203fe6ea46SHeejin Ahn } 7213fe6ea46SHeejin Ahn assert(ErasedUncondBr && "Unconditional branch not erased!"); 7223fe6ea46SHeejin Ahn } 723cf699b45SHeejin Ahn } 724cf699b45SHeejin Ahn 725cf699b45SHeejin Ahn // When there are block / end_block markers that overlap with try / end_try 726cf699b45SHeejin Ahn // markers, and the block and try markers' return types are the same, the 727cf699b45SHeejin Ahn // block /end_block markers are not necessary, because try / end_try markers 728cf699b45SHeejin Ahn // also can serve as boundaries for branches. 729cf699b45SHeejin Ahn // block <- Not necessary 730cf699b45SHeejin Ahn // try 731cf699b45SHeejin Ahn // ... 732cf699b45SHeejin Ahn // catch 733cf699b45SHeejin Ahn // ... 734cf699b45SHeejin Ahn // end 735cf699b45SHeejin Ahn // end <- Not necessary 736cf699b45SHeejin Ahn SmallVector<MachineInstr *, 32> ToDelete; 737cf699b45SHeejin Ahn for (auto &MBB : MF) { 738cf699b45SHeejin Ahn for (auto &MI : MBB) { 739cf699b45SHeejin Ahn if (MI.getOpcode() != WebAssembly::TRY) 740cf699b45SHeejin Ahn continue; 741cf699b45SHeejin Ahn 742cf699b45SHeejin Ahn MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try]; 743cf699b45SHeejin Ahn MachineBasicBlock *TryBB = Try->getParent(); 744cf699b45SHeejin Ahn MachineBasicBlock *Cont = EndTry->getParent(); 745cf699b45SHeejin Ahn int64_t RetType = Try->getOperand(0).getImm(); 7465c644c9bSHeejin Ahn for (auto B = Try->getIterator(), E = std::next(EndTry->getIterator()); 747cf699b45SHeejin Ahn B != TryBB->begin() && E != Cont->end() && 748cf699b45SHeejin Ahn std::prev(B)->getOpcode() == WebAssembly::BLOCK && 749cf699b45SHeejin Ahn E->getOpcode() == WebAssembly::END_BLOCK && 750cf699b45SHeejin Ahn std::prev(B)->getOperand(0).getImm() == RetType; 751cf699b45SHeejin Ahn --B, ++E) { 752cf699b45SHeejin Ahn ToDelete.push_back(&*std::prev(B)); 753cf699b45SHeejin Ahn ToDelete.push_back(&*E); 754cf699b45SHeejin Ahn } 755cf699b45SHeejin Ahn } 756cf699b45SHeejin Ahn } 757cf699b45SHeejin Ahn for (auto *MI : ToDelete) { 758cf699b45SHeejin Ahn if (MI->getOpcode() == WebAssembly::BLOCK) 759cf699b45SHeejin Ahn unregisterScope(MI); 760cf699b45SHeejin Ahn MI->eraseFromParent(); 761cf699b45SHeejin Ahn } 762cf699b45SHeejin Ahn } 763cf699b45SHeejin Ahn 76483c26eaeSHeejin Ahn // Get the appropriate copy opcode for the given register class. 76583c26eaeSHeejin Ahn static unsigned getCopyOpcode(const TargetRegisterClass *RC) { 76683c26eaeSHeejin Ahn if (RC == &WebAssembly::I32RegClass) 76783c26eaeSHeejin Ahn return WebAssembly::COPY_I32; 76883c26eaeSHeejin Ahn if (RC == &WebAssembly::I64RegClass) 76983c26eaeSHeejin Ahn return WebAssembly::COPY_I64; 77083c26eaeSHeejin Ahn if (RC == &WebAssembly::F32RegClass) 77183c26eaeSHeejin Ahn return WebAssembly::COPY_F32; 77283c26eaeSHeejin Ahn if (RC == &WebAssembly::F64RegClass) 77383c26eaeSHeejin Ahn return WebAssembly::COPY_F64; 77483c26eaeSHeejin Ahn if (RC == &WebAssembly::V128RegClass) 77583c26eaeSHeejin Ahn return WebAssembly::COPY_V128; 776*60653e24SHeejin Ahn if (RC == &WebAssembly::FUNCREFRegClass) 777*60653e24SHeejin Ahn return WebAssembly::COPY_FUNCREF; 778*60653e24SHeejin Ahn if (RC == &WebAssembly::EXTERNREFRegClass) 779*60653e24SHeejin Ahn return WebAssembly::COPY_EXTERNREF; 78083c26eaeSHeejin Ahn if (RC == &WebAssembly::EXNREFRegClass) 78183c26eaeSHeejin Ahn return WebAssembly::COPY_EXNREF; 78283c26eaeSHeejin Ahn llvm_unreachable("Unexpected register class"); 78383c26eaeSHeejin Ahn } 78483c26eaeSHeejin Ahn 78561d5c76aSHeejin Ahn // When MBB is split into MBB and Split, we should unstackify defs in MBB that 78661d5c76aSHeejin Ahn // have their uses in Split. 78761d5c76aSHeejin Ahn static void unstackifyVRegsUsedInSplitBB(MachineBasicBlock &MBB, 78861d5c76aSHeejin Ahn MachineBasicBlock &Split, 78961d5c76aSHeejin Ahn WebAssemblyFunctionInfo &MFI, 79083c26eaeSHeejin Ahn MachineRegisterInfo &MRI, 79183c26eaeSHeejin Ahn const WebAssemblyInstrInfo &TII) { 79261d5c76aSHeejin Ahn for (auto &MI : Split) { 79361d5c76aSHeejin Ahn for (auto &MO : MI.explicit_uses()) { 79461d5c76aSHeejin Ahn if (!MO.isReg() || Register::isPhysicalRegister(MO.getReg())) 79561d5c76aSHeejin Ahn continue; 79661d5c76aSHeejin Ahn if (MachineInstr *Def = MRI.getUniqueVRegDef(MO.getReg())) 79761d5c76aSHeejin Ahn if (Def->getParent() == &MBB) 79861d5c76aSHeejin Ahn MFI.unstackifyVReg(MO.getReg()); 79961d5c76aSHeejin Ahn } 80061d5c76aSHeejin Ahn } 80183c26eaeSHeejin Ahn 80283c26eaeSHeejin Ahn // In RegStackify, when a register definition is used multiple times, 80383c26eaeSHeejin Ahn // Reg = INST ... 80483c26eaeSHeejin Ahn // INST ..., Reg, ... 80583c26eaeSHeejin Ahn // INST ..., Reg, ... 80683c26eaeSHeejin Ahn // INST ..., Reg, ... 80783c26eaeSHeejin Ahn // 80883c26eaeSHeejin Ahn // we introduce a TEE, which has the following form: 80983c26eaeSHeejin Ahn // DefReg = INST ... 81083c26eaeSHeejin Ahn // TeeReg, Reg = TEE_... DefReg 81183c26eaeSHeejin Ahn // INST ..., TeeReg, ... 81283c26eaeSHeejin Ahn // INST ..., Reg, ... 81383c26eaeSHeejin Ahn // INST ..., Reg, ... 81483c26eaeSHeejin Ahn // with DefReg and TeeReg stackified but Reg not stackified. 81583c26eaeSHeejin Ahn // 81683c26eaeSHeejin Ahn // But the invariant that TeeReg should be stackified can be violated while we 81783c26eaeSHeejin Ahn // unstackify registers in the split BB above. In this case, we convert TEEs 81883c26eaeSHeejin Ahn // into two COPYs. This COPY will be eventually eliminated in ExplicitLocals. 81983c26eaeSHeejin Ahn // DefReg = INST ... 82083c26eaeSHeejin Ahn // TeeReg = COPY DefReg 82183c26eaeSHeejin Ahn // Reg = COPY DefReg 82283c26eaeSHeejin Ahn // INST ..., TeeReg, ... 82383c26eaeSHeejin Ahn // INST ..., Reg, ... 82483c26eaeSHeejin Ahn // INST ..., Reg, ... 82583c26eaeSHeejin Ahn for (auto I = MBB.begin(), E = MBB.end(); I != E;) { 82683c26eaeSHeejin Ahn MachineInstr &MI = *I++; 82783c26eaeSHeejin Ahn if (!WebAssembly::isTee(MI.getOpcode())) 82883c26eaeSHeejin Ahn continue; 82983c26eaeSHeejin Ahn Register TeeReg = MI.getOperand(0).getReg(); 83083c26eaeSHeejin Ahn Register Reg = MI.getOperand(1).getReg(); 83183c26eaeSHeejin Ahn Register DefReg = MI.getOperand(2).getReg(); 83283c26eaeSHeejin Ahn if (!MFI.isVRegStackified(TeeReg)) { 83383c26eaeSHeejin Ahn // Now we are not using TEE anymore, so unstackify DefReg too 83483c26eaeSHeejin Ahn MFI.unstackifyVReg(DefReg); 83583c26eaeSHeejin Ahn unsigned CopyOpc = getCopyOpcode(MRI.getRegClass(DefReg)); 83683c26eaeSHeejin Ahn BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), TeeReg) 83783c26eaeSHeejin Ahn .addReg(DefReg); 83883c26eaeSHeejin Ahn BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), Reg).addReg(DefReg); 83983c26eaeSHeejin Ahn MI.eraseFromParent(); 84083c26eaeSHeejin Ahn } 84183c26eaeSHeejin Ahn } 84261d5c76aSHeejin Ahn } 84361d5c76aSHeejin Ahn 844c4ac74fbSHeejin Ahn bool WebAssemblyCFGStackify::fixUnwindMismatches(MachineFunction &MF) { 845c4ac74fbSHeejin Ahn const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 84661d5c76aSHeejin Ahn auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 847c4ac74fbSHeejin Ahn MachineRegisterInfo &MRI = MF.getRegInfo(); 848c4ac74fbSHeejin Ahn 849c4ac74fbSHeejin Ahn // Linearizing the control flow by placing TRY / END_TRY markers can create 850c4ac74fbSHeejin Ahn // mismatches in unwind destinations. There are two kinds of mismatches we 851c4ac74fbSHeejin Ahn // try to solve here. 852c4ac74fbSHeejin Ahn 853c4ac74fbSHeejin Ahn // 1. When an instruction may throw, but the EH pad it will unwind to can be 854c4ac74fbSHeejin Ahn // different from the original CFG. 855c4ac74fbSHeejin Ahn // 856c4ac74fbSHeejin Ahn // Example: we have the following CFG: 857c4ac74fbSHeejin Ahn // bb0: 858c4ac74fbSHeejin Ahn // call @foo (if it throws, unwind to bb2) 859c4ac74fbSHeejin Ahn // bb1: 860c4ac74fbSHeejin Ahn // call @bar (if it throws, unwind to bb3) 861c4ac74fbSHeejin Ahn // bb2 (ehpad): 862c4ac74fbSHeejin Ahn // catch 863c4ac74fbSHeejin Ahn // ... 864c4ac74fbSHeejin Ahn // bb3 (ehpad) 865c4ac74fbSHeejin Ahn // catch 866c4ac74fbSHeejin Ahn // handler body 867c4ac74fbSHeejin Ahn // 868c4ac74fbSHeejin Ahn // And the CFG is sorted in this order. Then after placing TRY markers, it 869c4ac74fbSHeejin Ahn // will look like: (BB markers are omitted) 870c4ac74fbSHeejin Ahn // try $label1 871c4ac74fbSHeejin Ahn // try 872c4ac74fbSHeejin Ahn // call @foo 873c4ac74fbSHeejin Ahn // call @bar (if it throws, unwind to bb3) 874c4ac74fbSHeejin Ahn // catch <- ehpad (bb2) 875c4ac74fbSHeejin Ahn // ... 876c4ac74fbSHeejin Ahn // end_try 877c4ac74fbSHeejin Ahn // catch <- ehpad (bb3) 878c4ac74fbSHeejin Ahn // handler body 879c4ac74fbSHeejin Ahn // end_try 880c4ac74fbSHeejin Ahn // 881c4ac74fbSHeejin Ahn // Now if bar() throws, it is going to end up ip in bb2, not bb3, where it 882c4ac74fbSHeejin Ahn // is supposed to end up. We solve this problem by 883c4ac74fbSHeejin Ahn // a. Split the target unwind EH pad (here bb3) so that the handler body is 884c4ac74fbSHeejin Ahn // right after 'end_try', which means we extract the handler body out of 885c4ac74fbSHeejin Ahn // the catch block. We do this because this handler body should be 886c4ac74fbSHeejin Ahn // somewhere branch-eable from the inner scope. 887c4ac74fbSHeejin Ahn // b. Wrap the call that has an incorrect unwind destination ('call @bar' 888c4ac74fbSHeejin Ahn // here) with a nested try/catch/end_try scope, and within the new catch 889c4ac74fbSHeejin Ahn // block, branches to the handler body. 890c4ac74fbSHeejin Ahn // c. Place a branch after the newly inserted nested end_try so it can bypass 891c4ac74fbSHeejin Ahn // the handler body, which is now outside of a catch block. 892c4ac74fbSHeejin Ahn // 893c4ac74fbSHeejin Ahn // The result will like as follows. (new: a) means this instruction is newly 894c4ac74fbSHeejin Ahn // created in the process of doing 'a' above. 895c4ac74fbSHeejin Ahn // 896c4ac74fbSHeejin Ahn // block $label0 (new: placeBlockMarker) 897c4ac74fbSHeejin Ahn // try $label1 898c4ac74fbSHeejin Ahn // try 899c4ac74fbSHeejin Ahn // call @foo 900c4ac74fbSHeejin Ahn // try (new: b) 901c4ac74fbSHeejin Ahn // call @bar 902c4ac74fbSHeejin Ahn // catch (new: b) 903c4ac74fbSHeejin Ahn // local.set n / drop (new: b) 904c4ac74fbSHeejin Ahn // br $label1 (new: b) 905c4ac74fbSHeejin Ahn // end_try (new: b) 906c4ac74fbSHeejin Ahn // catch <- ehpad (bb2) 907c4ac74fbSHeejin Ahn // end_try 908c4ac74fbSHeejin Ahn // br $label0 (new: c) 909c4ac74fbSHeejin Ahn // catch <- ehpad (bb3) 910c4ac74fbSHeejin Ahn // end_try (hoisted: a) 911c4ac74fbSHeejin Ahn // handler body 912c4ac74fbSHeejin Ahn // end_block (new: placeBlockMarker) 913c4ac74fbSHeejin Ahn // 914c4ac74fbSHeejin Ahn // Note that the new wrapping block/end_block will be generated later in 915c4ac74fbSHeejin Ahn // placeBlockMarker. 916c4ac74fbSHeejin Ahn // 9179f96a58cSHeejin Ahn // TODO Currently local.set and local.gets are generated to move exnref value 9189f96a58cSHeejin Ahn // created by catches. That's because we don't support yielding values from a 9199f96a58cSHeejin Ahn // block in LLVM machine IR yet, even though it is supported by wasm. Delete 9209f96a58cSHeejin Ahn // unnecessary local.get/local.sets once yielding values from a block is 9219f96a58cSHeejin Ahn // supported. The full EH spec requires multi-value support to do this, but 922c4ac74fbSHeejin Ahn // for C++ we don't yet need it because we only throw a single i32. 923c4ac74fbSHeejin Ahn // 924c4ac74fbSHeejin Ahn // --- 925c4ac74fbSHeejin Ahn // 2. The same as 1, but in this case an instruction unwinds to a caller 926c4ac74fbSHeejin Ahn // function and not another EH pad. 927c4ac74fbSHeejin Ahn // 928c4ac74fbSHeejin Ahn // Example: we have the following CFG: 929c4ac74fbSHeejin Ahn // bb0: 930c4ac74fbSHeejin Ahn // call @foo (if it throws, unwind to bb2) 931c4ac74fbSHeejin Ahn // bb1: 932c4ac74fbSHeejin Ahn // call @bar (if it throws, unwind to caller) 933c4ac74fbSHeejin Ahn // bb2 (ehpad): 934c4ac74fbSHeejin Ahn // catch 935c4ac74fbSHeejin Ahn // ... 936c4ac74fbSHeejin Ahn // 937c4ac74fbSHeejin Ahn // And the CFG is sorted in this order. Then after placing TRY markers, it 938c4ac74fbSHeejin Ahn // will look like: 939c4ac74fbSHeejin Ahn // try 940c4ac74fbSHeejin Ahn // call @foo 941c4ac74fbSHeejin Ahn // call @bar (if it throws, unwind to caller) 942c4ac74fbSHeejin Ahn // catch <- ehpad (bb2) 943c4ac74fbSHeejin Ahn // ... 944c4ac74fbSHeejin Ahn // end_try 945c4ac74fbSHeejin Ahn // 946c4ac74fbSHeejin Ahn // Now if bar() throws, it is going to end up ip in bb2, when it is supposed 947c4ac74fbSHeejin Ahn // throw up to the caller. 948c4ac74fbSHeejin Ahn // We solve this problem by 949c4ac74fbSHeejin Ahn // a. Create a new 'appendix' BB at the end of the function and put a single 950c4ac74fbSHeejin Ahn // 'rethrow' instruction (+ local.get) in there. 951c4ac74fbSHeejin Ahn // b. Wrap the call that has an incorrect unwind destination ('call @bar' 952c4ac74fbSHeejin Ahn // here) with a nested try/catch/end_try scope, and within the new catch 953c4ac74fbSHeejin Ahn // block, branches to the new appendix block. 954c4ac74fbSHeejin Ahn // 955c4ac74fbSHeejin Ahn // block $label0 (new: placeBlockMarker) 956c4ac74fbSHeejin Ahn // try 957c4ac74fbSHeejin Ahn // call @foo 958c4ac74fbSHeejin Ahn // try (new: b) 959c4ac74fbSHeejin Ahn // call @bar 960c4ac74fbSHeejin Ahn // catch (new: b) 961c4ac74fbSHeejin Ahn // local.set n (new: b) 962c4ac74fbSHeejin Ahn // br $label0 (new: b) 963c4ac74fbSHeejin Ahn // end_try (new: b) 964c4ac74fbSHeejin Ahn // catch <- ehpad (bb2) 965c4ac74fbSHeejin Ahn // ... 966c4ac74fbSHeejin Ahn // end_try 967c4ac74fbSHeejin Ahn // ... 968c4ac74fbSHeejin Ahn // end_block (new: placeBlockMarker) 969c4ac74fbSHeejin Ahn // local.get n (new: a) <- appendix block 970c4ac74fbSHeejin Ahn // rethrow (new: a) 971c4ac74fbSHeejin Ahn // 972c4ac74fbSHeejin Ahn // In case there are multiple calls in a BB that may throw to the caller, they 973c4ac74fbSHeejin Ahn // can be wrapped together in one nested try scope. (In 1, this couldn't 974c4ac74fbSHeejin Ahn // happen, because may-throwing instruction there had an unwind destination, 975c4ac74fbSHeejin Ahn // i.e., it was an invoke before, and there could be only one invoke within a 976c4ac74fbSHeejin Ahn // BB.) 977c4ac74fbSHeejin Ahn 978c4ac74fbSHeejin Ahn SmallVector<const MachineBasicBlock *, 8> EHPadStack; 979c4ac74fbSHeejin Ahn // Range of intructions to be wrapped in a new nested try/catch 980c4ac74fbSHeejin Ahn using TryRange = std::pair<MachineInstr *, MachineInstr *>; 981daeead4bSHeejin Ahn // In original CFG, <unwind destination BB, a vector of try ranges> 982c4ac74fbSHeejin Ahn DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> UnwindDestToTryRanges; 983c4ac74fbSHeejin Ahn // In new CFG, <destination to branch to, a vector of try ranges> 984c4ac74fbSHeejin Ahn DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> BrDestToTryRanges; 9859f96a58cSHeejin Ahn // In new CFG, <destination to branch to, register containing exnref> 986c4ac74fbSHeejin Ahn DenseMap<MachineBasicBlock *, unsigned> BrDestToExnReg; 987c4ac74fbSHeejin Ahn 988834debffSHeejin Ahn // Destinations for branches that will be newly added, for which a new 989834debffSHeejin Ahn // BLOCK/END_BLOCK markers are necessary. 990834debffSHeejin Ahn SmallVector<MachineBasicBlock *, 8> BrDests; 991834debffSHeejin Ahn 992c4ac74fbSHeejin Ahn // Gather possibly throwing calls (i.e., previously invokes) whose current 993c4ac74fbSHeejin Ahn // unwind destination is not the same as the original CFG. 994c4ac74fbSHeejin Ahn for (auto &MBB : reverse(MF)) { 995c4ac74fbSHeejin Ahn bool SeenThrowableInstInBB = false; 996c4ac74fbSHeejin Ahn for (auto &MI : reverse(MBB)) { 997c4ac74fbSHeejin Ahn if (MI.getOpcode() == WebAssembly::TRY) 998c4ac74fbSHeejin Ahn EHPadStack.pop_back(); 999c4ac74fbSHeejin Ahn else if (MI.getOpcode() == WebAssembly::CATCH) 1000c4ac74fbSHeejin Ahn EHPadStack.push_back(MI.getParent()); 1001c4ac74fbSHeejin Ahn 1002c4ac74fbSHeejin Ahn // In this loop we only gather calls that have an EH pad to unwind. So 1003c4ac74fbSHeejin Ahn // there will be at most 1 such call (= invoke) in a BB, so after we've 1004c4ac74fbSHeejin Ahn // seen one, we can skip the rest of BB. Also if MBB has no EH pad 1005c4ac74fbSHeejin Ahn // successor or MI does not throw, this is not an invoke. 1006c4ac74fbSHeejin Ahn if (SeenThrowableInstInBB || !MBB.hasEHPadSuccessor() || 1007c4ac74fbSHeejin Ahn !WebAssembly::mayThrow(MI)) 1008c4ac74fbSHeejin Ahn continue; 1009c4ac74fbSHeejin Ahn SeenThrowableInstInBB = true; 1010c4ac74fbSHeejin Ahn 1011c4ac74fbSHeejin Ahn // If the EH pad on the stack top is where this instruction should unwind 1012c4ac74fbSHeejin Ahn // next, we're good. 1013c4ac74fbSHeejin Ahn MachineBasicBlock *UnwindDest = nullptr; 1014c4ac74fbSHeejin Ahn for (auto *Succ : MBB.successors()) { 1015c4ac74fbSHeejin Ahn if (Succ->isEHPad()) { 1016c4ac74fbSHeejin Ahn UnwindDest = Succ; 1017c4ac74fbSHeejin Ahn break; 1018c4ac74fbSHeejin Ahn } 1019c4ac74fbSHeejin Ahn } 1020c4ac74fbSHeejin Ahn if (EHPadStack.back() == UnwindDest) 1021c4ac74fbSHeejin Ahn continue; 1022c4ac74fbSHeejin Ahn 1023c4ac74fbSHeejin Ahn // If not, record the range. 1024c4ac74fbSHeejin Ahn UnwindDestToTryRanges[UnwindDest].push_back(TryRange(&MI, &MI)); 1025c4ac74fbSHeejin Ahn } 1026c4ac74fbSHeejin Ahn } 1027c4ac74fbSHeejin Ahn 1028c4ac74fbSHeejin Ahn assert(EHPadStack.empty()); 1029c4ac74fbSHeejin Ahn 1030c4ac74fbSHeejin Ahn // Gather possibly throwing calls that are supposed to unwind up to the caller 1031c4ac74fbSHeejin Ahn // if they throw, but currently unwind to an incorrect destination. Unlike the 1032c4ac74fbSHeejin Ahn // loop above, there can be multiple calls within a BB that unwind to the 1033c4ac74fbSHeejin Ahn // caller, which we should group together in a range. 1034c4ac74fbSHeejin Ahn bool NeedAppendixBlock = false; 1035c4ac74fbSHeejin Ahn for (auto &MBB : reverse(MF)) { 1036c4ac74fbSHeejin Ahn MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; // inclusive 1037c4ac74fbSHeejin Ahn for (auto &MI : reverse(MBB)) { 1038c4ac74fbSHeejin Ahn if (MI.getOpcode() == WebAssembly::TRY) 1039c4ac74fbSHeejin Ahn EHPadStack.pop_back(); 1040c4ac74fbSHeejin Ahn else if (MI.getOpcode() == WebAssembly::CATCH) 1041c4ac74fbSHeejin Ahn EHPadStack.push_back(MI.getParent()); 1042c4ac74fbSHeejin Ahn 1043c4ac74fbSHeejin Ahn // If MBB has an EH pad successor, this inst does not unwind to caller. 1044c4ac74fbSHeejin Ahn if (MBB.hasEHPadSuccessor()) 1045c4ac74fbSHeejin Ahn continue; 1046c4ac74fbSHeejin Ahn 1047c4ac74fbSHeejin Ahn // We wrap up the current range when we see a marker even if we haven't 1048c4ac74fbSHeejin Ahn // finished a BB. 1049d8ddf839SWouter van Oortmerssen if (RangeEnd && WebAssembly::isMarker(MI.getOpcode())) { 1050c4ac74fbSHeejin Ahn NeedAppendixBlock = true; 1051c4ac74fbSHeejin Ahn // Record the range. nullptr here means the unwind destination is the 1052c4ac74fbSHeejin Ahn // caller. 1053c4ac74fbSHeejin Ahn UnwindDestToTryRanges[nullptr].push_back( 1054c4ac74fbSHeejin Ahn TryRange(RangeBegin, RangeEnd)); 1055c4ac74fbSHeejin Ahn RangeBegin = RangeEnd = nullptr; // Reset range pointers 1056c4ac74fbSHeejin Ahn } 1057c4ac74fbSHeejin Ahn 1058c4ac74fbSHeejin Ahn // If EHPadStack is empty, that means it is correctly unwind to caller if 1059c4ac74fbSHeejin Ahn // it throws, so we're good. If MI does not throw, we're good too. 1060c4ac74fbSHeejin Ahn if (EHPadStack.empty() || !WebAssembly::mayThrow(MI)) 1061c4ac74fbSHeejin Ahn continue; 1062c4ac74fbSHeejin Ahn 1063c4ac74fbSHeejin Ahn // We found an instruction that unwinds to the caller but currently has an 1064c4ac74fbSHeejin Ahn // incorrect unwind destination. Create a new range or increment the 1065c4ac74fbSHeejin Ahn // currently existing range. 1066c4ac74fbSHeejin Ahn if (!RangeEnd) 1067c4ac74fbSHeejin Ahn RangeBegin = RangeEnd = &MI; 1068c4ac74fbSHeejin Ahn else 1069c4ac74fbSHeejin Ahn RangeBegin = &MI; 1070c4ac74fbSHeejin Ahn } 1071c4ac74fbSHeejin Ahn 1072c4ac74fbSHeejin Ahn if (RangeEnd) { 1073c4ac74fbSHeejin Ahn NeedAppendixBlock = true; 1074c4ac74fbSHeejin Ahn // Record the range. nullptr here means the unwind destination is the 1075c4ac74fbSHeejin Ahn // caller. 1076c4ac74fbSHeejin Ahn UnwindDestToTryRanges[nullptr].push_back(TryRange(RangeBegin, RangeEnd)); 1077c4ac74fbSHeejin Ahn RangeBegin = RangeEnd = nullptr; // Reset range pointers 1078c4ac74fbSHeejin Ahn } 1079c4ac74fbSHeejin Ahn } 1080c4ac74fbSHeejin Ahn 1081c4ac74fbSHeejin Ahn assert(EHPadStack.empty()); 1082c4ac74fbSHeejin Ahn // We don't have any unwind destination mismatches to resolve. 1083c4ac74fbSHeejin Ahn if (UnwindDestToTryRanges.empty()) 1084c4ac74fbSHeejin Ahn return false; 1085c4ac74fbSHeejin Ahn 1086c4ac74fbSHeejin Ahn // If we found instructions that should unwind to the caller but currently 1087c4ac74fbSHeejin Ahn // have incorrect unwind destination, we create an appendix block at the end 1088c4ac74fbSHeejin Ahn // of the function with a local.get and a rethrow instruction. 1089c4ac74fbSHeejin Ahn if (NeedAppendixBlock) { 1090c4ac74fbSHeejin Ahn auto *AppendixBB = getAppendixBlock(MF); 109105c145d6SDaniel Sanders Register ExnReg = MRI.createVirtualRegister(&WebAssembly::EXNREFRegClass); 1092c4ac74fbSHeejin Ahn BuildMI(AppendixBB, DebugLoc(), TII.get(WebAssembly::RETHROW)) 1093c4ac74fbSHeejin Ahn .addReg(ExnReg); 1094c4ac74fbSHeejin Ahn // These instruction ranges should branch to this appendix BB. 1095c4ac74fbSHeejin Ahn for (auto Range : UnwindDestToTryRanges[nullptr]) 1096c4ac74fbSHeejin Ahn BrDestToTryRanges[AppendixBB].push_back(Range); 1097c4ac74fbSHeejin Ahn BrDestToExnReg[AppendixBB] = ExnReg; 1098c4ac74fbSHeejin Ahn } 1099c4ac74fbSHeejin Ahn 1100c4ac74fbSHeejin Ahn // We loop through unwind destination EH pads that are targeted from some 1101c4ac74fbSHeejin Ahn // inner scopes. Because these EH pads are destination of more than one scope 1102c4ac74fbSHeejin Ahn // now, we split them so that the handler body is after 'end_try'. 1103c4ac74fbSHeejin Ahn // - Before 1104c4ac74fbSHeejin Ahn // ehpad: 1105c4ac74fbSHeejin Ahn // catch 1106c4ac74fbSHeejin Ahn // local.set n / drop 1107c4ac74fbSHeejin Ahn // handler body 1108c4ac74fbSHeejin Ahn // ... 1109c4ac74fbSHeejin Ahn // cont: 1110c4ac74fbSHeejin Ahn // end_try 1111c4ac74fbSHeejin Ahn // 1112c4ac74fbSHeejin Ahn // - After 1113c4ac74fbSHeejin Ahn // ehpad: 1114c4ac74fbSHeejin Ahn // catch 1115c4ac74fbSHeejin Ahn // local.set n / drop 1116c4ac74fbSHeejin Ahn // brdest: (new) 1117c4ac74fbSHeejin Ahn // end_try (hoisted from 'cont' BB) 1118c4ac74fbSHeejin Ahn // handler body (taken from 'ehpad') 1119c4ac74fbSHeejin Ahn // ... 1120c4ac74fbSHeejin Ahn // cont: 1121c4ac74fbSHeejin Ahn for (auto &P : UnwindDestToTryRanges) { 1122daeead4bSHeejin Ahn NumUnwindMismatches += P.second.size(); 1123c4ac74fbSHeejin Ahn 1124c4ac74fbSHeejin Ahn // This means the destination is the appendix BB, which was separately 1125c4ac74fbSHeejin Ahn // handled above. 1126c4ac74fbSHeejin Ahn if (!P.first) 1127c4ac74fbSHeejin Ahn continue; 1128c4ac74fbSHeejin Ahn 1129c4ac74fbSHeejin Ahn MachineBasicBlock *EHPad = P.first; 1130d25c17f3SHeejin Ahn Register ExnReg = 0; 1131d25c17f3SHeejin Ahn MachineInstr *Catch = findCatch(EHPad, ExnReg); 1132c4ac74fbSHeejin Ahn auto SplitPos = std::next(Catch->getIterator()); 1133c4ac74fbSHeejin Ahn 1134c4ac74fbSHeejin Ahn // Create a new BB that's gonna be the destination for branches from the 1135c4ac74fbSHeejin Ahn // inner mismatched scope. 1136c4ac74fbSHeejin Ahn MachineInstr *BeginTry = EHPadToTry[EHPad]; 1137c4ac74fbSHeejin Ahn MachineInstr *EndTry = BeginToEnd[BeginTry]; 1138c4ac74fbSHeejin Ahn MachineBasicBlock *Cont = EndTry->getParent(); 1139c4ac74fbSHeejin Ahn auto *BrDest = MF.CreateMachineBasicBlock(); 1140c4ac74fbSHeejin Ahn MF.insert(std::next(EHPad->getIterator()), BrDest); 1141c4ac74fbSHeejin Ahn // Hoist up the existing 'end_try'. 1142c4ac74fbSHeejin Ahn BrDest->insert(BrDest->end(), EndTry->removeFromParent()); 1143c4ac74fbSHeejin Ahn // Take out the handler body from EH pad to the new branch destination BB. 1144c4ac74fbSHeejin Ahn BrDest->splice(BrDest->end(), EHPad, SplitPos, EHPad->end()); 114583c26eaeSHeejin Ahn unstackifyVRegsUsedInSplitBB(*EHPad, *BrDest, MFI, MRI, TII); 1146c4ac74fbSHeejin Ahn // Fix predecessor-successor relationship. 1147c4ac74fbSHeejin Ahn BrDest->transferSuccessors(EHPad); 1148c4ac74fbSHeejin Ahn EHPad->addSuccessor(BrDest); 1149c4ac74fbSHeejin Ahn 1150c4ac74fbSHeejin Ahn // All try ranges that were supposed to unwind to this EH pad now have to 1151c4ac74fbSHeejin Ahn // branch to this new branch dest BB. 1152c4ac74fbSHeejin Ahn for (auto Range : UnwindDestToTryRanges[EHPad]) 1153c4ac74fbSHeejin Ahn BrDestToTryRanges[BrDest].push_back(Range); 1154c4ac74fbSHeejin Ahn BrDestToExnReg[BrDest] = ExnReg; 1155c4ac74fbSHeejin Ahn 1156c4ac74fbSHeejin Ahn // In case we fall through to the continuation BB after the catch block, we 1157c4ac74fbSHeejin Ahn // now have to add a branch to it. 1158c4ac74fbSHeejin Ahn // - Before 1159c4ac74fbSHeejin Ahn // try 1160c4ac74fbSHeejin Ahn // ... 1161c4ac74fbSHeejin Ahn // (falls through to 'cont') 1162c4ac74fbSHeejin Ahn // catch 1163c4ac74fbSHeejin Ahn // handler body 1164c4ac74fbSHeejin Ahn // end 1165c4ac74fbSHeejin Ahn // <-- cont 1166c4ac74fbSHeejin Ahn // 1167c4ac74fbSHeejin Ahn // - After 1168c4ac74fbSHeejin Ahn // try 1169c4ac74fbSHeejin Ahn // ... 1170c4ac74fbSHeejin Ahn // br %cont (new) 1171c4ac74fbSHeejin Ahn // catch 1172c4ac74fbSHeejin Ahn // end 1173c4ac74fbSHeejin Ahn // handler body 1174c4ac74fbSHeejin Ahn // <-- cont 1175c4ac74fbSHeejin Ahn MachineBasicBlock *EHPadLayoutPred = &*std::prev(EHPad->getIterator()); 1176c4ac74fbSHeejin Ahn MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 1177c4ac74fbSHeejin Ahn SmallVector<MachineOperand, 4> Cond; 1178c4ac74fbSHeejin Ahn bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond); 1179c4ac74fbSHeejin Ahn if (Analyzable && !TBB && !FBB) { 1180c4ac74fbSHeejin Ahn DebugLoc DL = EHPadLayoutPred->empty() 1181c4ac74fbSHeejin Ahn ? DebugLoc() 1182c4ac74fbSHeejin Ahn : EHPadLayoutPred->rbegin()->getDebugLoc(); 1183c4ac74fbSHeejin Ahn BuildMI(EHPadLayoutPred, DL, TII.get(WebAssembly::BR)).addMBB(Cont); 1184834debffSHeejin Ahn BrDests.push_back(Cont); 1185c4ac74fbSHeejin Ahn } 1186c4ac74fbSHeejin Ahn } 1187c4ac74fbSHeejin Ahn 1188c4ac74fbSHeejin Ahn // For possibly throwing calls whose unwind destinations are currently 1189c4ac74fbSHeejin Ahn // incorrect because of CFG linearization, we wrap them with a nested 1190c4ac74fbSHeejin Ahn // try/catch/end_try, and within the new catch block, we branch to the correct 1191c4ac74fbSHeejin Ahn // handler. 1192c4ac74fbSHeejin Ahn // - Before 1193c4ac74fbSHeejin Ahn // mbb: 1194c4ac74fbSHeejin Ahn // call @foo <- Unwind destination mismatch! 1195c4ac74fbSHeejin Ahn // ehpad: 1196c4ac74fbSHeejin Ahn // ... 1197c4ac74fbSHeejin Ahn // 1198c4ac74fbSHeejin Ahn // - After 1199c4ac74fbSHeejin Ahn // mbb: 1200c4ac74fbSHeejin Ahn // try (new) 1201c4ac74fbSHeejin Ahn // call @foo 1202c4ac74fbSHeejin Ahn // nested-ehpad: (new) 1203c4ac74fbSHeejin Ahn // catch (new) 1204c4ac74fbSHeejin Ahn // local.set n / drop (new) 1205c4ac74fbSHeejin Ahn // br %brdest (new) 1206c4ac74fbSHeejin Ahn // nested-end: (new) 1207c4ac74fbSHeejin Ahn // end_try (new) 1208c4ac74fbSHeejin Ahn // ehpad: 1209c4ac74fbSHeejin Ahn // ... 1210c4ac74fbSHeejin Ahn for (auto &P : BrDestToTryRanges) { 1211c4ac74fbSHeejin Ahn MachineBasicBlock *BrDest = P.first; 1212c4ac74fbSHeejin Ahn auto &TryRanges = P.second; 1213c4ac74fbSHeejin Ahn unsigned ExnReg = BrDestToExnReg[BrDest]; 1214c4ac74fbSHeejin Ahn 1215c4ac74fbSHeejin Ahn for (auto Range : TryRanges) { 1216c4ac74fbSHeejin Ahn MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; 1217c4ac74fbSHeejin Ahn std::tie(RangeBegin, RangeEnd) = Range; 1218c4ac74fbSHeejin Ahn auto *MBB = RangeBegin->getParent(); 1219ba40896fSHeejin Ahn // Store the first function call from this range, because RangeBegin can 1220ba40896fSHeejin Ahn // be moved to point EH_LABEL before the call 1221ba40896fSHeejin Ahn MachineInstr *RangeBeginCall = RangeBegin; 1222c4ac74fbSHeejin Ahn 1223c4ac74fbSHeejin Ahn // Include possible EH_LABELs in the range 1224c4ac74fbSHeejin Ahn if (RangeBegin->getIterator() != MBB->begin() && 1225c4ac74fbSHeejin Ahn std::prev(RangeBegin->getIterator())->isEHLabel()) 1226c4ac74fbSHeejin Ahn RangeBegin = &*std::prev(RangeBegin->getIterator()); 1227c4ac74fbSHeejin Ahn if (std::next(RangeEnd->getIterator()) != MBB->end() && 1228c4ac74fbSHeejin Ahn std::next(RangeEnd->getIterator())->isEHLabel()) 1229c4ac74fbSHeejin Ahn RangeEnd = &*std::next(RangeEnd->getIterator()); 1230c4ac74fbSHeejin Ahn 1231c4ac74fbSHeejin Ahn MachineBasicBlock *EHPad = nullptr; 1232c4ac74fbSHeejin Ahn for (auto *Succ : MBB->successors()) { 1233c4ac74fbSHeejin Ahn if (Succ->isEHPad()) { 1234c4ac74fbSHeejin Ahn EHPad = Succ; 1235c4ac74fbSHeejin Ahn break; 1236c4ac74fbSHeejin Ahn } 1237c4ac74fbSHeejin Ahn } 1238c4ac74fbSHeejin Ahn 1239ba40896fSHeejin Ahn // Local expression tree before the first call of this range should go 1240ba40896fSHeejin Ahn // after the nested TRY. 1241ba40896fSHeejin Ahn SmallPtrSet<const MachineInstr *, 4> AfterSet; 1242ba40896fSHeejin Ahn AfterSet.insert(RangeBegin); 1243ba40896fSHeejin Ahn AfterSet.insert(RangeBeginCall); 1244ba40896fSHeejin Ahn for (auto I = MachineBasicBlock::iterator(RangeBeginCall), 1245ba40896fSHeejin Ahn E = MBB->begin(); 1246ba40896fSHeejin Ahn I != E; --I) { 1247ba40896fSHeejin Ahn if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 1248ba40896fSHeejin Ahn continue; 1249ba40896fSHeejin Ahn if (WebAssembly::isChild(*std::prev(I), MFI)) 1250ba40896fSHeejin Ahn AfterSet.insert(&*std::prev(I)); 1251ba40896fSHeejin Ahn else 1252ba40896fSHeejin Ahn break; 1253ba40896fSHeejin Ahn } 1254ba40896fSHeejin Ahn 1255c4ac74fbSHeejin Ahn // Create the nested try instruction. 1256ba40896fSHeejin Ahn auto InsertPos = getLatestInsertPos( 1257ba40896fSHeejin Ahn MBB, SmallPtrSet<const MachineInstr *, 4>(), AfterSet); 1258c4ac74fbSHeejin Ahn MachineInstr *NestedTry = 1259ba40896fSHeejin Ahn BuildMI(*MBB, InsertPos, RangeBegin->getDebugLoc(), 1260c4ac74fbSHeejin Ahn TII.get(WebAssembly::TRY)) 12612cb27072SThomas Lively .addImm(int64_t(WebAssembly::BlockType::Void)); 1262c4ac74fbSHeejin Ahn 1263c4ac74fbSHeejin Ahn // Create the nested EH pad and fill instructions in. 1264c4ac74fbSHeejin Ahn MachineBasicBlock *NestedEHPad = MF.CreateMachineBasicBlock(); 1265c4ac74fbSHeejin Ahn MF.insert(std::next(MBB->getIterator()), NestedEHPad); 1266c4ac74fbSHeejin Ahn NestedEHPad->setIsEHPad(); 1267c4ac74fbSHeejin Ahn NestedEHPad->setIsEHScopeEntry(); 1268c4ac74fbSHeejin Ahn BuildMI(NestedEHPad, RangeEnd->getDebugLoc(), TII.get(WebAssembly::CATCH), 1269c4ac74fbSHeejin Ahn ExnReg); 1270c4ac74fbSHeejin Ahn BuildMI(NestedEHPad, RangeEnd->getDebugLoc(), TII.get(WebAssembly::BR)) 1271c4ac74fbSHeejin Ahn .addMBB(BrDest); 1272c4ac74fbSHeejin Ahn 1273c4ac74fbSHeejin Ahn // Create the nested continuation BB and end_try instruction. 1274c4ac74fbSHeejin Ahn MachineBasicBlock *NestedCont = MF.CreateMachineBasicBlock(); 1275c4ac74fbSHeejin Ahn MF.insert(std::next(NestedEHPad->getIterator()), NestedCont); 1276c4ac74fbSHeejin Ahn MachineInstr *NestedEndTry = 1277c4ac74fbSHeejin Ahn BuildMI(*NestedCont, NestedCont->begin(), RangeEnd->getDebugLoc(), 1278c4ac74fbSHeejin Ahn TII.get(WebAssembly::END_TRY)); 1279c4ac74fbSHeejin Ahn // In case MBB has more instructions after the try range, move them to the 1280c4ac74fbSHeejin Ahn // new nested continuation BB. 1281c4ac74fbSHeejin Ahn NestedCont->splice(NestedCont->end(), MBB, 1282c4ac74fbSHeejin Ahn std::next(RangeEnd->getIterator()), MBB->end()); 128383c26eaeSHeejin Ahn unstackifyVRegsUsedInSplitBB(*MBB, *NestedCont, MFI, MRI, TII); 1284c4ac74fbSHeejin Ahn registerTryScope(NestedTry, NestedEndTry, NestedEHPad); 1285c4ac74fbSHeejin Ahn 1286c4ac74fbSHeejin Ahn // Fix predecessor-successor relationship. 1287c4ac74fbSHeejin Ahn NestedCont->transferSuccessors(MBB); 1288834debffSHeejin Ahn if (EHPad) { 1289c4ac74fbSHeejin Ahn NestedCont->removeSuccessor(EHPad); 1290834debffSHeejin Ahn // If EHPad does not have any predecessors left after removing 1291834debffSHeejin Ahn // NextedCont predecessor, remove its successor too, because this EHPad 1292834debffSHeejin Ahn // is not reachable from the entry BB anyway. We can't remove EHPad BB 1293834debffSHeejin Ahn // itself because it can contain 'catch' or 'end', which are necessary 1294834debffSHeejin Ahn // for keeping try-catch-end structure. 1295834debffSHeejin Ahn if (EHPad->pred_empty()) 1296834debffSHeejin Ahn EHPad->removeSuccessor(BrDest); 1297834debffSHeejin Ahn } 1298c4ac74fbSHeejin Ahn MBB->addSuccessor(NestedEHPad); 1299c4ac74fbSHeejin Ahn MBB->addSuccessor(NestedCont); 1300c4ac74fbSHeejin Ahn NestedEHPad->addSuccessor(BrDest); 1301c4ac74fbSHeejin Ahn } 1302c4ac74fbSHeejin Ahn } 1303c4ac74fbSHeejin Ahn 1304c4ac74fbSHeejin Ahn // Renumber BBs and recalculate ScopeTop info because new BBs might have been 1305c4ac74fbSHeejin Ahn // created and inserted above. 1306c4ac74fbSHeejin Ahn MF.RenumberBlocks(); 1307c4ac74fbSHeejin Ahn ScopeTops.clear(); 1308c4ac74fbSHeejin Ahn ScopeTops.resize(MF.getNumBlockIDs()); 1309c4ac74fbSHeejin Ahn for (auto &MBB : reverse(MF)) { 1310c4ac74fbSHeejin Ahn for (auto &MI : reverse(MBB)) { 1311c4ac74fbSHeejin Ahn if (ScopeTops[MBB.getNumber()]) 1312c4ac74fbSHeejin Ahn break; 1313c4ac74fbSHeejin Ahn switch (MI.getOpcode()) { 1314c4ac74fbSHeejin Ahn case WebAssembly::END_BLOCK: 1315c4ac74fbSHeejin Ahn case WebAssembly::END_LOOP: 1316c4ac74fbSHeejin Ahn case WebAssembly::END_TRY: 1317c4ac74fbSHeejin Ahn ScopeTops[MBB.getNumber()] = EndToBegin[&MI]->getParent(); 1318c4ac74fbSHeejin Ahn break; 1319c4ac74fbSHeejin Ahn case WebAssembly::CATCH: 1320c4ac74fbSHeejin Ahn ScopeTops[MBB.getNumber()] = EHPadToTry[&MBB]->getParent(); 1321c4ac74fbSHeejin Ahn break; 1322c4ac74fbSHeejin Ahn } 1323c4ac74fbSHeejin Ahn } 1324c4ac74fbSHeejin Ahn } 1325c4ac74fbSHeejin Ahn 1326c4ac74fbSHeejin Ahn // Recompute the dominator tree. 1327c4ac74fbSHeejin Ahn getAnalysis<MachineDominatorTree>().runOnMachineFunction(MF); 1328c4ac74fbSHeejin Ahn 1329834debffSHeejin Ahn // Place block markers for newly added branches, if necessary. 1330834debffSHeejin Ahn 1331834debffSHeejin Ahn // If we've created an appendix BB and a branch to it, place a block/end_block 1332834debffSHeejin Ahn // marker for that. For some new branches, those branch destination BBs start 1333834debffSHeejin Ahn // with a hoisted end_try marker, so we don't need a new marker there. 1334834debffSHeejin Ahn if (AppendixBB) 1335834debffSHeejin Ahn BrDests.push_back(AppendixBB); 1336834debffSHeejin Ahn 1337c4ac74fbSHeejin Ahn llvm::sort(BrDests, 1338c4ac74fbSHeejin Ahn [&](const MachineBasicBlock *A, const MachineBasicBlock *B) { 1339c4ac74fbSHeejin Ahn auto ANum = A->getNumber(); 1340c4ac74fbSHeejin Ahn auto BNum = B->getNumber(); 1341c4ac74fbSHeejin Ahn return ANum < BNum; 1342c4ac74fbSHeejin Ahn }); 1343c4ac74fbSHeejin Ahn for (auto *Dest : BrDests) 1344c4ac74fbSHeejin Ahn placeBlockMarker(*Dest); 1345c4ac74fbSHeejin Ahn 1346c4ac74fbSHeejin Ahn return true; 1347c4ac74fbSHeejin Ahn } 1348c4ac74fbSHeejin Ahn 13491d68e80fSDan Gohman static unsigned 135018c56a07SHeejin Ahn getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack, 13511d68e80fSDan Gohman const MachineBasicBlock *MBB) { 13521d68e80fSDan Gohman unsigned Depth = 0; 13531d68e80fSDan Gohman for (auto X : reverse(Stack)) { 13541d68e80fSDan Gohman if (X == MBB) 13551d68e80fSDan Gohman break; 13561d68e80fSDan Gohman ++Depth; 13571d68e80fSDan Gohman } 13581d68e80fSDan Gohman assert(Depth < Stack.size() && "Branch destination should be in scope"); 13591d68e80fSDan Gohman return Depth; 13601d68e80fSDan Gohman } 13611d68e80fSDan Gohman 13622726b88cSDan Gohman /// In normal assembly languages, when the end of a function is unreachable, 13632726b88cSDan Gohman /// because the function ends in an infinite loop or a noreturn call or similar, 13642726b88cSDan Gohman /// it isn't necessary to worry about the function return type at the end of 13652726b88cSDan Gohman /// the function, because it's never reached. However, in WebAssembly, blocks 13662726b88cSDan Gohman /// that end at the function end need to have a return type signature that 13672726b88cSDan Gohman /// matches the function signature, even though it's unreachable. This function 13682726b88cSDan Gohman /// checks for such cases and fixes up the signatures. 1369e76fa9ecSHeejin Ahn void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) { 1370e76fa9ecSHeejin Ahn const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 13712726b88cSDan Gohman 13722726b88cSDan Gohman if (MFI.getResults().empty()) 13732726b88cSDan Gohman return; 13742726b88cSDan Gohman 13752cb27072SThomas Lively // MCInstLower will add the proper types to multivalue signatures based on the 13762cb27072SThomas Lively // function return type 13772cb27072SThomas Lively WebAssembly::BlockType RetType = 13782cb27072SThomas Lively MFI.getResults().size() > 1 13792cb27072SThomas Lively ? WebAssembly::BlockType::Multivalue 13802cb27072SThomas Lively : WebAssembly::BlockType( 13812cb27072SThomas Lively WebAssembly::toValType(MFI.getResults().front())); 13822726b88cSDan Gohman 1383d25c17f3SHeejin Ahn SmallVector<MachineBasicBlock::reverse_iterator, 4> Worklist; 1384d25c17f3SHeejin Ahn Worklist.push_back(MF.rbegin()->rbegin()); 1385d25c17f3SHeejin Ahn 1386d25c17f3SHeejin Ahn auto Process = [&](MachineBasicBlock::reverse_iterator It) { 1387d25c17f3SHeejin Ahn auto *MBB = It->getParent(); 1388d25c17f3SHeejin Ahn while (It != MBB->rend()) { 1389d25c17f3SHeejin Ahn MachineInstr &MI = *It++; 1390801bf7ebSShiva Chen if (MI.isPosition() || MI.isDebugInstr()) 13912726b88cSDan Gohman continue; 13922cb27072SThomas Lively switch (MI.getOpcode()) { 1393d25c17f3SHeejin Ahn case WebAssembly::END_TRY: { 1394d25c17f3SHeejin Ahn // If a 'try''s return type is fixed, both its try body and catch body 1395d25c17f3SHeejin Ahn // should satisfy the return type, so we need to search 'end' 1396d25c17f3SHeejin Ahn // instructions before its corresponding 'catch' too. 1397d25c17f3SHeejin Ahn auto *EHPad = TryToEHPad.lookup(EndToBegin[&MI]); 1398d25c17f3SHeejin Ahn assert(EHPad); 1399d25c17f3SHeejin Ahn Worklist.push_back(std::next(findCatch(EHPad)->getReverseIterator())); 1400d25c17f3SHeejin Ahn LLVM_FALLTHROUGH; 1401d25c17f3SHeejin Ahn } 14022cb27072SThomas Lively case WebAssembly::END_BLOCK: 14032cb27072SThomas Lively case WebAssembly::END_LOOP: 140418c56a07SHeejin Ahn EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 14052726b88cSDan Gohman continue; 14062cb27072SThomas Lively default: 1407d25c17f3SHeejin Ahn // Something other than an `end`. We're done for this BB. 14082726b88cSDan Gohman return; 14092726b88cSDan Gohman } 14102726b88cSDan Gohman } 1411d25c17f3SHeejin Ahn // We've reached the beginning of a BB. Continue the search in the previous 1412d25c17f3SHeejin Ahn // BB. 1413d25c17f3SHeejin Ahn Worklist.push_back(MBB->getPrevNode()->rbegin()); 1414d25c17f3SHeejin Ahn }; 1415d25c17f3SHeejin Ahn 1416d25c17f3SHeejin Ahn while (!Worklist.empty()) 1417d25c17f3SHeejin Ahn Process(Worklist.pop_back_val()); 14182cb27072SThomas Lively } 14192726b88cSDan Gohman 1420d934cb88SDan Gohman // WebAssembly functions end with an end instruction, as if the function body 1421d934cb88SDan Gohman // were a block. 142218c56a07SHeejin Ahn static void appendEndToFunction(MachineFunction &MF, 1423d934cb88SDan Gohman const WebAssemblyInstrInfo &TII) { 142410b31358SDerek Schuff BuildMI(MF.back(), MF.back().end(), 142510b31358SDerek Schuff MF.back().findPrevDebugLoc(MF.back().end()), 1426d934cb88SDan Gohman TII.get(WebAssembly::END_FUNCTION)); 1427d934cb88SDan Gohman } 1428d934cb88SDan Gohman 1429e76fa9ecSHeejin Ahn /// Insert LOOP/TRY/BLOCK markers at appropriate places. 1430e76fa9ecSHeejin Ahn void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) { 1431e76fa9ecSHeejin Ahn // We allocate one more than the number of blocks in the function to 1432e76fa9ecSHeejin Ahn // accommodate for the possible fake block we may insert at the end. 1433e76fa9ecSHeejin Ahn ScopeTops.resize(MF.getNumBlockIDs() + 1); 14348fe7e86bSDan Gohman // Place the LOOP for MBB if MBB is the header of a loop. 1435e76fa9ecSHeejin Ahn for (auto &MBB : MF) 1436e76fa9ecSHeejin Ahn placeLoopMarker(MBB); 143744a5a4b1SHeejin Ahn 1438d6f48786SHeejin Ahn const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 143944a5a4b1SHeejin Ahn for (auto &MBB : MF) { 144044a5a4b1SHeejin Ahn if (MBB.isEHPad()) { 144144a5a4b1SHeejin Ahn // Place the TRY for MBB if MBB is the EH pad of an exception. 1442e76fa9ecSHeejin Ahn if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 1443e76fa9ecSHeejin Ahn MF.getFunction().hasPersonalityFn()) 1444e76fa9ecSHeejin Ahn placeTryMarker(MBB); 144544a5a4b1SHeejin Ahn } else { 144632807932SDan Gohman // Place the BLOCK for MBB if MBB is branched to from above. 1447e76fa9ecSHeejin Ahn placeBlockMarker(MBB); 1448950a13cfSDan Gohman } 144944a5a4b1SHeejin Ahn } 1450c4ac74fbSHeejin Ahn // Fix mismatches in unwind destinations induced by linearizing the code. 1451daeead4bSHeejin Ahn if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 1452daeead4bSHeejin Ahn MF.getFunction().hasPersonalityFn()) 1453c4ac74fbSHeejin Ahn fixUnwindMismatches(MF); 145444a5a4b1SHeejin Ahn } 1455950a13cfSDan Gohman 1456e76fa9ecSHeejin Ahn void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) { 14571d68e80fSDan Gohman // Now rewrite references to basic blocks to be depth immediates. 14581d68e80fSDan Gohman SmallVector<const MachineBasicBlock *, 8> Stack; 14591d68e80fSDan Gohman for (auto &MBB : reverse(MF)) { 1460e76fa9ecSHeejin Ahn for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) { 1461e76fa9ecSHeejin Ahn MachineInstr &MI = *I; 14621d68e80fSDan Gohman switch (MI.getOpcode()) { 14631d68e80fSDan Gohman case WebAssembly::BLOCK: 1464e76fa9ecSHeejin Ahn case WebAssembly::TRY: 1465e76fa9ecSHeejin Ahn assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= 1466e76fa9ecSHeejin Ahn MBB.getNumber() && 1467e76fa9ecSHeejin Ahn "Block/try marker should be balanced"); 1468e76fa9ecSHeejin Ahn Stack.pop_back(); 1469e76fa9ecSHeejin Ahn break; 1470e76fa9ecSHeejin Ahn 14711d68e80fSDan Gohman case WebAssembly::LOOP: 14721d68e80fSDan Gohman assert(Stack.back() == &MBB && "Loop top should be balanced"); 14731d68e80fSDan Gohman Stack.pop_back(); 14741d68e80fSDan Gohman break; 1475e76fa9ecSHeejin Ahn 14761d68e80fSDan Gohman case WebAssembly::END_BLOCK: 1477e76fa9ecSHeejin Ahn case WebAssembly::END_TRY: 14781d68e80fSDan Gohman Stack.push_back(&MBB); 14791d68e80fSDan Gohman break; 1480e76fa9ecSHeejin Ahn 14811d68e80fSDan Gohman case WebAssembly::END_LOOP: 1482e76fa9ecSHeejin Ahn Stack.push_back(EndToBegin[&MI]->getParent()); 14831d68e80fSDan Gohman break; 1484e76fa9ecSHeejin Ahn 14851d68e80fSDan Gohman default: 14861d68e80fSDan Gohman if (MI.isTerminator()) { 14871d68e80fSDan Gohman // Rewrite MBB operands to be depth immediates. 14881d68e80fSDan Gohman SmallVector<MachineOperand, 4> Ops(MI.operands()); 14891d68e80fSDan Gohman while (MI.getNumOperands() > 0) 14901d68e80fSDan Gohman MI.RemoveOperand(MI.getNumOperands() - 1); 14911d68e80fSDan Gohman for (auto MO : Ops) { 14921d68e80fSDan Gohman if (MO.isMBB()) 149318c56a07SHeejin Ahn MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB())); 14941d68e80fSDan Gohman MI.addOperand(MF, MO); 149532807932SDan Gohman } 14961d68e80fSDan Gohman } 14971d68e80fSDan Gohman break; 14981d68e80fSDan Gohman } 14991d68e80fSDan Gohman } 15001d68e80fSDan Gohman } 15011d68e80fSDan Gohman assert(Stack.empty() && "Control flow should be balanced"); 1502e76fa9ecSHeejin Ahn } 15032726b88cSDan Gohman 1504e76fa9ecSHeejin Ahn void WebAssemblyCFGStackify::releaseMemory() { 1505e76fa9ecSHeejin Ahn ScopeTops.clear(); 1506e76fa9ecSHeejin Ahn BeginToEnd.clear(); 1507e76fa9ecSHeejin Ahn EndToBegin.clear(); 1508e76fa9ecSHeejin Ahn TryToEHPad.clear(); 1509e76fa9ecSHeejin Ahn EHPadToTry.clear(); 1510c4ac74fbSHeejin Ahn AppendixBB = nullptr; 15111d68e80fSDan Gohman } 151232807932SDan Gohman 1513950a13cfSDan Gohman bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 1514d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n" 1515950a13cfSDan Gohman "********** Function: " 1516950a13cfSDan Gohman << MF.getName() << '\n'); 1517cf699b45SHeejin Ahn const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 1518950a13cfSDan Gohman 1519e76fa9ecSHeejin Ahn releaseMemory(); 1520e76fa9ecSHeejin Ahn 1521e040533eSDan Gohman // Liveness is not tracked for VALUE_STACK physreg. 15229c3bf318SDerek Schuff MF.getRegInfo().invalidateLiveness(); 1523950a13cfSDan Gohman 1524e76fa9ecSHeejin Ahn // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes. 1525e76fa9ecSHeejin Ahn placeMarkers(MF); 1526e76fa9ecSHeejin Ahn 1527c4ac74fbSHeejin Ahn // Remove unnecessary instructions possibly introduced by try/end_trys. 1528cf699b45SHeejin Ahn if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 1529cf699b45SHeejin Ahn MF.getFunction().hasPersonalityFn()) 1530cf699b45SHeejin Ahn removeUnnecessaryInstrs(MF); 1531cf699b45SHeejin Ahn 1532e76fa9ecSHeejin Ahn // Convert MBB operands in terminators to relative depth immediates. 1533e76fa9ecSHeejin Ahn rewriteDepthImmediates(MF); 1534e76fa9ecSHeejin Ahn 1535e76fa9ecSHeejin Ahn // Fix up block/loop/try signatures at the end of the function to conform to 1536e76fa9ecSHeejin Ahn // WebAssembly's rules. 1537e76fa9ecSHeejin Ahn fixEndsAtEndOfFunction(MF); 1538e76fa9ecSHeejin Ahn 1539e76fa9ecSHeejin Ahn // Add an end instruction at the end of the function body. 1540e76fa9ecSHeejin Ahn const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1541e76fa9ecSHeejin Ahn if (!MF.getSubtarget<WebAssemblySubtarget>() 1542e76fa9ecSHeejin Ahn .getTargetTriple() 1543e76fa9ecSHeejin Ahn .isOSBinFormatELF()) 154418c56a07SHeejin Ahn appendEndToFunction(MF, TII); 154532807932SDan Gohman 15461aaa481fSHeejin Ahn MF.getInfo<WebAssemblyFunctionInfo>()->setCFGStackified(); 1547950a13cfSDan Gohman return true; 1548950a13cfSDan Gohman } 1549