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