199d60e0dSHeejin Ahn //===-- WasmEHPrepare - Prepare excepton handling for WebAssembly --------===//
299d60e0dSHeejin Ahn //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
699d60e0dSHeejin Ahn //
799d60e0dSHeejin Ahn //===----------------------------------------------------------------------===//
899d60e0dSHeejin Ahn //
999d60e0dSHeejin Ahn // This transformation is designed for use by code generators which use
10d6f48786SHeejin Ahn // WebAssembly exception handling scheme. This currently supports C++
11d6f48786SHeejin Ahn // exceptions.
1299d60e0dSHeejin Ahn //
1399d60e0dSHeejin Ahn // WebAssembly exception handling uses Windows exception IR for the middle level
1499d60e0dSHeejin Ahn // representation. This pass does the following transformation for every
1599d60e0dSHeejin Ahn // catchpad block:
1699d60e0dSHeejin Ahn // (In C-style pseudocode)
1799d60e0dSHeejin Ahn //
1899d60e0dSHeejin Ahn // - Before:
1999d60e0dSHeejin Ahn //   catchpad ...
2099d60e0dSHeejin Ahn //   exn = wasm.get.exception();
2199d60e0dSHeejin Ahn //   selector = wasm.get.selector();
2299d60e0dSHeejin Ahn //   ...
2399d60e0dSHeejin Ahn //
2499d60e0dSHeejin Ahn // - After:
2599d60e0dSHeejin Ahn //   catchpad ...
26c2c9a3fdSHeejin Ahn //   exn = wasm.catch(WebAssembly::CPP_EXCEPTION);
2799d60e0dSHeejin Ahn //   // Only add below in case it's not a single catch (...)
28d6f48786SHeejin Ahn //   wasm.landingpad.index(index);
2999d60e0dSHeejin Ahn //   __wasm_lpad_context.lpad_index = index;
3099d60e0dSHeejin Ahn //   __wasm_lpad_context.lsda = wasm.lsda();
3199d60e0dSHeejin Ahn //   _Unwind_CallPersonality(exn);
322f88a30cSHeejin Ahn //   selector = __wasm_lpad_context.selector;
3399d60e0dSHeejin Ahn //   ...
3499d60e0dSHeejin Ahn //
3599d60e0dSHeejin Ahn //
3699d60e0dSHeejin Ahn // * Background: Direct personality function call
3799d60e0dSHeejin Ahn // In WebAssembly EH, the VM is responsible for unwinding the stack once an
3899d60e0dSHeejin Ahn // exception is thrown. After the stack is unwound, the control flow is
39d6f48786SHeejin Ahn // transfered to WebAssembly 'catch' instruction.
4099d60e0dSHeejin Ahn //
4199d60e0dSHeejin Ahn // Unwinding the stack is not done by libunwind but the VM, so the personality
4299d60e0dSHeejin Ahn // function in libcxxabi cannot be called from libunwind during the unwinding
4399d60e0dSHeejin Ahn // process. So after a catch instruction, we insert a call to a wrapper function
4499d60e0dSHeejin Ahn // in libunwind that in turn calls the real personality function.
4599d60e0dSHeejin Ahn //
4699d60e0dSHeejin Ahn // In Itanium EH, if the personality function decides there is no matching catch
4799d60e0dSHeejin Ahn // clause in a call frame and no cleanup action to perform, the unwinder doesn't
4899d60e0dSHeejin Ahn // stop there and continues unwinding. But in Wasm EH, the unwinder stops at
4999d60e0dSHeejin Ahn // every call frame with a catch intruction, after which the personality
5099d60e0dSHeejin Ahn // function is called from the compiler-generated user code here.
5199d60e0dSHeejin Ahn //
5299d60e0dSHeejin Ahn // In libunwind, we have this struct that serves as a communincation channel
5399d60e0dSHeejin Ahn // between the compiler-generated user code and the personality function in
5499d60e0dSHeejin Ahn // libcxxabi.
5599d60e0dSHeejin Ahn //
5699d60e0dSHeejin Ahn // struct _Unwind_LandingPadContext {
5799d60e0dSHeejin Ahn //   uintptr_t lpad_index;
5899d60e0dSHeejin Ahn //   uintptr_t lsda;
5999d60e0dSHeejin Ahn //   uintptr_t selector;
6099d60e0dSHeejin Ahn // };
6199d60e0dSHeejin Ahn // struct _Unwind_LandingPadContext __wasm_lpad_context = ...;
6299d60e0dSHeejin Ahn //
6399d60e0dSHeejin Ahn // And this wrapper in libunwind calls the personality function.
6499d60e0dSHeejin Ahn //
6599d60e0dSHeejin Ahn // _Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) {
6699d60e0dSHeejin Ahn //   struct _Unwind_Exception *exception_obj =
6799d60e0dSHeejin Ahn //       (struct _Unwind_Exception *)exception_ptr;
6899d60e0dSHeejin Ahn //   _Unwind_Reason_Code ret = __gxx_personality_v0(
6999d60e0dSHeejin Ahn //       1, _UA_CLEANUP_PHASE, exception_obj->exception_class, exception_obj,
7099d60e0dSHeejin Ahn //       (struct _Unwind_Context *)__wasm_lpad_context);
7199d60e0dSHeejin Ahn //   return ret;
7299d60e0dSHeejin Ahn // }
7399d60e0dSHeejin Ahn //
7499d60e0dSHeejin Ahn // We pass a landing pad index, and the address of LSDA for the current function
7599d60e0dSHeejin Ahn // to the wrapper function _Unwind_CallPersonality in libunwind, and we retrieve
7699d60e0dSHeejin Ahn // the selector after it returns.
7799d60e0dSHeejin Ahn //
7899d60e0dSHeejin Ahn //===----------------------------------------------------------------------===//
7999d60e0dSHeejin Ahn 
80*989f1c72Sserge-sans-paille #include "llvm/CodeGen/MachineBasicBlock.h"
81*989f1c72Sserge-sans-paille #include "llvm/CodeGen/Passes.h"
8233c3fce5SHeejin Ahn #include "llvm/CodeGen/WasmEHFuncInfo.h"
8399d60e0dSHeejin Ahn #include "llvm/IR/IRBuilder.h"
845d986953SReid Kleckner #include "llvm/IR/IntrinsicsWebAssembly.h"
8505da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
8699d60e0dSHeejin Ahn #include "llvm/Transforms/Utils/BasicBlockUtils.h"
8799d60e0dSHeejin Ahn 
8899d60e0dSHeejin Ahn using namespace llvm;
8999d60e0dSHeejin Ahn 
9099d60e0dSHeejin Ahn #define DEBUG_TYPE "wasmehprepare"
9199d60e0dSHeejin Ahn 
9299d60e0dSHeejin Ahn namespace {
9399d60e0dSHeejin Ahn class WasmEHPrepare : public FunctionPass {
9499d60e0dSHeejin Ahn   Type *LPadContextTy = nullptr; // type of 'struct _Unwind_LandingPadContext'
9599d60e0dSHeejin Ahn   GlobalVariable *LPadContextGV = nullptr; // __wasm_lpad_context
9699d60e0dSHeejin Ahn 
9799d60e0dSHeejin Ahn   // Field addresses of struct _Unwind_LandingPadContext
9899d60e0dSHeejin Ahn   Value *LPadIndexField = nullptr; // lpad_index field
9999d60e0dSHeejin Ahn   Value *LSDAField = nullptr;      // lsda field
10099d60e0dSHeejin Ahn   Value *SelectorField = nullptr;  // selector
10199d60e0dSHeejin Ahn 
102095796a3SHeejin Ahn   Function *ThrowF = nullptr;       // wasm.throw() intrinsic
10399d60e0dSHeejin Ahn   Function *LPadIndexF = nullptr;   // wasm.landingpad.index() intrinsic
10499d60e0dSHeejin Ahn   Function *LSDAF = nullptr;        // wasm.lsda() intrinsic
10599d60e0dSHeejin Ahn   Function *GetExnF = nullptr;      // wasm.get.exception() intrinsic
106c2c9a3fdSHeejin Ahn   Function *CatchF = nullptr;       // wasm.catch() intrinsic
10799d60e0dSHeejin Ahn   Function *GetSelectorF = nullptr; // wasm.get.ehselector() intrinsic
10813680223SJames Y Knight   FunctionCallee CallPersonalityF =
10913680223SJames Y Knight       nullptr; // _Unwind_CallPersonality() wrapper
11099d60e0dSHeejin Ahn 
111095796a3SHeejin Ahn   bool prepareThrows(Function &F);
112445f4e74SHeejin Ahn   bool prepareEHPads(Function &F);
113445f4e74SHeejin Ahn   void prepareEHPad(BasicBlock *BB, bool NeedPersonality, unsigned Index = 0);
11499d60e0dSHeejin Ahn 
11599d60e0dSHeejin Ahn public:
11699d60e0dSHeejin Ahn   static char ID; // Pass identification, replacement for typeid
11799d60e0dSHeejin Ahn 
WasmEHPrepare()11899d60e0dSHeejin Ahn   WasmEHPrepare() : FunctionPass(ID) {}
11999d60e0dSHeejin Ahn   bool doInitialization(Module &M) override;
12099d60e0dSHeejin Ahn   bool runOnFunction(Function &F) override;
12199d60e0dSHeejin Ahn 
getPassName() const12299d60e0dSHeejin Ahn   StringRef getPassName() const override {
12399d60e0dSHeejin Ahn     return "WebAssembly Exception handling preparation";
12499d60e0dSHeejin Ahn   }
12599d60e0dSHeejin Ahn };
12699d60e0dSHeejin Ahn } // end anonymous namespace
12799d60e0dSHeejin Ahn 
12899d60e0dSHeejin Ahn char WasmEHPrepare::ID = 0;
1292e983972SHeejin Ahn INITIALIZE_PASS_BEGIN(WasmEHPrepare, DEBUG_TYPE,
1302e983972SHeejin Ahn                       "Prepare WebAssembly exceptions", false, false)
1312e983972SHeejin Ahn INITIALIZE_PASS_END(WasmEHPrepare, DEBUG_TYPE, "Prepare WebAssembly exceptions",
13227c96d3dSGabor Buella                     false, false)
13399d60e0dSHeejin Ahn 
createWasmEHPass()13499d60e0dSHeejin Ahn FunctionPass *llvm::createWasmEHPass() { return new WasmEHPrepare(); }
13599d60e0dSHeejin Ahn 
doInitialization(Module & M)13699d60e0dSHeejin Ahn bool WasmEHPrepare::doInitialization(Module &M) {
13799d60e0dSHeejin Ahn   IRBuilder<> IRB(M.getContext());
13899d60e0dSHeejin Ahn   LPadContextTy = StructType::get(IRB.getInt32Ty(),   // lpad_index
13999d60e0dSHeejin Ahn                                   IRB.getInt8PtrTy(), // lsda
14099d60e0dSHeejin Ahn                                   IRB.getInt32Ty()    // selector
14199d60e0dSHeejin Ahn   );
14299d60e0dSHeejin Ahn   return false;
14399d60e0dSHeejin Ahn }
14499d60e0dSHeejin Ahn 
145095796a3SHeejin Ahn // Erase the specified BBs if the BB does not have any remaining predecessors,
146095796a3SHeejin Ahn // and also all its dead children.
147095796a3SHeejin Ahn template <typename Container>
eraseDeadBBsAndChildren(const Container & BBs)148a48ee9f2SHeejin Ahn static void eraseDeadBBsAndChildren(const Container &BBs) {
149095796a3SHeejin Ahn   SmallVector<BasicBlock *, 8> WL(BBs.begin(), BBs.end());
150095796a3SHeejin Ahn   while (!WL.empty()) {
151095796a3SHeejin Ahn     auto *BB = WL.pop_back_val();
15285d6af39SKazu Hirata     if (!pred_empty(BB))
153095796a3SHeejin Ahn       continue;
154095796a3SHeejin Ahn     WL.append(succ_begin(BB), succ_end(BB));
155a48ee9f2SHeejin Ahn     DeleteDeadBlock(BB);
156095796a3SHeejin Ahn   }
157095796a3SHeejin Ahn }
158095796a3SHeejin Ahn 
runOnFunction(Function & F)15999d60e0dSHeejin Ahn bool WasmEHPrepare::runOnFunction(Function &F) {
160095796a3SHeejin Ahn   bool Changed = false;
161095796a3SHeejin Ahn   Changed |= prepareThrows(F);
162095796a3SHeejin Ahn   Changed |= prepareEHPads(F);
163095796a3SHeejin Ahn   return Changed;
164095796a3SHeejin Ahn }
165095796a3SHeejin Ahn 
prepareThrows(Function & F)166095796a3SHeejin Ahn bool WasmEHPrepare::prepareThrows(Function &F) {
167095796a3SHeejin Ahn   Module &M = *F.getParent();
168095796a3SHeejin Ahn   IRBuilder<> IRB(F.getContext());
169095796a3SHeejin Ahn   bool Changed = false;
170095796a3SHeejin Ahn 
171095796a3SHeejin Ahn   // wasm.throw() intinsic, which will be lowered to wasm 'throw' instruction.
172095796a3SHeejin Ahn   ThrowF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_throw);
17366ce4194SHeejin Ahn   // Insert an unreachable instruction after a call to @llvm.wasm.throw and
17466ce4194SHeejin Ahn   // delete all following instructions within the BB, and delete all the dead
17566ce4194SHeejin Ahn   // children of the BB as well.
17666ce4194SHeejin Ahn   for (User *U : ThrowF->users()) {
177d6f48786SHeejin Ahn     // A call to @llvm.wasm.throw() is only generated from __cxa_throw()
178d6f48786SHeejin Ahn     // builtin call within libcxxabi, and cannot be an InvokeInst.
179095796a3SHeejin Ahn     auto *ThrowI = cast<CallInst>(U);
180095796a3SHeejin Ahn     if (ThrowI->getFunction() != &F)
181095796a3SHeejin Ahn       continue;
182095796a3SHeejin Ahn     Changed = true;
183095796a3SHeejin Ahn     auto *BB = ThrowI->getParent();
1847bc76fd0SKazu Hirata     SmallVector<BasicBlock *, 4> Succs(successors(BB));
185095796a3SHeejin Ahn     auto &InstList = BB->getInstList();
186095796a3SHeejin Ahn     InstList.erase(std::next(BasicBlock::iterator(ThrowI)), InstList.end());
187095796a3SHeejin Ahn     IRB.SetInsertPoint(BB);
188095796a3SHeejin Ahn     IRB.CreateUnreachable();
189a48ee9f2SHeejin Ahn     eraseDeadBBsAndChildren(Succs);
190095796a3SHeejin Ahn   }
191095796a3SHeejin Ahn 
192095796a3SHeejin Ahn   return Changed;
193095796a3SHeejin Ahn }
194095796a3SHeejin Ahn 
prepareEHPads(Function & F)195095796a3SHeejin Ahn bool WasmEHPrepare::prepareEHPads(Function &F) {
1962e983972SHeejin Ahn   Module &M = *F.getParent();
1972e983972SHeejin Ahn   IRBuilder<> IRB(F.getContext());
198445f4e74SHeejin Ahn 
199445f4e74SHeejin Ahn   SmallVector<BasicBlock *, 16> CatchPads;
200445f4e74SHeejin Ahn   SmallVector<BasicBlock *, 16> CleanupPads;
201445f4e74SHeejin Ahn   for (BasicBlock &BB : F) {
202445f4e74SHeejin Ahn     if (!BB.isEHPad())
203445f4e74SHeejin Ahn       continue;
204445f4e74SHeejin Ahn     auto *Pad = BB.getFirstNonPHI();
205445f4e74SHeejin Ahn     if (isa<CatchPadInst>(Pad))
206445f4e74SHeejin Ahn       CatchPads.push_back(&BB);
207445f4e74SHeejin Ahn     else if (isa<CleanupPadInst>(Pad))
208445f4e74SHeejin Ahn       CleanupPads.push_back(&BB);
209445f4e74SHeejin Ahn   }
210445f4e74SHeejin Ahn   if (CatchPads.empty() && CleanupPads.empty())
211445f4e74SHeejin Ahn     return false;
212445f4e74SHeejin Ahn 
21399d60e0dSHeejin Ahn   assert(F.hasPersonalityFn() && "Personality function not found");
21499d60e0dSHeejin Ahn 
215c60d8229SHeejin Ahn   // __wasm_lpad_context global variable.
2164f9b8397SHeejin Ahn   // This variable should be thread local. If the target does not support TLS,
2174f9b8397SHeejin Ahn   // we depend on CoalesceFeaturesAndStripAtomics to downgrade it to
2184f9b8397SHeejin Ahn   // non-thread-local ones, in which case we don't allow this object to be
2194f9b8397SHeejin Ahn   // linked with other objects using shared memory.
22099d60e0dSHeejin Ahn   LPadContextGV = cast<GlobalVariable>(
22199d60e0dSHeejin Ahn       M.getOrInsertGlobal("__wasm_lpad_context", LPadContextTy));
222c60d8229SHeejin Ahn   LPadContextGV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel);
223c60d8229SHeejin Ahn 
22499d60e0dSHeejin Ahn   LPadIndexField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 0,
22599d60e0dSHeejin Ahn                                           "lpad_index_gep");
22699d60e0dSHeejin Ahn   LSDAField =
22799d60e0dSHeejin Ahn       IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 1, "lsda_gep");
22899d60e0dSHeejin Ahn   SelectorField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 2,
22999d60e0dSHeejin Ahn                                          "selector_gep");
23099d60e0dSHeejin Ahn 
23199d60e0dSHeejin Ahn   // wasm.landingpad.index() intrinsic, which is to specify landingpad index
23299d60e0dSHeejin Ahn   LPadIndexF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_landingpad_index);
23399d60e0dSHeejin Ahn   // wasm.lsda() intrinsic. Returns the address of LSDA table for the current
23499d60e0dSHeejin Ahn   // function.
23599d60e0dSHeejin Ahn   LSDAF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_lsda);
23699d60e0dSHeejin Ahn   // wasm.get.exception() and wasm.get.ehselector() intrinsics. Calls to these
23799d60e0dSHeejin Ahn   // are generated in clang.
23899d60e0dSHeejin Ahn   GetExnF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_exception);
23999d60e0dSHeejin Ahn   GetSelectorF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_ehselector);
24099d60e0dSHeejin Ahn 
241c2c9a3fdSHeejin Ahn   // wasm.catch() will be lowered down to wasm 'catch' instruction in
2429724c3cfSHeejin Ahn   // instruction selection.
243c2c9a3fdSHeejin Ahn   CatchF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_catch);
244d6f48786SHeejin Ahn 
24599d60e0dSHeejin Ahn   // _Unwind_CallPersonality() wrapper function, which calls the personality
24613680223SJames Y Knight   CallPersonalityF = M.getOrInsertFunction(
24713680223SJames Y Knight       "_Unwind_CallPersonality", IRB.getInt32Ty(), IRB.getInt8PtrTy());
24813680223SJames Y Knight   if (Function *F = dyn_cast<Function>(CallPersonalityF.getCallee()))
24913680223SJames Y Knight     F->setDoesNotThrow();
250445f4e74SHeejin Ahn 
251445f4e74SHeejin Ahn   unsigned Index = 0;
252445f4e74SHeejin Ahn   for (auto *BB : CatchPads) {
253445f4e74SHeejin Ahn     auto *CPI = cast<CatchPadInst>(BB->getFirstNonPHI());
254445f4e74SHeejin Ahn     // In case of a single catch (...), we don't need to emit a personalify
255445f4e74SHeejin Ahn     // function call
256445f4e74SHeejin Ahn     if (CPI->getNumArgOperands() == 1 &&
257445f4e74SHeejin Ahn         cast<Constant>(CPI->getArgOperand(0))->isNullValue())
258445f4e74SHeejin Ahn       prepareEHPad(BB, false);
259445f4e74SHeejin Ahn     else
260445f4e74SHeejin Ahn       prepareEHPad(BB, true, Index++);
261445f4e74SHeejin Ahn   }
262445f4e74SHeejin Ahn 
263445f4e74SHeejin Ahn   // Cleanup pads don't need a personality function call.
264445f4e74SHeejin Ahn   for (auto *BB : CleanupPads)
265445f4e74SHeejin Ahn     prepareEHPad(BB, false);
266445f4e74SHeejin Ahn 
267445f4e74SHeejin Ahn   return true;
26899d60e0dSHeejin Ahn }
26999d60e0dSHeejin Ahn 
2702e983972SHeejin Ahn // Prepare an EH pad for Wasm EH handling. If NeedPersonality is false, Index is
271d6f48786SHeejin Ahn // ignored.
prepareEHPad(BasicBlock * BB,bool NeedPersonality,unsigned Index)2722e983972SHeejin Ahn void WasmEHPrepare::prepareEHPad(BasicBlock *BB, bool NeedPersonality,
273445f4e74SHeejin Ahn                                  unsigned Index) {
27499d60e0dSHeejin Ahn   assert(BB->isEHPad() && "BB is not an EHPad!");
27599d60e0dSHeejin Ahn   IRBuilder<> IRB(BB->getContext());
27699d60e0dSHeejin Ahn   IRB.SetInsertPoint(&*BB->getFirstInsertionPt());
277d6f48786SHeejin Ahn 
27899d60e0dSHeejin Ahn   auto *FPI = cast<FuncletPadInst>(BB->getFirstNonPHI());
27999d60e0dSHeejin Ahn   Instruction *GetExnCI = nullptr, *GetSelectorCI = nullptr;
28099d60e0dSHeejin Ahn   for (auto &U : FPI->uses()) {
28199d60e0dSHeejin Ahn     if (auto *CI = dyn_cast<CallInst>(U.getUser())) {
282a58b62b4SCraig Topper       if (CI->getCalledOperand() == GetExnF)
28399d60e0dSHeejin Ahn         GetExnCI = CI;
284a58b62b4SCraig Topper       if (CI->getCalledOperand() == GetSelectorF)
28599d60e0dSHeejin Ahn         GetSelectorCI = CI;
28699d60e0dSHeejin Ahn     }
28799d60e0dSHeejin Ahn   }
28899d60e0dSHeejin Ahn 
289561abd83SHeejin Ahn   // Cleanup pads do not have any of wasm.get.exception() or
290561abd83SHeejin Ahn   // wasm.get.ehselector() calls. We need to do nothing.
291d6f48786SHeejin Ahn   if (!GetExnCI) {
292d6f48786SHeejin Ahn     assert(!GetSelectorCI &&
293d6f48786SHeejin Ahn            "wasm.get.ehselector() cannot exist w/o wasm.get.exception()");
294d6f48786SHeejin Ahn     return;
295d6f48786SHeejin Ahn   }
296d6f48786SHeejin Ahn 
297c2c9a3fdSHeejin Ahn   // Replace wasm.get.exception intrinsic with wasm.catch intrinsic, which will
298c2c9a3fdSHeejin Ahn   // be lowered to wasm 'catch' instruction. We do this mainly because
2999724c3cfSHeejin Ahn   // instruction selection cannot handle wasm.get.exception intrinsic's token
3009724c3cfSHeejin Ahn   // argument.
3019724c3cfSHeejin Ahn   Instruction *CatchCI =
3029724c3cfSHeejin Ahn       IRB.CreateCall(CatchF, {IRB.getInt32(WebAssembly::CPP_EXCEPTION)}, "exn");
3039724c3cfSHeejin Ahn   GetExnCI->replaceAllUsesWith(CatchCI);
30499d60e0dSHeejin Ahn   GetExnCI->eraseFromParent();
30599d60e0dSHeejin Ahn 
30699d60e0dSHeejin Ahn   // In case it is a catchpad with single catch (...) or a cleanuppad, we don't
30799d60e0dSHeejin Ahn   // need to call personality function because we don't need a selector.
3082e983972SHeejin Ahn   if (!NeedPersonality) {
30999d60e0dSHeejin Ahn     if (GetSelectorCI) {
31099d60e0dSHeejin Ahn       assert(GetSelectorCI->use_empty() &&
31199d60e0dSHeejin Ahn              "wasm.get.ehselector() still has uses!");
31299d60e0dSHeejin Ahn       GetSelectorCI->eraseFromParent();
31399d60e0dSHeejin Ahn     }
31499d60e0dSHeejin Ahn     return;
31599d60e0dSHeejin Ahn   }
3169724c3cfSHeejin Ahn   IRB.SetInsertPoint(CatchCI->getNextNode());
31799d60e0dSHeejin Ahn 
31899d60e0dSHeejin Ahn   // This is to create a map of <landingpad EH label, landingpad index> in
31999d60e0dSHeejin Ahn   // SelectionDAGISel, which is to be used in EHStreamer to emit LSDA tables.
32099d60e0dSHeejin Ahn   // Pseudocode: wasm.landingpad.index(Index);
32124faf859SHeejin Ahn   IRB.CreateCall(LPadIndexF, {FPI, IRB.getInt32(Index)});
32299d60e0dSHeejin Ahn 
32399d60e0dSHeejin Ahn   // Pseudocode: __wasm_lpad_context.lpad_index = index;
32499d60e0dSHeejin Ahn   IRB.CreateStore(IRB.getInt32(Index), LPadIndexField);
32599d60e0dSHeejin Ahn 
32699d60e0dSHeejin Ahn   auto *CPI = cast<CatchPadInst>(FPI);
327445f4e74SHeejin Ahn   // TODO Sometimes storing the LSDA address every time is not necessary, in
328445f4e74SHeejin Ahn   // case it is already set in a dominating EH pad and there is no function call
329445f4e74SHeejin Ahn   // between from that EH pad to here. Consider optimizing those cases.
33099d60e0dSHeejin Ahn   // Pseudocode: __wasm_lpad_context.lsda = wasm.lsda();
33199d60e0dSHeejin Ahn   IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField);
33299d60e0dSHeejin Ahn 
33399d60e0dSHeejin Ahn   // Pseudocode: _Unwind_CallPersonality(exn);
3349724c3cfSHeejin Ahn   CallInst *PersCI = IRB.CreateCall(CallPersonalityF, CatchCI,
335d6f48786SHeejin Ahn                                     OperandBundleDef("funclet", CPI));
33699d60e0dSHeejin Ahn   PersCI->setDoesNotThrow();
33799d60e0dSHeejin Ahn 
3382f88a30cSHeejin Ahn   // Pseudocode: int selector = __wasm_lpad_context.selector;
33914359ef1SJames Y Knight   Instruction *Selector =
34014359ef1SJames Y Knight       IRB.CreateLoad(IRB.getInt32Ty(), SelectorField, "selector");
34199d60e0dSHeejin Ahn 
34299d60e0dSHeejin Ahn   // Replace the return value from wasm.get.ehselector() with the selector value
34399d60e0dSHeejin Ahn   // loaded from __wasm_lpad_context.selector.
34499d60e0dSHeejin Ahn   assert(GetSelectorCI && "wasm.get.ehselector() call does not exist");
34599d60e0dSHeejin Ahn   GetSelectorCI->replaceAllUsesWith(Selector);
34699d60e0dSHeejin Ahn   GetSelectorCI->eraseFromParent();
34799d60e0dSHeejin Ahn }
34833c3fce5SHeejin Ahn 
calculateWasmEHInfo(const Function * F,WasmEHFuncInfo & EHInfo)34933c3fce5SHeejin Ahn void llvm::calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &EHInfo) {
350d6f48786SHeejin Ahn   // If an exception is not caught by a catchpad (i.e., it is a foreign
351d6f48786SHeejin Ahn   // exception), it will unwind to its parent catchswitch's unwind destination.
352d6f48786SHeejin Ahn   // We don't record an unwind destination for cleanuppads because every
353d6f48786SHeejin Ahn   // exception should be caught by it.
35433c3fce5SHeejin Ahn   for (const auto &BB : *F) {
35533c3fce5SHeejin Ahn     if (!BB.isEHPad())
35633c3fce5SHeejin Ahn       continue;
35733c3fce5SHeejin Ahn     const Instruction *Pad = BB.getFirstNonPHI();
35833c3fce5SHeejin Ahn 
35933c3fce5SHeejin Ahn     if (const auto *CatchPad = dyn_cast<CatchPadInst>(Pad)) {
36033c3fce5SHeejin Ahn       const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest();
36133c3fce5SHeejin Ahn       if (!UnwindBB)
36233c3fce5SHeejin Ahn         continue;
36333c3fce5SHeejin Ahn       const Instruction *UnwindPad = UnwindBB->getFirstNonPHI();
36433c3fce5SHeejin Ahn       if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(UnwindPad))
36533c3fce5SHeejin Ahn         // Currently there should be only one handler per a catchswitch.
366a08e609dSHeejin Ahn         EHInfo.setUnwindDest(&BB, *CatchSwitch->handlers().begin());
36733c3fce5SHeejin Ahn       else // cleanuppad
368a08e609dSHeejin Ahn         EHInfo.setUnwindDest(&BB, UnwindBB);
36933c3fce5SHeejin Ahn     }
37033c3fce5SHeejin Ahn   }
37133c3fce5SHeejin Ahn }
372