xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
10b57cec5SDimitry Andric //=== WebAssemblyLateEHPrepare.cpp - WebAssembly Exception Preparation -===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// \brief Does various transformations for exception handling.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
150b57cec5SDimitry Andric #include "WebAssembly.h"
160b57cec5SDimitry Andric #include "WebAssemblySubtarget.h"
170b57cec5SDimitry Andric #include "WebAssemblyUtilities.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/WasmEHFuncInfo.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
228bcb0991SDimitry Andric #include "llvm/Support/Debug.h"
23*5ffd83dbSDimitry Andric #include "llvm/Target/TargetMachine.h"
240b57cec5SDimitry Andric using namespace llvm;
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-late-eh-prepare"
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric namespace {
290b57cec5SDimitry Andric class WebAssemblyLateEHPrepare final : public MachineFunctionPass {
300b57cec5SDimitry Andric   StringRef getPassName() const override {
310b57cec5SDimitry Andric     return "WebAssembly Late Prepare Exception";
320b57cec5SDimitry Andric   }
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
35*5ffd83dbSDimitry Andric   void recordCatchRetBBs(MachineFunction &MF);
360b57cec5SDimitry Andric   bool addCatches(MachineFunction &MF);
370b57cec5SDimitry Andric   bool replaceFuncletReturns(MachineFunction &MF);
380b57cec5SDimitry Andric   bool removeUnnecessaryUnreachables(MachineFunction &MF);
390b57cec5SDimitry Andric   bool addExceptionExtraction(MachineFunction &MF);
400b57cec5SDimitry Andric   bool restoreStackPointer(MachineFunction &MF);
410b57cec5SDimitry Andric 
42*5ffd83dbSDimitry Andric   MachineBasicBlock *getMatchingEHPad(MachineInstr *MI);
43*5ffd83dbSDimitry Andric   SmallSet<MachineBasicBlock *, 8> CatchRetBBs;
44*5ffd83dbSDimitry Andric 
450b57cec5SDimitry Andric public:
460b57cec5SDimitry Andric   static char ID; // Pass identification, replacement for typeid
470b57cec5SDimitry Andric   WebAssemblyLateEHPrepare() : MachineFunctionPass(ID) {}
480b57cec5SDimitry Andric };
490b57cec5SDimitry Andric } // end anonymous namespace
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric char WebAssemblyLateEHPrepare::ID = 0;
520b57cec5SDimitry Andric INITIALIZE_PASS(WebAssemblyLateEHPrepare, DEBUG_TYPE,
530b57cec5SDimitry Andric                 "WebAssembly Late Exception Preparation", false, false)
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyLateEHPrepare() {
560b57cec5SDimitry Andric   return new WebAssemblyLateEHPrepare();
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric // Returns the nearest EH pad that dominates this instruction. This does not use
600b57cec5SDimitry Andric // dominator analysis; it just does BFS on its predecessors until arriving at an
610b57cec5SDimitry Andric // EH pad. This assumes valid EH scopes so the first EH pad it arrives in all
620b57cec5SDimitry Andric // possible search paths should be the same.
630b57cec5SDimitry Andric // Returns nullptr in case it does not find any EH pad in the search, or finds
640b57cec5SDimitry Andric // multiple different EH pads.
65*5ffd83dbSDimitry Andric MachineBasicBlock *
66*5ffd83dbSDimitry Andric WebAssemblyLateEHPrepare::getMatchingEHPad(MachineInstr *MI) {
670b57cec5SDimitry Andric   MachineFunction *MF = MI->getParent()->getParent();
680b57cec5SDimitry Andric   SmallVector<MachineBasicBlock *, 2> WL;
690b57cec5SDimitry Andric   SmallPtrSet<MachineBasicBlock *, 2> Visited;
700b57cec5SDimitry Andric   WL.push_back(MI->getParent());
710b57cec5SDimitry Andric   MachineBasicBlock *EHPad = nullptr;
720b57cec5SDimitry Andric   while (!WL.empty()) {
730b57cec5SDimitry Andric     MachineBasicBlock *MBB = WL.pop_back_val();
740b57cec5SDimitry Andric     if (Visited.count(MBB))
750b57cec5SDimitry Andric       continue;
760b57cec5SDimitry Andric     Visited.insert(MBB);
770b57cec5SDimitry Andric     if (MBB->isEHPad()) {
780b57cec5SDimitry Andric       if (EHPad && EHPad != MBB)
790b57cec5SDimitry Andric         return nullptr;
800b57cec5SDimitry Andric       EHPad = MBB;
810b57cec5SDimitry Andric       continue;
820b57cec5SDimitry Andric     }
830b57cec5SDimitry Andric     if (MBB == &MF->front())
840b57cec5SDimitry Andric       return nullptr;
85*5ffd83dbSDimitry Andric     for (auto *Pred : MBB->predecessors())
86*5ffd83dbSDimitry Andric       if (!CatchRetBBs.count(Pred)) // We don't go into child scopes
87*5ffd83dbSDimitry Andric         WL.push_back(Pred);
880b57cec5SDimitry Andric   }
890b57cec5SDimitry Andric   return EHPad;
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric // Erase the specified BBs if the BB does not have any remaining predecessors,
930b57cec5SDimitry Andric // and also all its dead children.
940b57cec5SDimitry Andric template <typename Container>
950b57cec5SDimitry Andric static void eraseDeadBBsAndChildren(const Container &MBBs) {
960b57cec5SDimitry Andric   SmallVector<MachineBasicBlock *, 8> WL(MBBs.begin(), MBBs.end());
970b57cec5SDimitry Andric   while (!WL.empty()) {
980b57cec5SDimitry Andric     MachineBasicBlock *MBB = WL.pop_back_val();
990b57cec5SDimitry Andric     if (!MBB->pred_empty())
1000b57cec5SDimitry Andric       continue;
1010b57cec5SDimitry Andric     SmallVector<MachineBasicBlock *, 4> Succs(MBB->succ_begin(),
1020b57cec5SDimitry Andric                                               MBB->succ_end());
1030b57cec5SDimitry Andric     WL.append(MBB->succ_begin(), MBB->succ_end());
1040b57cec5SDimitry Andric     for (auto *Succ : Succs)
1050b57cec5SDimitry Andric       MBB->removeSuccessor(Succ);
1060b57cec5SDimitry Andric     MBB->eraseFromParent();
1070b57cec5SDimitry Andric   }
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::runOnMachineFunction(MachineFunction &MF) {
1110b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Late EH Prepare **********\n"
1120b57cec5SDimitry Andric                        "********** Function: "
1130b57cec5SDimitry Andric                     << MF.getName() << '\n');
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   if (MF.getTarget().getMCAsmInfo()->getExceptionHandlingType() !=
1160b57cec5SDimitry Andric       ExceptionHandling::Wasm)
1170b57cec5SDimitry Andric     return false;
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   bool Changed = false;
1200b57cec5SDimitry Andric   if (MF.getFunction().hasPersonalityFn()) {
121*5ffd83dbSDimitry Andric     recordCatchRetBBs(MF);
1220b57cec5SDimitry Andric     Changed |= addCatches(MF);
1230b57cec5SDimitry Andric     Changed |= replaceFuncletReturns(MF);
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric   Changed |= removeUnnecessaryUnreachables(MF);
1260b57cec5SDimitry Andric   if (MF.getFunction().hasPersonalityFn()) {
1270b57cec5SDimitry Andric     Changed |= addExceptionExtraction(MF);
1280b57cec5SDimitry Andric     Changed |= restoreStackPointer(MF);
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric   return Changed;
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric 
133*5ffd83dbSDimitry Andric // Record which BB ends with 'CATCHRET' instruction, because this will be
134*5ffd83dbSDimitry Andric // replaced with BRs later. This set of 'CATCHRET' BBs is necessary in
135*5ffd83dbSDimitry Andric // 'getMatchingEHPad' function.
136*5ffd83dbSDimitry Andric void WebAssemblyLateEHPrepare::recordCatchRetBBs(MachineFunction &MF) {
137*5ffd83dbSDimitry Andric   CatchRetBBs.clear();
138*5ffd83dbSDimitry Andric   for (auto &MBB : MF) {
139*5ffd83dbSDimitry Andric     auto Pos = MBB.getFirstTerminator();
140*5ffd83dbSDimitry Andric     if (Pos == MBB.end())
141*5ffd83dbSDimitry Andric       continue;
142*5ffd83dbSDimitry Andric     MachineInstr *TI = &*Pos;
143*5ffd83dbSDimitry Andric     if (TI->getOpcode() == WebAssembly::CATCHRET)
144*5ffd83dbSDimitry Andric       CatchRetBBs.insert(&MBB);
145*5ffd83dbSDimitry Andric   }
146*5ffd83dbSDimitry Andric }
147*5ffd83dbSDimitry Andric 
1480b57cec5SDimitry Andric // Add catch instruction to beginning of catchpads and cleanuppads.
1490b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::addCatches(MachineFunction &MF) {
1500b57cec5SDimitry Andric   bool Changed = false;
1510b57cec5SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
1520b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
1530b57cec5SDimitry Andric   for (auto &MBB : MF) {
1540b57cec5SDimitry Andric     if (MBB.isEHPad()) {
1550b57cec5SDimitry Andric       Changed = true;
1560b57cec5SDimitry Andric       auto InsertPos = MBB.begin();
1570b57cec5SDimitry Andric       if (InsertPos->isEHLabel()) // EH pad starts with an EH label
1580b57cec5SDimitry Andric         ++InsertPos;
1598bcb0991SDimitry Andric       Register DstReg = MRI.createVirtualRegister(&WebAssembly::EXNREFRegClass);
1600b57cec5SDimitry Andric       BuildMI(MBB, InsertPos, MBB.begin()->getDebugLoc(),
1610b57cec5SDimitry Andric               TII.get(WebAssembly::CATCH), DstReg);
1620b57cec5SDimitry Andric     }
1630b57cec5SDimitry Andric   }
1640b57cec5SDimitry Andric   return Changed;
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) {
1680b57cec5SDimitry Andric   bool Changed = false;
1690b57cec5SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   for (auto &MBB : MF) {
1720b57cec5SDimitry Andric     auto Pos = MBB.getFirstTerminator();
1730b57cec5SDimitry Andric     if (Pos == MBB.end())
1740b57cec5SDimitry Andric       continue;
1750b57cec5SDimitry Andric     MachineInstr *TI = &*Pos;
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric     switch (TI->getOpcode()) {
1780b57cec5SDimitry Andric     case WebAssembly::CATCHRET: {
1790b57cec5SDimitry Andric       // Replace a catchret with a branch
1800b57cec5SDimitry Andric       MachineBasicBlock *TBB = TI->getOperand(0).getMBB();
1810b57cec5SDimitry Andric       if (!MBB.isLayoutSuccessor(TBB))
1820b57cec5SDimitry Andric         BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::BR))
1830b57cec5SDimitry Andric             .addMBB(TBB);
1840b57cec5SDimitry Andric       TI->eraseFromParent();
1850b57cec5SDimitry Andric       Changed = true;
1860b57cec5SDimitry Andric       break;
1870b57cec5SDimitry Andric     }
1880b57cec5SDimitry Andric     case WebAssembly::CLEANUPRET:
1890b57cec5SDimitry Andric     case WebAssembly::RETHROW_IN_CATCH: {
1900b57cec5SDimitry Andric       // Replace a cleanupret/rethrow_in_catch with a rethrow
1910b57cec5SDimitry Andric       auto *EHPad = getMatchingEHPad(TI);
1920b57cec5SDimitry Andric       auto CatchPos = EHPad->begin();
1930b57cec5SDimitry Andric       if (CatchPos->isEHLabel()) // EH pad starts with an EH label
1940b57cec5SDimitry Andric         ++CatchPos;
1950b57cec5SDimitry Andric       MachineInstr *Catch = &*CatchPos;
1968bcb0991SDimitry Andric       Register ExnReg = Catch->getOperand(0).getReg();
1970b57cec5SDimitry Andric       BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW))
1980b57cec5SDimitry Andric           .addReg(ExnReg);
1990b57cec5SDimitry Andric       TI->eraseFromParent();
2000b57cec5SDimitry Andric       Changed = true;
2010b57cec5SDimitry Andric       break;
2020b57cec5SDimitry Andric     }
2030b57cec5SDimitry Andric     }
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric   return Changed;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables(
2090b57cec5SDimitry Andric     MachineFunction &MF) {
2100b57cec5SDimitry Andric   bool Changed = false;
2110b57cec5SDimitry Andric   for (auto &MBB : MF) {
2120b57cec5SDimitry Andric     for (auto &MI : MBB) {
2130b57cec5SDimitry Andric       if (MI.getOpcode() != WebAssembly::THROW &&
2140b57cec5SDimitry Andric           MI.getOpcode() != WebAssembly::RETHROW)
2150b57cec5SDimitry Andric         continue;
2160b57cec5SDimitry Andric       Changed = true;
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric       // The instruction after the throw should be an unreachable or a branch to
2190b57cec5SDimitry Andric       // another BB that should eventually lead to an unreachable. Delete it
2200b57cec5SDimitry Andric       // because throw itself is a terminator, and also delete successors if
2210b57cec5SDimitry Andric       // any.
2220b57cec5SDimitry Andric       MBB.erase(std::next(MI.getIterator()), MBB.end());
2230b57cec5SDimitry Andric       SmallVector<MachineBasicBlock *, 8> Succs(MBB.succ_begin(),
2240b57cec5SDimitry Andric                                                 MBB.succ_end());
2250b57cec5SDimitry Andric       for (auto *Succ : Succs)
2260b57cec5SDimitry Andric         if (!Succ->isEHPad())
2270b57cec5SDimitry Andric           MBB.removeSuccessor(Succ);
2280b57cec5SDimitry Andric       eraseDeadBBsAndChildren(Succs);
2290b57cec5SDimitry Andric     }
2300b57cec5SDimitry Andric   }
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   return Changed;
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric // Wasm uses 'br_on_exn' instruction to check the tag of an exception. It takes
2360b57cec5SDimitry Andric // exnref type object returned by 'catch', and branches to the destination if it
2370b57cec5SDimitry Andric // matches a given tag. We currently use __cpp_exception symbol to represent the
2380b57cec5SDimitry Andric // tag for all C++ exceptions.
2390b57cec5SDimitry Andric //
2400b57cec5SDimitry Andric // block $l (result i32)
2410b57cec5SDimitry Andric //   ...
2420b57cec5SDimitry Andric //   ;; exnref $e is on the stack at this point
2430b57cec5SDimitry Andric //   br_on_exn $l $e ;; branch to $l with $e's arguments
2440b57cec5SDimitry Andric //   ...
2450b57cec5SDimitry Andric // end
2460b57cec5SDimitry Andric // ;; Here we expect the extracted values are on top of the wasm value stack
2470b57cec5SDimitry Andric // ... Handle exception using values ...
2480b57cec5SDimitry Andric //
2490b57cec5SDimitry Andric // br_on_exn takes an exnref object and branches if it matches the given tag.
2500b57cec5SDimitry Andric // There can be multiple br_on_exn instructions if we want to match for another
2510b57cec5SDimitry Andric // tag, but for now we only test for __cpp_exception tag, and if it does not
2520b57cec5SDimitry Andric // match, i.e., it is a foreign exception, we rethrow it.
2530b57cec5SDimitry Andric //
2540b57cec5SDimitry Andric // In the destination BB that's the target of br_on_exn, extracted exception
2550b57cec5SDimitry Andric // values (in C++'s case a single i32, which represents an exception pointer)
2560b57cec5SDimitry Andric // are placed on top of the wasm stack. Because we can't model wasm stack in
2570b57cec5SDimitry Andric // LLVM instruction, we use 'extract_exception' pseudo instruction to retrieve
2580b57cec5SDimitry Andric // it. The pseudo instruction will be deleted later.
2590b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::addExceptionExtraction(MachineFunction &MF) {
2600b57cec5SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
2618bcb0991SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
2620b57cec5SDimitry Andric   auto *EHInfo = MF.getWasmEHFuncInfo();
2630b57cec5SDimitry Andric   SmallVector<MachineInstr *, 16> ExtractInstrs;
2640b57cec5SDimitry Andric   SmallVector<MachineInstr *, 8> ToDelete;
2650b57cec5SDimitry Andric   for (auto &MBB : MF) {
2660b57cec5SDimitry Andric     for (auto &MI : MBB) {
2670b57cec5SDimitry Andric       if (MI.getOpcode() == WebAssembly::EXTRACT_EXCEPTION_I32) {
2680b57cec5SDimitry Andric         if (MI.getOperand(0).isDead())
2690b57cec5SDimitry Andric           ToDelete.push_back(&MI);
2700b57cec5SDimitry Andric         else
2710b57cec5SDimitry Andric           ExtractInstrs.push_back(&MI);
2720b57cec5SDimitry Andric       }
2730b57cec5SDimitry Andric     }
2740b57cec5SDimitry Andric   }
2750b57cec5SDimitry Andric   bool Changed = !ToDelete.empty() || !ExtractInstrs.empty();
2760b57cec5SDimitry Andric   for (auto *MI : ToDelete)
2770b57cec5SDimitry Andric     MI->eraseFromParent();
2780b57cec5SDimitry Andric   if (ExtractInstrs.empty())
2790b57cec5SDimitry Andric     return Changed;
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric   // Find terminate pads.
2820b57cec5SDimitry Andric   SmallSet<MachineBasicBlock *, 8> TerminatePads;
2830b57cec5SDimitry Andric   for (auto &MBB : MF) {
2840b57cec5SDimitry Andric     for (auto &MI : MBB) {
2850b57cec5SDimitry Andric       if (MI.isCall()) {
2860b57cec5SDimitry Andric         const MachineOperand &CalleeOp = MI.getOperand(0);
2870b57cec5SDimitry Andric         if (CalleeOp.isGlobal() && CalleeOp.getGlobal()->getName() ==
2880b57cec5SDimitry Andric                                        WebAssembly::ClangCallTerminateFn)
2890b57cec5SDimitry Andric           TerminatePads.insert(getMatchingEHPad(&MI));
2900b57cec5SDimitry Andric       }
2910b57cec5SDimitry Andric     }
2920b57cec5SDimitry Andric   }
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric   for (auto *Extract : ExtractInstrs) {
2950b57cec5SDimitry Andric     MachineBasicBlock *EHPad = getMatchingEHPad(Extract);
2960b57cec5SDimitry Andric     assert(EHPad && "No matching EH pad for extract_exception");
2970b57cec5SDimitry Andric     auto CatchPos = EHPad->begin();
2980b57cec5SDimitry Andric     if (CatchPos->isEHLabel()) // EH pad starts with an EH label
2990b57cec5SDimitry Andric       ++CatchPos;
3000b57cec5SDimitry Andric     MachineInstr *Catch = &*CatchPos;
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric     if (Catch->getNextNode() != Extract)
3030b57cec5SDimitry Andric       EHPad->insert(Catch->getNextNode(), Extract->removeFromParent());
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric     // - Before:
3060b57cec5SDimitry Andric     // ehpad:
3070b57cec5SDimitry Andric     //   %exnref:exnref = catch
3080b57cec5SDimitry Andric     //   %exn:i32 = extract_exception
3090b57cec5SDimitry Andric     //   ... use exn ...
3100b57cec5SDimitry Andric     //
3110b57cec5SDimitry Andric     // - After:
3120b57cec5SDimitry Andric     // ehpad:
3130b57cec5SDimitry Andric     //   %exnref:exnref = catch
3140b57cec5SDimitry Andric     //   br_on_exn %thenbb, $__cpp_exception, %exnref
3150b57cec5SDimitry Andric     //   br %elsebb
3160b57cec5SDimitry Andric     // elsebb:
3170b57cec5SDimitry Andric     //   rethrow
3180b57cec5SDimitry Andric     // thenbb:
3190b57cec5SDimitry Andric     //   %exn:i32 = extract_exception
3200b57cec5SDimitry Andric     //   ... use exn ...
3218bcb0991SDimitry Andric     Register ExnReg = Catch->getOperand(0).getReg();
3220b57cec5SDimitry Andric     auto *ThenMBB = MF.CreateMachineBasicBlock();
3230b57cec5SDimitry Andric     auto *ElseMBB = MF.CreateMachineBasicBlock();
3240b57cec5SDimitry Andric     MF.insert(std::next(MachineFunction::iterator(EHPad)), ElseMBB);
3250b57cec5SDimitry Andric     MF.insert(std::next(MachineFunction::iterator(ElseMBB)), ThenMBB);
3260b57cec5SDimitry Andric     ThenMBB->splice(ThenMBB->end(), EHPad, Extract, EHPad->end());
3270b57cec5SDimitry Andric     ThenMBB->transferSuccessors(EHPad);
3280b57cec5SDimitry Andric     EHPad->addSuccessor(ThenMBB);
3290b57cec5SDimitry Andric     EHPad->addSuccessor(ElseMBB);
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric     DebugLoc DL = Extract->getDebugLoc();
3320b57cec5SDimitry Andric     const char *CPPExnSymbol = MF.createExternalSymbolName("__cpp_exception");
3330b57cec5SDimitry Andric     BuildMI(EHPad, DL, TII.get(WebAssembly::BR_ON_EXN))
3340b57cec5SDimitry Andric         .addMBB(ThenMBB)
3350b57cec5SDimitry Andric         .addExternalSymbol(CPPExnSymbol)
3360b57cec5SDimitry Andric         .addReg(ExnReg);
3370b57cec5SDimitry Andric     BuildMI(EHPad, DL, TII.get(WebAssembly::BR)).addMBB(ElseMBB);
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     // When this is a terminate pad with __clang_call_terminate() call, we don't
3400b57cec5SDimitry Andric     // rethrow it anymore and call __clang_call_terminate() with a nullptr
3410b57cec5SDimitry Andric     // argument, which will call std::terminate().
3420b57cec5SDimitry Andric     //
3430b57cec5SDimitry Andric     // - Before:
3440b57cec5SDimitry Andric     // ehpad:
3450b57cec5SDimitry Andric     //   %exnref:exnref = catch
3460b57cec5SDimitry Andric     //   %exn:i32 = extract_exception
3470b57cec5SDimitry Andric     //   call @__clang_call_terminate(%exn)
3480b57cec5SDimitry Andric     //   unreachable
3490b57cec5SDimitry Andric     //
3500b57cec5SDimitry Andric     // - After:
3510b57cec5SDimitry Andric     // ehpad:
3520b57cec5SDimitry Andric     //   %exnref:exnref = catch
3530b57cec5SDimitry Andric     //   br_on_exn %thenbb, $__cpp_exception, %exnref
3540b57cec5SDimitry Andric     //   br %elsebb
3550b57cec5SDimitry Andric     // elsebb:
3560b57cec5SDimitry Andric     //   call @__clang_call_terminate(0)
3570b57cec5SDimitry Andric     //   unreachable
3580b57cec5SDimitry Andric     // thenbb:
3590b57cec5SDimitry Andric     //   %exn:i32 = extract_exception
3600b57cec5SDimitry Andric     //   call @__clang_call_terminate(%exn)
3610b57cec5SDimitry Andric     //   unreachable
3620b57cec5SDimitry Andric     if (TerminatePads.count(EHPad)) {
3630b57cec5SDimitry Andric       Function *ClangCallTerminateFn =
3640b57cec5SDimitry Andric           MF.getFunction().getParent()->getFunction(
3650b57cec5SDimitry Andric               WebAssembly::ClangCallTerminateFn);
3660b57cec5SDimitry Andric       assert(ClangCallTerminateFn &&
3670b57cec5SDimitry Andric              "There is no __clang_call_terminate() function");
3688bcb0991SDimitry Andric       Register Reg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
3698bcb0991SDimitry Andric       BuildMI(ElseMBB, DL, TII.get(WebAssembly::CONST_I32), Reg).addImm(0);
370*5ffd83dbSDimitry Andric       BuildMI(ElseMBB, DL, TII.get(WebAssembly::CALL))
3710b57cec5SDimitry Andric           .addGlobalAddress(ClangCallTerminateFn)
3728bcb0991SDimitry Andric           .addReg(Reg);
3730b57cec5SDimitry Andric       BuildMI(ElseMBB, DL, TII.get(WebAssembly::UNREACHABLE));
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric     } else {
3760b57cec5SDimitry Andric       BuildMI(ElseMBB, DL, TII.get(WebAssembly::RETHROW)).addReg(ExnReg);
3770b57cec5SDimitry Andric       if (EHInfo->hasEHPadUnwindDest(EHPad))
3780b57cec5SDimitry Andric         ElseMBB->addSuccessor(EHInfo->getEHPadUnwindDest(EHPad));
3790b57cec5SDimitry Andric     }
3800b57cec5SDimitry Andric   }
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric   return true;
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric // After the stack is unwound due to a thrown exception, the __stack_pointer
3860b57cec5SDimitry Andric // global can point to an invalid address. This inserts instructions that
3870b57cec5SDimitry Andric // restore __stack_pointer global.
3880b57cec5SDimitry Andric bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) {
3890b57cec5SDimitry Andric   const auto *FrameLowering = static_cast<const WebAssemblyFrameLowering *>(
3900b57cec5SDimitry Andric       MF.getSubtarget().getFrameLowering());
3910b57cec5SDimitry Andric   if (!FrameLowering->needsPrologForEH(MF))
3920b57cec5SDimitry Andric     return false;
3930b57cec5SDimitry Andric   bool Changed = false;
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   for (auto &MBB : MF) {
3960b57cec5SDimitry Andric     if (!MBB.isEHPad())
3970b57cec5SDimitry Andric       continue;
3980b57cec5SDimitry Andric     Changed = true;
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric     // Insert __stack_pointer restoring instructions at the beginning of each EH
4010b57cec5SDimitry Andric     // pad, after the catch instruction. Here it is safe to assume that SP32
4020b57cec5SDimitry Andric     // holds the latest value of __stack_pointer, because the only exception for
4030b57cec5SDimitry Andric     // this case is when a function uses the red zone, but that only happens
4040b57cec5SDimitry Andric     // with leaf functions, and we don't restore __stack_pointer in leaf
4050b57cec5SDimitry Andric     // functions anyway.
4060b57cec5SDimitry Andric     auto InsertPos = MBB.begin();
4070b57cec5SDimitry Andric     if (InsertPos->isEHLabel()) // EH pad starts with an EH label
4080b57cec5SDimitry Andric       ++InsertPos;
4090b57cec5SDimitry Andric     if (InsertPos->getOpcode() == WebAssembly::CATCH)
4100b57cec5SDimitry Andric       ++InsertPos;
411*5ffd83dbSDimitry Andric     FrameLowering->writeSPToGlobal(FrameLowering->getSPReg(MF), MF, MBB,
412*5ffd83dbSDimitry Andric                                    InsertPos, MBB.begin()->getDebugLoc());
4130b57cec5SDimitry Andric   }
4140b57cec5SDimitry Andric   return Changed;
4150b57cec5SDimitry Andric }
416