1 //===-- WebAssemblyEHRestoreStackPointer.cpp - __stack_pointer restoration ===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// After the stack is unwound due to a thrown exception, the __stack_pointer 12 /// global can point to an invalid address. This inserts instructions that 13 /// restore __stack_pointer global. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 18 #include "WebAssembly.h" 19 #include "WebAssemblySubtarget.h" 20 #include "WebAssemblyUtilities.h" 21 #include "llvm/CodeGen/MachineFrameInfo.h" 22 #include "llvm/MC/MCAsmInfo.h" 23 using namespace llvm; 24 25 #define DEBUG_TYPE "wasm-eh-restore-stack-pointer" 26 27 namespace { 28 class WebAssemblyEHRestoreStackPointer final : public MachineFunctionPass { 29 public: 30 static char ID; // Pass identification, replacement for typeid 31 WebAssemblyEHRestoreStackPointer() : MachineFunctionPass(ID) {} 32 33 StringRef getPassName() const override { 34 return "WebAssembly Restore Stack Pointer for Exception Handling"; 35 } 36 37 void getAnalysisUsage(AnalysisUsage &AU) const override { 38 AU.setPreservesCFG(); 39 MachineFunctionPass::getAnalysisUsage(AU); 40 } 41 42 bool runOnMachineFunction(MachineFunction &MF) override; 43 }; 44 } // end anonymous namespace 45 46 char WebAssemblyEHRestoreStackPointer::ID = 0; 47 INITIALIZE_PASS(WebAssemblyEHRestoreStackPointer, DEBUG_TYPE, 48 "Restore Stack Pointer for Exception Handling", true, false) 49 50 FunctionPass *llvm::createWebAssemblyEHRestoreStackPointer() { 51 return new WebAssemblyEHRestoreStackPointer(); 52 } 53 54 bool WebAssemblyEHRestoreStackPointer::runOnMachineFunction( 55 MachineFunction &MF) { 56 LLVM_DEBUG(dbgs() << "********** EH Restore Stack Pointer **********\n" 57 "********** Function: " 58 << MF.getName() << '\n'); 59 60 const auto *FrameLowering = static_cast<const WebAssemblyFrameLowering *>( 61 MF.getSubtarget().getFrameLowering()); 62 if (!FrameLowering->needsPrologForEH(MF)) 63 return false; 64 bool Changed = false; 65 66 for (auto &MBB : MF) { 67 if (!MBB.isEHPad()) 68 continue; 69 Changed = true; 70 71 // Insert __stack_pointer restoring instructions at the beginning of each EH 72 // pad, after the catch instruction. (Catch instructions may have been 73 // reordered, and catch_all instructions have not been inserted yet, but 74 // those cases are handled in LateEHPrepare). 75 // 76 // Here it is safe to assume that SP32 holds the latest value of 77 // __stack_pointer, because the only exception for this case is when a 78 // function uses the red zone, but that only happens with leaf functions, 79 // and we don't restore __stack_pointer in leaf functions anyway. 80 auto InsertPos = MBB.begin(); 81 if (WebAssembly::isCatch(*MBB.begin())) 82 InsertPos++; 83 FrameLowering->writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPos, 84 MBB.begin()->getDebugLoc()); 85 } 86 return Changed; 87 } 88