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