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