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" 175f757f3fSDimitry Andric #include "WebAssemblyUtilities.h" 18e8d8bef9SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 1981ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/WasmEHFuncInfo.h" 220b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 238bcb0991SDimitry Andric #include "llvm/Support/Debug.h" 245ffd83dbSDimitry Andric #include "llvm/Target/TargetMachine.h" 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-late-eh-prepare" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric namespace { 300b57cec5SDimitry Andric class WebAssemblyLateEHPrepare final : public MachineFunctionPass { 310b57cec5SDimitry Andric StringRef getPassName() const override { 320b57cec5SDimitry Andric return "WebAssembly Late Prepare Exception"; 330b57cec5SDimitry Andric } 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 36e8d8bef9SDimitry Andric bool removeUnreachableEHPads(MachineFunction &MF); 375ffd83dbSDimitry Andric void recordCatchRetBBs(MachineFunction &MF); 38e8d8bef9SDimitry Andric bool hoistCatches(MachineFunction &MF); 39e8d8bef9SDimitry Andric bool addCatchAlls(MachineFunction &MF); 400b57cec5SDimitry Andric bool replaceFuncletReturns(MachineFunction &MF); 410b57cec5SDimitry Andric bool removeUnnecessaryUnreachables(MachineFunction &MF); 420b57cec5SDimitry Andric bool restoreStackPointer(MachineFunction &MF); 430b57cec5SDimitry Andric 445ffd83dbSDimitry Andric MachineBasicBlock *getMatchingEHPad(MachineInstr *MI); 45e8d8bef9SDimitry 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(); 7681ad6265SDimitry Andric if (!Visited.insert(MBB).second) 770b57cec5SDimitry Andric continue; 780b57cec5SDimitry Andric if (MBB->isEHPad()) { 790b57cec5SDimitry Andric if (EHPad && EHPad != MBB) 800b57cec5SDimitry Andric return nullptr; 810b57cec5SDimitry Andric EHPad = MBB; 820b57cec5SDimitry Andric continue; 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric if (MBB == &MF->front()) 850b57cec5SDimitry Andric return nullptr; 865ffd83dbSDimitry Andric for (auto *Pred : MBB->predecessors()) 875ffd83dbSDimitry Andric if (!CatchRetBBs.count(Pred)) // We don't go into child scopes 885ffd83dbSDimitry Andric WL.push_back(Pred); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric return EHPad; 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric // Erase the specified BBs if the BB does not have any remaining predecessors, 940b57cec5SDimitry Andric // and also all its dead children. 950b57cec5SDimitry Andric template <typename Container> 960b57cec5SDimitry Andric static void eraseDeadBBsAndChildren(const Container &MBBs) { 970b57cec5SDimitry Andric SmallVector<MachineBasicBlock *, 8> WL(MBBs.begin(), MBBs.end()); 98e8d8bef9SDimitry Andric SmallPtrSet<MachineBasicBlock *, 8> Deleted; 990b57cec5SDimitry Andric while (!WL.empty()) { 1000b57cec5SDimitry Andric MachineBasicBlock *MBB = WL.pop_back_val(); 101e8d8bef9SDimitry Andric if (Deleted.count(MBB) || !MBB->pred_empty()) 1020b57cec5SDimitry Andric continue; 103e8d8bef9SDimitry Andric SmallVector<MachineBasicBlock *, 4> Succs(MBB->successors()); 1040b57cec5SDimitry Andric WL.append(MBB->succ_begin(), MBB->succ_end()); 1050b57cec5SDimitry Andric for (auto *Succ : Succs) 1060b57cec5SDimitry Andric MBB->removeSuccessor(Succ); 107e8d8bef9SDimitry Andric // To prevent deleting the same BB multiple times, which can happen when 108e8d8bef9SDimitry Andric // 'MBBs' contain both a parent and a child 109e8d8bef9SDimitry Andric Deleted.insert(MBB); 1100b57cec5SDimitry Andric MBB->eraseFromParent(); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::runOnMachineFunction(MachineFunction &MF) { 1150b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Late EH Prepare **********\n" 1160b57cec5SDimitry Andric "********** Function: " 1170b57cec5SDimitry Andric << MF.getName() << '\n'); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric if (MF.getTarget().getMCAsmInfo()->getExceptionHandlingType() != 1200b57cec5SDimitry Andric ExceptionHandling::Wasm) 1210b57cec5SDimitry Andric return false; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric bool Changed = false; 1240b57cec5SDimitry Andric if (MF.getFunction().hasPersonalityFn()) { 125e8d8bef9SDimitry Andric Changed |= removeUnreachableEHPads(MF); 1265ffd83dbSDimitry Andric recordCatchRetBBs(MF); 127e8d8bef9SDimitry Andric Changed |= hoistCatches(MF); 128e8d8bef9SDimitry Andric Changed |= addCatchAlls(MF); 1290b57cec5SDimitry Andric Changed |= replaceFuncletReturns(MF); 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric Changed |= removeUnnecessaryUnreachables(MF); 132e8d8bef9SDimitry Andric if (MF.getFunction().hasPersonalityFn()) 1330b57cec5SDimitry Andric Changed |= restoreStackPointer(MF); 1340b57cec5SDimitry Andric return Changed; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 137e8d8bef9SDimitry Andric // Remove unreachable EH pads and its children. If they remain, CFG 138e8d8bef9SDimitry Andric // stackification can be tricky. 139e8d8bef9SDimitry Andric bool WebAssemblyLateEHPrepare::removeUnreachableEHPads(MachineFunction &MF) { 140e8d8bef9SDimitry Andric SmallVector<MachineBasicBlock *, 4> ToDelete; 141e8d8bef9SDimitry Andric for (auto &MBB : MF) 142e8d8bef9SDimitry Andric if (MBB.isEHPad() && MBB.pred_empty()) 143e8d8bef9SDimitry Andric ToDelete.push_back(&MBB); 144e8d8bef9SDimitry Andric eraseDeadBBsAndChildren(ToDelete); 145e8d8bef9SDimitry Andric return !ToDelete.empty(); 146e8d8bef9SDimitry Andric } 147e8d8bef9SDimitry Andric 148e8d8bef9SDimitry Andric // Record which BB ends with catchret instruction, because this will be replaced 149e8d8bef9SDimitry Andric // with 'br's later. This set of catchret BBs is necessary in 'getMatchingEHPad' 150e8d8bef9SDimitry Andric // function. 1515ffd83dbSDimitry Andric void WebAssemblyLateEHPrepare::recordCatchRetBBs(MachineFunction &MF) { 1525ffd83dbSDimitry Andric CatchRetBBs.clear(); 1535ffd83dbSDimitry Andric for (auto &MBB : MF) { 1545ffd83dbSDimitry Andric auto Pos = MBB.getFirstTerminator(); 1555ffd83dbSDimitry Andric if (Pos == MBB.end()) 1565ffd83dbSDimitry Andric continue; 1575ffd83dbSDimitry Andric MachineInstr *TI = &*Pos; 1585ffd83dbSDimitry Andric if (TI->getOpcode() == WebAssembly::CATCHRET) 1595ffd83dbSDimitry Andric CatchRetBBs.insert(&MBB); 1605ffd83dbSDimitry Andric } 1615ffd83dbSDimitry Andric } 1625ffd83dbSDimitry Andric 163e8d8bef9SDimitry Andric // Hoist catch instructions to the beginning of their matching EH pad BBs in 164e8d8bef9SDimitry Andric // case, 165e8d8bef9SDimitry Andric // (1) catch instruction is not the first instruction in EH pad. 166e8d8bef9SDimitry Andric // ehpad: 167e8d8bef9SDimitry Andric // some_other_instruction 168e8d8bef9SDimitry Andric // ... 169e8d8bef9SDimitry Andric // %exn = catch 0 170e8d8bef9SDimitry Andric // (2) catch instruction is in a non-EH pad BB. For example, 171e8d8bef9SDimitry Andric // ehpad: 172e8d8bef9SDimitry Andric // br bb0 173e8d8bef9SDimitry Andric // bb0: 174e8d8bef9SDimitry Andric // %exn = catch 0 175e8d8bef9SDimitry Andric bool WebAssemblyLateEHPrepare::hoistCatches(MachineFunction &MF) { 176e8d8bef9SDimitry Andric bool Changed = false; 177e8d8bef9SDimitry Andric SmallVector<MachineInstr *, 16> Catches; 178e8d8bef9SDimitry Andric for (auto &MBB : MF) 179e8d8bef9SDimitry Andric for (auto &MI : MBB) 180e8d8bef9SDimitry Andric if (WebAssembly::isCatch(MI.getOpcode())) 181e8d8bef9SDimitry Andric Catches.push_back(&MI); 182e8d8bef9SDimitry Andric 183e8d8bef9SDimitry Andric for (auto *Catch : Catches) { 184e8d8bef9SDimitry Andric MachineBasicBlock *EHPad = getMatchingEHPad(Catch); 185e8d8bef9SDimitry Andric assert(EHPad && "No matching EH pad for catch"); 186e8d8bef9SDimitry Andric auto InsertPos = EHPad->begin(); 187e8d8bef9SDimitry Andric // Skip EH_LABELs in the beginning of an EH pad if present. We don't use 188e8d8bef9SDimitry Andric // these labels at the moment, but other targets also seem to have an 189e8d8bef9SDimitry Andric // EH_LABEL instruction in the beginning of an EH pad. 190e8d8bef9SDimitry Andric while (InsertPos != EHPad->end() && InsertPos->isEHLabel()) 191e8d8bef9SDimitry Andric InsertPos++; 192e8d8bef9SDimitry Andric if (InsertPos == Catch) 193e8d8bef9SDimitry Andric continue; 194e8d8bef9SDimitry Andric Changed = true; 195e8d8bef9SDimitry Andric EHPad->insert(InsertPos, Catch->removeFromParent()); 196e8d8bef9SDimitry Andric } 197e8d8bef9SDimitry Andric return Changed; 198e8d8bef9SDimitry Andric } 199e8d8bef9SDimitry Andric 200e8d8bef9SDimitry Andric // Add catch_all to beginning of cleanup pads. 201e8d8bef9SDimitry Andric bool WebAssemblyLateEHPrepare::addCatchAlls(MachineFunction &MF) { 2020b57cec5SDimitry Andric bool Changed = false; 2030b57cec5SDimitry Andric const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 204e8d8bef9SDimitry Andric 2050b57cec5SDimitry Andric for (auto &MBB : MF) { 206e8d8bef9SDimitry Andric if (!MBB.isEHPad()) 207e8d8bef9SDimitry Andric continue; 2080b57cec5SDimitry Andric auto InsertPos = MBB.begin(); 209e8d8bef9SDimitry Andric // Skip EH_LABELs in the beginning of an EH pad if present. 210e8d8bef9SDimitry Andric while (InsertPos != MBB.end() && InsertPos->isEHLabel()) 211e8d8bef9SDimitry Andric InsertPos++; 212e8d8bef9SDimitry Andric // This runs after hoistCatches(), so we assume that if there is a catch, 213fe6060f1SDimitry Andric // that should be the first non-EH-label instruction in an EH pad. 214e8d8bef9SDimitry Andric if (InsertPos == MBB.end() || 215e8d8bef9SDimitry Andric !WebAssembly::isCatch(InsertPos->getOpcode())) { 216e8d8bef9SDimitry Andric Changed = true; 217fe6060f1SDimitry Andric BuildMI(MBB, InsertPos, 218fe6060f1SDimitry Andric InsertPos == MBB.end() ? DebugLoc() : InsertPos->getDebugLoc(), 219e8d8bef9SDimitry Andric TII.get(WebAssembly::CATCH_ALL)); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric return Changed; 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 225e8d8bef9SDimitry Andric // Replace pseudo-instructions catchret and cleanupret with br and rethrow 226e8d8bef9SDimitry Andric // respectively. 2270b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) { 2280b57cec5SDimitry Andric bool Changed = false; 2290b57cec5SDimitry Andric const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric for (auto &MBB : MF) { 2320b57cec5SDimitry Andric auto Pos = MBB.getFirstTerminator(); 2330b57cec5SDimitry Andric if (Pos == MBB.end()) 2340b57cec5SDimitry Andric continue; 2350b57cec5SDimitry Andric MachineInstr *TI = &*Pos; 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric switch (TI->getOpcode()) { 2380b57cec5SDimitry Andric case WebAssembly::CATCHRET: { 2390b57cec5SDimitry Andric // Replace a catchret with a branch 2400b57cec5SDimitry Andric MachineBasicBlock *TBB = TI->getOperand(0).getMBB(); 2410b57cec5SDimitry Andric if (!MBB.isLayoutSuccessor(TBB)) 2420b57cec5SDimitry Andric BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::BR)) 2430b57cec5SDimitry Andric .addMBB(TBB); 2440b57cec5SDimitry Andric TI->eraseFromParent(); 2450b57cec5SDimitry Andric Changed = true; 2460b57cec5SDimitry Andric break; 2470b57cec5SDimitry Andric } 248*415efcecSDimitry Andric case WebAssembly::RETHROW: 249*415efcecSDimitry Andric // These RETHROWs here were lowered from llvm.wasm.rethrow() intrinsics, 250*415efcecSDimitry Andric // generated in Clang for when an exception is not caught by the given 251*415efcecSDimitry Andric // type (e.g. catch (int)). 252*415efcecSDimitry Andric // 253*415efcecSDimitry Andric // RETHROW's BB argument is the EH pad where the exception to rethrow has 254*415efcecSDimitry Andric // been caught. (Until this point, RETHROW has just a '0' as a placeholder 255*415efcecSDimitry Andric // argument.) For these llvm.wasm.rethrow()s, we can safely assume the 256*415efcecSDimitry Andric // exception comes from the nearest dominating EH pad, because catch.start 257*415efcecSDimitry Andric // EH pad is structured like this: 258*415efcecSDimitry Andric // 259*415efcecSDimitry Andric // catch.start: 260*415efcecSDimitry Andric // catchpad ... 261*415efcecSDimitry Andric // %matches = compare ehselector with typeid 262*415efcecSDimitry Andric // br i1 %matches, label %catch, label %rethrow 263*415efcecSDimitry Andric // 264*415efcecSDimitry Andric // rethrow: 265*415efcecSDimitry Andric // ;; rethrows the exception caught in 'catch.start' 266*415efcecSDimitry Andric // call @llvm.wasm.rethrow() 267*415efcecSDimitry Andric TI->removeOperand(0); 268*415efcecSDimitry Andric TI->addOperand(MachineOperand::CreateMBB(getMatchingEHPad(TI))); 269*415efcecSDimitry Andric Changed = true; 270*415efcecSDimitry Andric break; 271e8d8bef9SDimitry Andric case WebAssembly::CLEANUPRET: { 272*415efcecSDimitry Andric // CLEANUPRETs have the EH pad BB the exception to rethrow has been caught 273*415efcecSDimitry Andric // as an argument. Use it and change the instruction opcode to 'RETHROW' 274*415efcecSDimitry Andric // to make rethrowing instructions consistent. 275*415efcecSDimitry Andric // 276*415efcecSDimitry Andric // This is because we cannot safely assume that it is always the nearest 277*415efcecSDimitry Andric // dominating EH pad, in case there are code transformations such as 278*415efcecSDimitry Andric // inlining. 2790b57cec5SDimitry Andric BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW)) 280*415efcecSDimitry Andric .addMBB(TI->getOperand(0).getMBB()); 2810b57cec5SDimitry Andric TI->eraseFromParent(); 2820b57cec5SDimitry Andric Changed = true; 2830b57cec5SDimitry Andric break; 2840b57cec5SDimitry Andric } 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric return Changed; 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 290e8d8bef9SDimitry Andric // Remove unnecessary unreachables after a throw or rethrow. 2910b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( 2920b57cec5SDimitry Andric MachineFunction &MF) { 2930b57cec5SDimitry Andric bool Changed = false; 2940b57cec5SDimitry Andric for (auto &MBB : MF) { 2950b57cec5SDimitry Andric for (auto &MI : MBB) { 2960b57cec5SDimitry Andric if (MI.getOpcode() != WebAssembly::THROW && 2970b57cec5SDimitry Andric MI.getOpcode() != WebAssembly::RETHROW) 2980b57cec5SDimitry Andric continue; 2990b57cec5SDimitry Andric Changed = true; 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric // The instruction after the throw should be an unreachable or a branch to 3020b57cec5SDimitry Andric // another BB that should eventually lead to an unreachable. Delete it 3030b57cec5SDimitry Andric // because throw itself is a terminator, and also delete successors if 3040b57cec5SDimitry Andric // any. 3050b57cec5SDimitry Andric MBB.erase(std::next(MI.getIterator()), MBB.end()); 306e8d8bef9SDimitry Andric SmallVector<MachineBasicBlock *, 8> Succs(MBB.successors()); 3070b57cec5SDimitry Andric for (auto *Succ : Succs) 3080b57cec5SDimitry Andric if (!Succ->isEHPad()) 3090b57cec5SDimitry Andric MBB.removeSuccessor(Succ); 3100b57cec5SDimitry Andric eraseDeadBBsAndChildren(Succs); 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric return Changed; 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric // After the stack is unwound due to a thrown exception, the __stack_pointer 3180b57cec5SDimitry Andric // global can point to an invalid address. This inserts instructions that 3190b57cec5SDimitry Andric // restore __stack_pointer global. 3200b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { 3210b57cec5SDimitry Andric const auto *FrameLowering = static_cast<const WebAssemblyFrameLowering *>( 3220b57cec5SDimitry Andric MF.getSubtarget().getFrameLowering()); 3230b57cec5SDimitry Andric if (!FrameLowering->needsPrologForEH(MF)) 3240b57cec5SDimitry Andric return false; 3250b57cec5SDimitry Andric bool Changed = false; 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric for (auto &MBB : MF) { 3280b57cec5SDimitry Andric if (!MBB.isEHPad()) 3290b57cec5SDimitry Andric continue; 3300b57cec5SDimitry Andric Changed = true; 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric // Insert __stack_pointer restoring instructions at the beginning of each EH 3330b57cec5SDimitry Andric // pad, after the catch instruction. Here it is safe to assume that SP32 3340b57cec5SDimitry Andric // holds the latest value of __stack_pointer, because the only exception for 3350b57cec5SDimitry Andric // this case is when a function uses the red zone, but that only happens 3360b57cec5SDimitry Andric // with leaf functions, and we don't restore __stack_pointer in leaf 3370b57cec5SDimitry Andric // functions anyway. 3380b57cec5SDimitry Andric auto InsertPos = MBB.begin(); 339fe6060f1SDimitry Andric // Skip EH_LABELs in the beginning of an EH pad if present. 340fe6060f1SDimitry Andric while (InsertPos != MBB.end() && InsertPos->isEHLabel()) 341fe6060f1SDimitry Andric InsertPos++; 342fe6060f1SDimitry Andric assert(InsertPos != MBB.end() && 343fe6060f1SDimitry Andric WebAssembly::isCatch(InsertPos->getOpcode()) && 344fe6060f1SDimitry Andric "catch/catch_all should be present in every EH pad at this point"); 345fe6060f1SDimitry Andric ++InsertPos; // Skip the catch instruction 3465ffd83dbSDimitry Andric FrameLowering->writeSPToGlobal(FrameLowering->getSPReg(MF), MF, MBB, 3475ffd83dbSDimitry Andric InsertPos, MBB.begin()->getDebugLoc()); 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric return Changed; 3500b57cec5SDimitry Andric } 351