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
WebAssemblyEHRestoreStackPointer()31 WebAssemblyEHRestoreStackPointer() : MachineFunctionPass(ID) {}
32
getPassName() const33 StringRef getPassName() const override {
34 return "WebAssembly Restore Stack Pointer for Exception Handling";
35 }
36
getAnalysisUsage(AnalysisUsage & AU) const37 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
createWebAssemblyEHRestoreStackPointer()50 FunctionPass *llvm::createWebAssemblyEHRestoreStackPointer() {
51 return new WebAssemblyEHRestoreStackPointer();
52 }
53
runOnMachineFunction(MachineFunction & MF)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