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