10b57cec5SDimitry Andric //=== WebAssemblyLateEHPrepare.cpp - WebAssembly Exception Preparation -===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// \brief Does various transformations for exception handling. 110b57cec5SDimitry Andric /// 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 150b57cec5SDimitry Andric #include "WebAssembly.h" 160b57cec5SDimitry Andric #include "WebAssemblySubtarget.h" 170b57cec5SDimitry Andric #include "WebAssemblyUtilities.h" 18*e8d8bef9SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/WasmEHFuncInfo.h" 210b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 228bcb0991SDimitry Andric #include "llvm/Support/Debug.h" 235ffd83dbSDimitry Andric #include "llvm/Target/TargetMachine.h" 240b57cec5SDimitry Andric using namespace llvm; 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-late-eh-prepare" 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace { 290b57cec5SDimitry Andric class WebAssemblyLateEHPrepare final : public MachineFunctionPass { 300b57cec5SDimitry Andric StringRef getPassName() const override { 310b57cec5SDimitry Andric return "WebAssembly Late Prepare Exception"; 320b57cec5SDimitry Andric } 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 35*e8d8bef9SDimitry Andric bool removeUnreachableEHPads(MachineFunction &MF); 365ffd83dbSDimitry Andric void recordCatchRetBBs(MachineFunction &MF); 37*e8d8bef9SDimitry Andric bool hoistCatches(MachineFunction &MF); 38*e8d8bef9SDimitry Andric bool addCatchAlls(MachineFunction &MF); 390b57cec5SDimitry Andric bool replaceFuncletReturns(MachineFunction &MF); 400b57cec5SDimitry Andric bool removeUnnecessaryUnreachables(MachineFunction &MF); 41*e8d8bef9SDimitry Andric bool ensureSingleBBTermPads(MachineFunction &MF); 420b57cec5SDimitry Andric bool restoreStackPointer(MachineFunction &MF); 430b57cec5SDimitry Andric 445ffd83dbSDimitry Andric MachineBasicBlock *getMatchingEHPad(MachineInstr *MI); 45*e8d8bef9SDimitry Andric SmallPtrSet<MachineBasicBlock *, 8> CatchRetBBs; 465ffd83dbSDimitry Andric 470b57cec5SDimitry Andric public: 480b57cec5SDimitry Andric static char ID; // Pass identification, replacement for typeid 490b57cec5SDimitry Andric WebAssemblyLateEHPrepare() : MachineFunctionPass(ID) {} 500b57cec5SDimitry Andric }; 510b57cec5SDimitry Andric } // end anonymous namespace 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric char WebAssemblyLateEHPrepare::ID = 0; 540b57cec5SDimitry Andric INITIALIZE_PASS(WebAssemblyLateEHPrepare, DEBUG_TYPE, 550b57cec5SDimitry Andric "WebAssembly Late Exception Preparation", false, false) 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyLateEHPrepare() { 580b57cec5SDimitry Andric return new WebAssemblyLateEHPrepare(); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric // Returns the nearest EH pad that dominates this instruction. This does not use 620b57cec5SDimitry Andric // dominator analysis; it just does BFS on its predecessors until arriving at an 630b57cec5SDimitry Andric // EH pad. This assumes valid EH scopes so the first EH pad it arrives in all 640b57cec5SDimitry Andric // possible search paths should be the same. 650b57cec5SDimitry Andric // Returns nullptr in case it does not find any EH pad in the search, or finds 660b57cec5SDimitry Andric // multiple different EH pads. 675ffd83dbSDimitry Andric MachineBasicBlock * 685ffd83dbSDimitry Andric WebAssemblyLateEHPrepare::getMatchingEHPad(MachineInstr *MI) { 690b57cec5SDimitry Andric MachineFunction *MF = MI->getParent()->getParent(); 700b57cec5SDimitry Andric SmallVector<MachineBasicBlock *, 2> WL; 710b57cec5SDimitry Andric SmallPtrSet<MachineBasicBlock *, 2> Visited; 720b57cec5SDimitry Andric WL.push_back(MI->getParent()); 730b57cec5SDimitry Andric MachineBasicBlock *EHPad = nullptr; 740b57cec5SDimitry Andric while (!WL.empty()) { 750b57cec5SDimitry Andric MachineBasicBlock *MBB = WL.pop_back_val(); 760b57cec5SDimitry Andric if (Visited.count(MBB)) 770b57cec5SDimitry Andric continue; 780b57cec5SDimitry Andric Visited.insert(MBB); 790b57cec5SDimitry Andric if (MBB->isEHPad()) { 800b57cec5SDimitry Andric if (EHPad && EHPad != MBB) 810b57cec5SDimitry Andric return nullptr; 820b57cec5SDimitry Andric EHPad = MBB; 830b57cec5SDimitry Andric continue; 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric if (MBB == &MF->front()) 860b57cec5SDimitry Andric return nullptr; 875ffd83dbSDimitry Andric for (auto *Pred : MBB->predecessors()) 885ffd83dbSDimitry Andric if (!CatchRetBBs.count(Pred)) // We don't go into child scopes 895ffd83dbSDimitry Andric WL.push_back(Pred); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric return EHPad; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric // Erase the specified BBs if the BB does not have any remaining predecessors, 950b57cec5SDimitry Andric // and also all its dead children. 960b57cec5SDimitry Andric template <typename Container> 970b57cec5SDimitry Andric static void eraseDeadBBsAndChildren(const Container &MBBs) { 980b57cec5SDimitry Andric SmallVector<MachineBasicBlock *, 8> WL(MBBs.begin(), MBBs.end()); 99*e8d8bef9SDimitry Andric SmallPtrSet<MachineBasicBlock *, 8> Deleted; 1000b57cec5SDimitry Andric while (!WL.empty()) { 1010b57cec5SDimitry Andric MachineBasicBlock *MBB = WL.pop_back_val(); 102*e8d8bef9SDimitry Andric if (Deleted.count(MBB) || !MBB->pred_empty()) 1030b57cec5SDimitry Andric continue; 104*e8d8bef9SDimitry Andric SmallVector<MachineBasicBlock *, 4> Succs(MBB->successors()); 1050b57cec5SDimitry Andric WL.append(MBB->succ_begin(), MBB->succ_end()); 1060b57cec5SDimitry Andric for (auto *Succ : Succs) 1070b57cec5SDimitry Andric MBB->removeSuccessor(Succ); 108*e8d8bef9SDimitry Andric // To prevent deleting the same BB multiple times, which can happen when 109*e8d8bef9SDimitry Andric // 'MBBs' contain both a parent and a child 110*e8d8bef9SDimitry Andric Deleted.insert(MBB); 1110b57cec5SDimitry Andric MBB->eraseFromParent(); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::runOnMachineFunction(MachineFunction &MF) { 1160b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Late EH Prepare **********\n" 1170b57cec5SDimitry Andric "********** Function: " 1180b57cec5SDimitry Andric << MF.getName() << '\n'); 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric if (MF.getTarget().getMCAsmInfo()->getExceptionHandlingType() != 1210b57cec5SDimitry Andric ExceptionHandling::Wasm) 1220b57cec5SDimitry Andric return false; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric bool Changed = false; 1250b57cec5SDimitry Andric if (MF.getFunction().hasPersonalityFn()) { 126*e8d8bef9SDimitry Andric Changed |= removeUnreachableEHPads(MF); 1275ffd83dbSDimitry Andric recordCatchRetBBs(MF); 128*e8d8bef9SDimitry Andric Changed |= hoistCatches(MF); 129*e8d8bef9SDimitry Andric Changed |= addCatchAlls(MF); 1300b57cec5SDimitry Andric Changed |= replaceFuncletReturns(MF); 131*e8d8bef9SDimitry Andric Changed |= ensureSingleBBTermPads(MF); 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric Changed |= removeUnnecessaryUnreachables(MF); 134*e8d8bef9SDimitry Andric if (MF.getFunction().hasPersonalityFn()) 1350b57cec5SDimitry Andric Changed |= restoreStackPointer(MF); 1360b57cec5SDimitry Andric return Changed; 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 139*e8d8bef9SDimitry Andric // Remove unreachable EH pads and its children. If they remain, CFG 140*e8d8bef9SDimitry Andric // stackification can be tricky. 141*e8d8bef9SDimitry Andric bool WebAssemblyLateEHPrepare::removeUnreachableEHPads(MachineFunction &MF) { 142*e8d8bef9SDimitry Andric SmallVector<MachineBasicBlock *, 4> ToDelete; 143*e8d8bef9SDimitry Andric for (auto &MBB : MF) 144*e8d8bef9SDimitry Andric if (MBB.isEHPad() && MBB.pred_empty()) 145*e8d8bef9SDimitry Andric ToDelete.push_back(&MBB); 146*e8d8bef9SDimitry Andric eraseDeadBBsAndChildren(ToDelete); 147*e8d8bef9SDimitry Andric return !ToDelete.empty(); 148*e8d8bef9SDimitry Andric } 149*e8d8bef9SDimitry Andric 150*e8d8bef9SDimitry Andric // Record which BB ends with catchret instruction, because this will be replaced 151*e8d8bef9SDimitry Andric // with 'br's later. This set of catchret BBs is necessary in 'getMatchingEHPad' 152*e8d8bef9SDimitry Andric // function. 1535ffd83dbSDimitry Andric void WebAssemblyLateEHPrepare::recordCatchRetBBs(MachineFunction &MF) { 1545ffd83dbSDimitry Andric CatchRetBBs.clear(); 1555ffd83dbSDimitry Andric for (auto &MBB : MF) { 1565ffd83dbSDimitry Andric auto Pos = MBB.getFirstTerminator(); 1575ffd83dbSDimitry Andric if (Pos == MBB.end()) 1585ffd83dbSDimitry Andric continue; 1595ffd83dbSDimitry Andric MachineInstr *TI = &*Pos; 1605ffd83dbSDimitry Andric if (TI->getOpcode() == WebAssembly::CATCHRET) 1615ffd83dbSDimitry Andric CatchRetBBs.insert(&MBB); 1625ffd83dbSDimitry Andric } 1635ffd83dbSDimitry Andric } 1645ffd83dbSDimitry Andric 165*e8d8bef9SDimitry Andric // Hoist catch instructions to the beginning of their matching EH pad BBs in 166*e8d8bef9SDimitry Andric // case, 167*e8d8bef9SDimitry Andric // (1) catch instruction is not the first instruction in EH pad. 168*e8d8bef9SDimitry Andric // ehpad: 169*e8d8bef9SDimitry Andric // some_other_instruction 170*e8d8bef9SDimitry Andric // ... 171*e8d8bef9SDimitry Andric // %exn = catch 0 172*e8d8bef9SDimitry Andric // (2) catch instruction is in a non-EH pad BB. For example, 173*e8d8bef9SDimitry Andric // ehpad: 174*e8d8bef9SDimitry Andric // br bb0 175*e8d8bef9SDimitry Andric // bb0: 176*e8d8bef9SDimitry Andric // %exn = catch 0 177*e8d8bef9SDimitry Andric bool WebAssemblyLateEHPrepare::hoistCatches(MachineFunction &MF) { 178*e8d8bef9SDimitry Andric bool Changed = false; 179*e8d8bef9SDimitry Andric SmallVector<MachineInstr *, 16> Catches; 180*e8d8bef9SDimitry Andric for (auto &MBB : MF) 181*e8d8bef9SDimitry Andric for (auto &MI : MBB) 182*e8d8bef9SDimitry Andric if (WebAssembly::isCatch(MI.getOpcode())) 183*e8d8bef9SDimitry Andric Catches.push_back(&MI); 184*e8d8bef9SDimitry Andric 185*e8d8bef9SDimitry Andric for (auto *Catch : Catches) { 186*e8d8bef9SDimitry Andric MachineBasicBlock *EHPad = getMatchingEHPad(Catch); 187*e8d8bef9SDimitry Andric assert(EHPad && "No matching EH pad for catch"); 188*e8d8bef9SDimitry Andric auto InsertPos = EHPad->begin(); 189*e8d8bef9SDimitry Andric // Skip EH_LABELs in the beginning of an EH pad if present. We don't use 190*e8d8bef9SDimitry Andric // these labels at the moment, but other targets also seem to have an 191*e8d8bef9SDimitry Andric // EH_LABEL instruction in the beginning of an EH pad. 192*e8d8bef9SDimitry Andric while (InsertPos != EHPad->end() && InsertPos->isEHLabel()) 193*e8d8bef9SDimitry Andric InsertPos++; 194*e8d8bef9SDimitry Andric if (InsertPos == Catch) 195*e8d8bef9SDimitry Andric continue; 196*e8d8bef9SDimitry Andric Changed = true; 197*e8d8bef9SDimitry Andric EHPad->insert(InsertPos, Catch->removeFromParent()); 198*e8d8bef9SDimitry Andric } 199*e8d8bef9SDimitry Andric return Changed; 200*e8d8bef9SDimitry Andric } 201*e8d8bef9SDimitry Andric 202*e8d8bef9SDimitry Andric // Add catch_all to beginning of cleanup pads. 203*e8d8bef9SDimitry Andric bool WebAssemblyLateEHPrepare::addCatchAlls(MachineFunction &MF) { 2040b57cec5SDimitry Andric bool Changed = false; 2050b57cec5SDimitry Andric const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 206*e8d8bef9SDimitry Andric 2070b57cec5SDimitry Andric for (auto &MBB : MF) { 208*e8d8bef9SDimitry Andric if (!MBB.isEHPad()) 209*e8d8bef9SDimitry Andric continue; 2100b57cec5SDimitry Andric auto InsertPos = MBB.begin(); 211*e8d8bef9SDimitry Andric // Skip EH_LABELs in the beginning of an EH pad if present. 212*e8d8bef9SDimitry Andric while (InsertPos != MBB.end() && InsertPos->isEHLabel()) 213*e8d8bef9SDimitry Andric InsertPos++; 214*e8d8bef9SDimitry Andric // This runs after hoistCatches(), so we assume that if there is a catch, 215*e8d8bef9SDimitry Andric // that should be the non-EH label first instruction in an EH pad. 216*e8d8bef9SDimitry Andric if (InsertPos == MBB.end() || 217*e8d8bef9SDimitry Andric !WebAssembly::isCatch(InsertPos->getOpcode())) { 218*e8d8bef9SDimitry Andric Changed = true; 219*e8d8bef9SDimitry Andric BuildMI(MBB, InsertPos, InsertPos->getDebugLoc(), 220*e8d8bef9SDimitry Andric TII.get(WebAssembly::CATCH_ALL)); 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric return Changed; 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric 226*e8d8bef9SDimitry Andric // Replace pseudo-instructions catchret and cleanupret with br and rethrow 227*e8d8bef9SDimitry Andric // respectively. 2280b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) { 2290b57cec5SDimitry Andric bool Changed = false; 2300b57cec5SDimitry Andric const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric for (auto &MBB : MF) { 2330b57cec5SDimitry Andric auto Pos = MBB.getFirstTerminator(); 2340b57cec5SDimitry Andric if (Pos == MBB.end()) 2350b57cec5SDimitry Andric continue; 2360b57cec5SDimitry Andric MachineInstr *TI = &*Pos; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric switch (TI->getOpcode()) { 2390b57cec5SDimitry Andric case WebAssembly::CATCHRET: { 2400b57cec5SDimitry Andric // Replace a catchret with a branch 2410b57cec5SDimitry Andric MachineBasicBlock *TBB = TI->getOperand(0).getMBB(); 2420b57cec5SDimitry Andric if (!MBB.isLayoutSuccessor(TBB)) 2430b57cec5SDimitry Andric BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::BR)) 2440b57cec5SDimitry Andric .addMBB(TBB); 2450b57cec5SDimitry Andric TI->eraseFromParent(); 2460b57cec5SDimitry Andric Changed = true; 2470b57cec5SDimitry Andric break; 2480b57cec5SDimitry Andric } 249*e8d8bef9SDimitry Andric case WebAssembly::CLEANUPRET: { 250*e8d8bef9SDimitry Andric // Replace a cleanupret with a rethrow. For C++ support, currently 251*e8d8bef9SDimitry Andric // rethrow's immediate argument is always 0 (= the latest exception). 2520b57cec5SDimitry Andric BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW)) 253*e8d8bef9SDimitry Andric .addImm(0); 2540b57cec5SDimitry Andric TI->eraseFromParent(); 2550b57cec5SDimitry Andric Changed = true; 2560b57cec5SDimitry Andric break; 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric } 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric return Changed; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 263*e8d8bef9SDimitry Andric // Remove unnecessary unreachables after a throw or rethrow. 2640b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( 2650b57cec5SDimitry Andric MachineFunction &MF) { 2660b57cec5SDimitry Andric bool Changed = false; 2670b57cec5SDimitry Andric for (auto &MBB : MF) { 2680b57cec5SDimitry Andric for (auto &MI : MBB) { 2690b57cec5SDimitry Andric if (MI.getOpcode() != WebAssembly::THROW && 2700b57cec5SDimitry Andric MI.getOpcode() != WebAssembly::RETHROW) 2710b57cec5SDimitry Andric continue; 2720b57cec5SDimitry Andric Changed = true; 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric // The instruction after the throw should be an unreachable or a branch to 2750b57cec5SDimitry Andric // another BB that should eventually lead to an unreachable. Delete it 2760b57cec5SDimitry Andric // because throw itself is a terminator, and also delete successors if 2770b57cec5SDimitry Andric // any. 2780b57cec5SDimitry Andric MBB.erase(std::next(MI.getIterator()), MBB.end()); 279*e8d8bef9SDimitry Andric SmallVector<MachineBasicBlock *, 8> Succs(MBB.successors()); 2800b57cec5SDimitry Andric for (auto *Succ : Succs) 2810b57cec5SDimitry Andric if (!Succ->isEHPad()) 2820b57cec5SDimitry Andric MBB.removeSuccessor(Succ); 2830b57cec5SDimitry Andric eraseDeadBBsAndChildren(Succs); 2840b57cec5SDimitry Andric } 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric return Changed; 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 290*e8d8bef9SDimitry Andric // Clang-generated terminate pads are an single-BB EH pad in the form of 291*e8d8bef9SDimitry Andric // termpad: 292*e8d8bef9SDimitry Andric // %exn = catch $__cpp_exception 293*e8d8bef9SDimitry Andric // call @__clang_call_terminate(%exn) 294*e8d8bef9SDimitry Andric // unreachable 295*e8d8bef9SDimitry Andric // (There can be local.set and local.gets before the call if we didn't run 296*e8d8bef9SDimitry Andric // RegStackify) 297*e8d8bef9SDimitry Andric // But code transformations can change or add more control flow, so the call to 298*e8d8bef9SDimitry Andric // __clang_call_terminate() function may not be in the original EH pad anymore. 299*e8d8bef9SDimitry Andric // This ensures every terminate pad is a single BB in the form illustrated 300*e8d8bef9SDimitry Andric // above. 3010b57cec5SDimitry Andric // 302*e8d8bef9SDimitry Andric // This is preparation work for the HandleEHTerminatePads pass later, which 303*e8d8bef9SDimitry Andric // duplicates terminate pads both for 'catch' and 'catch_all'. Refer to 304*e8d8bef9SDimitry Andric // WebAssemblyHandleEHTerminatePads.cpp for details. 305*e8d8bef9SDimitry Andric bool WebAssemblyLateEHPrepare::ensureSingleBBTermPads(MachineFunction &MF) { 3060b57cec5SDimitry Andric const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 3070b57cec5SDimitry Andric 308*e8d8bef9SDimitry Andric // Find calls to __clang_call_terminate() 309*e8d8bef9SDimitry Andric SmallVector<MachineInstr *, 8> ClangCallTerminateCalls; 310*e8d8bef9SDimitry Andric SmallPtrSet<MachineBasicBlock *, 8> TermPads; 3110b57cec5SDimitry Andric for (auto &MBB : MF) { 3120b57cec5SDimitry Andric for (auto &MI : MBB) { 3130b57cec5SDimitry Andric if (MI.isCall()) { 3140b57cec5SDimitry Andric const MachineOperand &CalleeOp = MI.getOperand(0); 3150b57cec5SDimitry Andric if (CalleeOp.isGlobal() && CalleeOp.getGlobal()->getName() == 316*e8d8bef9SDimitry Andric WebAssembly::ClangCallTerminateFn) { 317*e8d8bef9SDimitry Andric MachineBasicBlock *EHPad = getMatchingEHPad(&MI); 318*e8d8bef9SDimitry Andric assert(EHPad && "No matching EH pad for __clang_call_terminate"); 319*e8d8bef9SDimitry Andric // In case a __clang_call_terminate call is duplicated during code 320*e8d8bef9SDimitry Andric // transformation so one terminate pad contains multiple 321*e8d8bef9SDimitry Andric // __clang_call_terminate calls, we only count one of them 322*e8d8bef9SDimitry Andric if (TermPads.insert(EHPad).second) 323*e8d8bef9SDimitry Andric ClangCallTerminateCalls.push_back(&MI); 324*e8d8bef9SDimitry Andric } 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric 329*e8d8bef9SDimitry Andric bool Changed = false; 330*e8d8bef9SDimitry Andric for (auto *Call : ClangCallTerminateCalls) { 331*e8d8bef9SDimitry Andric MachineBasicBlock *EHPad = getMatchingEHPad(Call); 332*e8d8bef9SDimitry Andric assert(EHPad && "No matching EH pad for __clang_call_terminate"); 3330b57cec5SDimitry Andric 334*e8d8bef9SDimitry Andric // If it is already the form we want, skip it 335*e8d8bef9SDimitry Andric if (Call->getParent() == EHPad && 336*e8d8bef9SDimitry Andric Call->getNextNode()->getOpcode() == WebAssembly::UNREACHABLE) 337*e8d8bef9SDimitry Andric continue; 3380b57cec5SDimitry Andric 339*e8d8bef9SDimitry Andric // In case the __clang_call_terminate() call is not in its matching EH pad, 340*e8d8bef9SDimitry Andric // move the call to the end of EH pad and add an unreachable instruction 341*e8d8bef9SDimitry Andric // after that. Delete all successors and their children if any, because here 342*e8d8bef9SDimitry Andric // the program terminates. 343*e8d8bef9SDimitry Andric Changed = true; 344*e8d8bef9SDimitry Andric // This runs after hoistCatches(), so catch instruction should be at the top 345*e8d8bef9SDimitry Andric MachineInstr *Catch = WebAssembly::findCatch(EHPad); 346*e8d8bef9SDimitry Andric assert(Catch && "EH pad does not have a catch instruction"); 347*e8d8bef9SDimitry Andric // Takes the result register of the catch instruction as argument. There may 348*e8d8bef9SDimitry Andric // have been some other local.set/local.gets in between, but at this point 349*e8d8bef9SDimitry Andric // we don't care. 350*e8d8bef9SDimitry Andric Call->getOperand(1).setReg(Catch->getOperand(0).getReg()); 351*e8d8bef9SDimitry Andric auto InsertPos = std::next(MachineBasicBlock::iterator(Catch)); 352*e8d8bef9SDimitry Andric EHPad->insert(InsertPos, Call->removeFromParent()); 353*e8d8bef9SDimitry Andric BuildMI(*EHPad, InsertPos, Call->getDebugLoc(), 354*e8d8bef9SDimitry Andric TII.get(WebAssembly::UNREACHABLE)); 355*e8d8bef9SDimitry Andric EHPad->erase(InsertPos, EHPad->end()); 356*e8d8bef9SDimitry Andric SmallVector<MachineBasicBlock *, 8> Succs(EHPad->successors()); 357*e8d8bef9SDimitry Andric for (auto *Succ : Succs) 358*e8d8bef9SDimitry Andric EHPad->removeSuccessor(Succ); 359*e8d8bef9SDimitry Andric eraseDeadBBsAndChildren(Succs); 3600b57cec5SDimitry Andric } 361*e8d8bef9SDimitry Andric return Changed; 3620b57cec5SDimitry Andric } 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric // After the stack is unwound due to a thrown exception, the __stack_pointer 3650b57cec5SDimitry Andric // global can point to an invalid address. This inserts instructions that 3660b57cec5SDimitry Andric // restore __stack_pointer global. 3670b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { 3680b57cec5SDimitry Andric const auto *FrameLowering = static_cast<const WebAssemblyFrameLowering *>( 3690b57cec5SDimitry Andric MF.getSubtarget().getFrameLowering()); 3700b57cec5SDimitry Andric if (!FrameLowering->needsPrologForEH(MF)) 3710b57cec5SDimitry Andric return false; 3720b57cec5SDimitry Andric bool Changed = false; 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric for (auto &MBB : MF) { 3750b57cec5SDimitry Andric if (!MBB.isEHPad()) 3760b57cec5SDimitry Andric continue; 3770b57cec5SDimitry Andric Changed = true; 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric // Insert __stack_pointer restoring instructions at the beginning of each EH 3800b57cec5SDimitry Andric // pad, after the catch instruction. Here it is safe to assume that SP32 3810b57cec5SDimitry Andric // holds the latest value of __stack_pointer, because the only exception for 3820b57cec5SDimitry Andric // this case is when a function uses the red zone, but that only happens 3830b57cec5SDimitry Andric // with leaf functions, and we don't restore __stack_pointer in leaf 3840b57cec5SDimitry Andric // functions anyway. 3850b57cec5SDimitry Andric auto InsertPos = MBB.begin(); 3860b57cec5SDimitry Andric if (InsertPos->isEHLabel()) // EH pad starts with an EH label 3870b57cec5SDimitry Andric ++InsertPos; 388*e8d8bef9SDimitry Andric if (WebAssembly::isCatch(InsertPos->getOpcode())) 3890b57cec5SDimitry Andric ++InsertPos; 3905ffd83dbSDimitry Andric FrameLowering->writeSPToGlobal(FrameLowering->getSPReg(MF), MF, MBB, 3915ffd83dbSDimitry Andric InsertPos, MBB.begin()->getDebugLoc()); 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric return Changed; 3940b57cec5SDimitry Andric } 395