10b57cec5SDimitry Andric //===-- WasmEHPrepare - Prepare excepton handling for WebAssembly --------===// 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 // This transformation is designed for use by code generators which use 100b57cec5SDimitry Andric // WebAssembly exception handling scheme. This currently supports C++ 110b57cec5SDimitry Andric // exceptions. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric // WebAssembly exception handling uses Windows exception IR for the middle level 140b57cec5SDimitry Andric // representation. This pass does the following transformation for every 150b57cec5SDimitry Andric // catchpad block: 160b57cec5SDimitry Andric // (In C-style pseudocode) 170b57cec5SDimitry Andric // 180b57cec5SDimitry Andric // - Before: 190b57cec5SDimitry Andric // catchpad ... 200b57cec5SDimitry Andric // exn = wasm.get.exception(); 210b57cec5SDimitry Andric // selector = wasm.get.selector(); 220b57cec5SDimitry Andric // ... 230b57cec5SDimitry Andric // 240b57cec5SDimitry Andric // - After: 250b57cec5SDimitry Andric // catchpad ... 26e8d8bef9SDimitry Andric // exn = wasm.catch(WebAssembly::CPP_EXCEPTION); 270b57cec5SDimitry Andric // // Only add below in case it's not a single catch (...) 280b57cec5SDimitry Andric // wasm.landingpad.index(index); 290b57cec5SDimitry Andric // __wasm_lpad_context.lpad_index = index; 300b57cec5SDimitry Andric // __wasm_lpad_context.lsda = wasm.lsda(); 310b57cec5SDimitry Andric // _Unwind_CallPersonality(exn); 32349cc55cSDimitry Andric // selector = __wasm_lpad_context.selector; 330b57cec5SDimitry Andric // ... 340b57cec5SDimitry Andric // 350b57cec5SDimitry Andric // 360b57cec5SDimitry Andric // * Background: Direct personality function call 370b57cec5SDimitry Andric // In WebAssembly EH, the VM is responsible for unwinding the stack once an 380b57cec5SDimitry Andric // exception is thrown. After the stack is unwound, the control flow is 390b57cec5SDimitry Andric // transfered to WebAssembly 'catch' instruction. 400b57cec5SDimitry Andric // 410b57cec5SDimitry Andric // Unwinding the stack is not done by libunwind but the VM, so the personality 420b57cec5SDimitry Andric // function in libcxxabi cannot be called from libunwind during the unwinding 430b57cec5SDimitry Andric // process. So after a catch instruction, we insert a call to a wrapper function 440b57cec5SDimitry Andric // in libunwind that in turn calls the real personality function. 450b57cec5SDimitry Andric // 460b57cec5SDimitry Andric // In Itanium EH, if the personality function decides there is no matching catch 470b57cec5SDimitry Andric // clause in a call frame and no cleanup action to perform, the unwinder doesn't 480b57cec5SDimitry Andric // stop there and continues unwinding. But in Wasm EH, the unwinder stops at 490b57cec5SDimitry Andric // every call frame with a catch intruction, after which the personality 500b57cec5SDimitry Andric // function is called from the compiler-generated user code here. 510b57cec5SDimitry Andric // 520b57cec5SDimitry Andric // In libunwind, we have this struct that serves as a communincation channel 530b57cec5SDimitry Andric // between the compiler-generated user code and the personality function in 540b57cec5SDimitry Andric // libcxxabi. 550b57cec5SDimitry Andric // 560b57cec5SDimitry Andric // struct _Unwind_LandingPadContext { 570b57cec5SDimitry Andric // uintptr_t lpad_index; 580b57cec5SDimitry Andric // uintptr_t lsda; 590b57cec5SDimitry Andric // uintptr_t selector; 600b57cec5SDimitry Andric // }; 610b57cec5SDimitry Andric // struct _Unwind_LandingPadContext __wasm_lpad_context = ...; 620b57cec5SDimitry Andric // 630b57cec5SDimitry Andric // And this wrapper in libunwind calls the personality function. 640b57cec5SDimitry Andric // 650b57cec5SDimitry Andric // _Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) { 660b57cec5SDimitry Andric // struct _Unwind_Exception *exception_obj = 670b57cec5SDimitry Andric // (struct _Unwind_Exception *)exception_ptr; 680b57cec5SDimitry Andric // _Unwind_Reason_Code ret = __gxx_personality_v0( 690b57cec5SDimitry Andric // 1, _UA_CLEANUP_PHASE, exception_obj->exception_class, exception_obj, 700b57cec5SDimitry Andric // (struct _Unwind_Context *)__wasm_lpad_context); 710b57cec5SDimitry Andric // return ret; 720b57cec5SDimitry Andric // } 730b57cec5SDimitry Andric // 740b57cec5SDimitry Andric // We pass a landing pad index, and the address of LSDA for the current function 750b57cec5SDimitry Andric // to the wrapper function _Unwind_CallPersonality in libunwind, and we retrieve 760b57cec5SDimitry Andric // the selector after it returns. 770b57cec5SDimitry Andric // 780b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 790b57cec5SDimitry Andric 805f757f3fSDimitry Andric #include "llvm/CodeGen/WasmEHPrepare.h" 8181ad6265SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 8281ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h" 830b57cec5SDimitry Andric #include "llvm/CodeGen/WasmEHFuncInfo.h" 8406c3fb27SDimitry Andric #include "llvm/IR/EHPersonalities.h" 850b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 86480093f4SDimitry Andric #include "llvm/IR/IntrinsicsWebAssembly.h" 87*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 88480093f4SDimitry Andric #include "llvm/InitializePasses.h" 890b57cec5SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h" 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric using namespace llvm; 920b57cec5SDimitry Andric 935f757f3fSDimitry Andric #define DEBUG_TYPE "wasm-eh-prepare" 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric namespace { 965f757f3fSDimitry Andric class WasmEHPrepareImpl { 975f757f3fSDimitry Andric friend class WasmEHPrepare; 985f757f3fSDimitry Andric 990b57cec5SDimitry Andric Type *LPadContextTy = nullptr; // type of 'struct _Unwind_LandingPadContext' 1000b57cec5SDimitry Andric GlobalVariable *LPadContextGV = nullptr; // __wasm_lpad_context 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric // Field addresses of struct _Unwind_LandingPadContext 1030b57cec5SDimitry Andric Value *LPadIndexField = nullptr; // lpad_index field 1040b57cec5SDimitry Andric Value *LSDAField = nullptr; // lsda field 1050b57cec5SDimitry Andric Value *SelectorField = nullptr; // selector 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric Function *ThrowF = nullptr; // wasm.throw() intrinsic 1080b57cec5SDimitry Andric Function *LPadIndexF = nullptr; // wasm.landingpad.index() intrinsic 1090b57cec5SDimitry Andric Function *LSDAF = nullptr; // wasm.lsda() intrinsic 1100b57cec5SDimitry Andric Function *GetExnF = nullptr; // wasm.get.exception() intrinsic 111e8d8bef9SDimitry Andric Function *CatchF = nullptr; // wasm.catch() intrinsic 1120b57cec5SDimitry Andric Function *GetSelectorF = nullptr; // wasm.get.ehselector() intrinsic 1130b57cec5SDimitry Andric FunctionCallee CallPersonalityF = 1140b57cec5SDimitry Andric nullptr; // _Unwind_CallPersonality() wrapper 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric bool prepareThrows(Function &F); 117fe6060f1SDimitry Andric bool prepareEHPads(Function &F); 118fe6060f1SDimitry Andric void prepareEHPad(BasicBlock *BB, bool NeedPersonality, unsigned Index = 0); 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric public: 1215f757f3fSDimitry Andric WasmEHPrepareImpl() = default; 1225f757f3fSDimitry Andric WasmEHPrepareImpl(Type *LPadContextTy_) : LPadContextTy(LPadContextTy_) {} 1235f757f3fSDimitry Andric bool runOnFunction(Function &F); 1245f757f3fSDimitry Andric }; 1255f757f3fSDimitry Andric 1265f757f3fSDimitry Andric class WasmEHPrepare : public FunctionPass { 1275f757f3fSDimitry Andric WasmEHPrepareImpl P; 1285f757f3fSDimitry Andric 1295f757f3fSDimitry Andric public: 1300b57cec5SDimitry Andric static char ID; // Pass identification, replacement for typeid 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric WasmEHPrepare() : FunctionPass(ID) {} 1330b57cec5SDimitry Andric bool doInitialization(Module &M) override; 1345f757f3fSDimitry Andric bool runOnFunction(Function &F) override { return P.runOnFunction(F); } 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric StringRef getPassName() const override { 1370b57cec5SDimitry Andric return "WebAssembly Exception handling preparation"; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric }; 1405f757f3fSDimitry Andric 1410b57cec5SDimitry Andric } // end anonymous namespace 1420b57cec5SDimitry Andric 1435f757f3fSDimitry Andric PreservedAnalyses WasmEHPreparePass::run(Function &F, 1445f757f3fSDimitry Andric FunctionAnalysisManager &) { 1455f757f3fSDimitry Andric auto &Context = F.getContext(); 1465f757f3fSDimitry Andric auto *I32Ty = Type::getInt32Ty(Context); 1475f757f3fSDimitry Andric auto *PtrTy = PointerType::get(Context, 0); 1485f757f3fSDimitry Andric auto *LPadContextTy = 1495f757f3fSDimitry Andric StructType::get(I32Ty /*lpad_index*/, PtrTy /*lsda*/, I32Ty /*selector*/); 1505f757f3fSDimitry Andric WasmEHPrepareImpl P(LPadContextTy); 1515f757f3fSDimitry Andric bool Changed = P.runOnFunction(F); 1525f757f3fSDimitry Andric return Changed ? PreservedAnalyses::none() : PreservedAnalyses ::all(); 1535f757f3fSDimitry Andric } 1545f757f3fSDimitry Andric 1550b57cec5SDimitry Andric char WasmEHPrepare::ID = 0; 1565ffd83dbSDimitry Andric INITIALIZE_PASS_BEGIN(WasmEHPrepare, DEBUG_TYPE, 1575ffd83dbSDimitry Andric "Prepare WebAssembly exceptions", false, false) 1585ffd83dbSDimitry Andric INITIALIZE_PASS_END(WasmEHPrepare, DEBUG_TYPE, "Prepare WebAssembly exceptions", 1590b57cec5SDimitry Andric false, false) 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric FunctionPass *llvm::createWasmEHPass() { return new WasmEHPrepare(); } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric bool WasmEHPrepare::doInitialization(Module &M) { 1640b57cec5SDimitry Andric IRBuilder<> IRB(M.getContext()); 1655f757f3fSDimitry Andric P.LPadContextTy = StructType::get(IRB.getInt32Ty(), // lpad_index 1665f757f3fSDimitry Andric IRB.getPtrTy(), // lsda 1670b57cec5SDimitry Andric IRB.getInt32Ty() // selector 1680b57cec5SDimitry Andric ); 1690b57cec5SDimitry Andric return false; 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric // Erase the specified BBs if the BB does not have any remaining predecessors, 1730b57cec5SDimitry Andric // and also all its dead children. 1740b57cec5SDimitry Andric template <typename Container> 175fe6060f1SDimitry Andric static void eraseDeadBBsAndChildren(const Container &BBs) { 1760b57cec5SDimitry Andric SmallVector<BasicBlock *, 8> WL(BBs.begin(), BBs.end()); 1770b57cec5SDimitry Andric while (!WL.empty()) { 1780b57cec5SDimitry Andric auto *BB = WL.pop_back_val(); 179e8d8bef9SDimitry Andric if (!pred_empty(BB)) 1800b57cec5SDimitry Andric continue; 1810b57cec5SDimitry Andric WL.append(succ_begin(BB), succ_end(BB)); 182fe6060f1SDimitry Andric DeleteDeadBlock(BB); 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1865f757f3fSDimitry Andric bool WasmEHPrepareImpl::runOnFunction(Function &F) { 1870b57cec5SDimitry Andric bool Changed = false; 1880b57cec5SDimitry Andric Changed |= prepareThrows(F); 1890b57cec5SDimitry Andric Changed |= prepareEHPads(F); 1900b57cec5SDimitry Andric return Changed; 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1935f757f3fSDimitry Andric bool WasmEHPrepareImpl::prepareThrows(Function &F) { 1940b57cec5SDimitry Andric Module &M = *F.getParent(); 1950b57cec5SDimitry Andric IRBuilder<> IRB(F.getContext()); 1960b57cec5SDimitry Andric bool Changed = false; 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric // wasm.throw() intinsic, which will be lowered to wasm 'throw' instruction. 1990b57cec5SDimitry Andric ThrowF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_throw); 2000b57cec5SDimitry Andric // Insert an unreachable instruction after a call to @llvm.wasm.throw and 2010b57cec5SDimitry Andric // delete all following instructions within the BB, and delete all the dead 2020b57cec5SDimitry Andric // children of the BB as well. 2030b57cec5SDimitry Andric for (User *U : ThrowF->users()) { 2040b57cec5SDimitry Andric // A call to @llvm.wasm.throw() is only generated from __cxa_throw() 2050b57cec5SDimitry Andric // builtin call within libcxxabi, and cannot be an InvokeInst. 2060b57cec5SDimitry Andric auto *ThrowI = cast<CallInst>(U); 2070b57cec5SDimitry Andric if (ThrowI->getFunction() != &F) 2080b57cec5SDimitry Andric continue; 2090b57cec5SDimitry Andric Changed = true; 2100b57cec5SDimitry Andric auto *BB = ThrowI->getParent(); 211e8d8bef9SDimitry Andric SmallVector<BasicBlock *, 4> Succs(successors(BB)); 212bdd1243dSDimitry Andric BB->erase(std::next(BasicBlock::iterator(ThrowI)), BB->end()); 2130b57cec5SDimitry Andric IRB.SetInsertPoint(BB); 2140b57cec5SDimitry Andric IRB.CreateUnreachable(); 215fe6060f1SDimitry Andric eraseDeadBBsAndChildren(Succs); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric return Changed; 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2215f757f3fSDimitry Andric bool WasmEHPrepareImpl::prepareEHPads(Function &F) { 2225ffd83dbSDimitry Andric Module &M = *F.getParent(); 2235ffd83dbSDimitry Andric IRBuilder<> IRB(F.getContext()); 224fe6060f1SDimitry Andric 225fe6060f1SDimitry Andric SmallVector<BasicBlock *, 16> CatchPads; 226fe6060f1SDimitry Andric SmallVector<BasicBlock *, 16> CleanupPads; 227fe6060f1SDimitry Andric for (BasicBlock &BB : F) { 228fe6060f1SDimitry Andric if (!BB.isEHPad()) 229fe6060f1SDimitry Andric continue; 230fe6060f1SDimitry Andric auto *Pad = BB.getFirstNonPHI(); 231fe6060f1SDimitry Andric if (isa<CatchPadInst>(Pad)) 232fe6060f1SDimitry Andric CatchPads.push_back(&BB); 233fe6060f1SDimitry Andric else if (isa<CleanupPadInst>(Pad)) 234fe6060f1SDimitry Andric CleanupPads.push_back(&BB); 235fe6060f1SDimitry Andric } 236fe6060f1SDimitry Andric if (CatchPads.empty() && CleanupPads.empty()) 237fe6060f1SDimitry Andric return false; 238fe6060f1SDimitry Andric 23906c3fb27SDimitry Andric if (!F.hasPersonalityFn() || 24006c3fb27SDimitry Andric !isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) { 24106c3fb27SDimitry Andric report_fatal_error("Function '" + F.getName() + 24206c3fb27SDimitry Andric "' does not have a correct Wasm personality function " 24306c3fb27SDimitry Andric "'__gxx_wasm_personality_v0'"); 24406c3fb27SDimitry Andric } 2450b57cec5SDimitry Andric assert(F.hasPersonalityFn() && "Personality function not found"); 2460b57cec5SDimitry Andric 24781ad6265SDimitry Andric // __wasm_lpad_context global variable. 24881ad6265SDimitry Andric // This variable should be thread local. If the target does not support TLS, 24981ad6265SDimitry Andric // we depend on CoalesceFeaturesAndStripAtomics to downgrade it to 25081ad6265SDimitry Andric // non-thread-local ones, in which case we don't allow this object to be 25181ad6265SDimitry Andric // linked with other objects using shared memory. 2520b57cec5SDimitry Andric LPadContextGV = cast<GlobalVariable>( 2530b57cec5SDimitry Andric M.getOrInsertGlobal("__wasm_lpad_context", LPadContextTy)); 25481ad6265SDimitry Andric LPadContextGV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel); 25581ad6265SDimitry Andric 256*0fca6ea1SDimitry Andric LPadIndexField = LPadContextGV; 257*0fca6ea1SDimitry Andric LSDAField = IRB.CreateConstInBoundsGEP2_32(LPadContextTy, LPadContextGV, 0, 1, 258*0fca6ea1SDimitry Andric "lsda_gep"); 259*0fca6ea1SDimitry Andric SelectorField = IRB.CreateConstInBoundsGEP2_32(LPadContextTy, LPadContextGV, 260*0fca6ea1SDimitry Andric 0, 2, "selector_gep"); 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric // wasm.landingpad.index() intrinsic, which is to specify landingpad index 2630b57cec5SDimitry Andric LPadIndexF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_landingpad_index); 2640b57cec5SDimitry Andric // wasm.lsda() intrinsic. Returns the address of LSDA table for the current 2650b57cec5SDimitry Andric // function. 2660b57cec5SDimitry Andric LSDAF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_lsda); 2670b57cec5SDimitry Andric // wasm.get.exception() and wasm.get.ehselector() intrinsics. Calls to these 2680b57cec5SDimitry Andric // are generated in clang. 2690b57cec5SDimitry Andric GetExnF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_exception); 2700b57cec5SDimitry Andric GetSelectorF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_ehselector); 2710b57cec5SDimitry Andric 272e8d8bef9SDimitry Andric // wasm.catch() will be lowered down to wasm 'catch' instruction in 273e8d8bef9SDimitry Andric // instruction selection. 274e8d8bef9SDimitry Andric CatchF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_catch); 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric // _Unwind_CallPersonality() wrapper function, which calls the personality 2775f757f3fSDimitry Andric CallPersonalityF = M.getOrInsertFunction("_Unwind_CallPersonality", 2785f757f3fSDimitry Andric IRB.getInt32Ty(), IRB.getPtrTy()); 2790b57cec5SDimitry Andric if (Function *F = dyn_cast<Function>(CallPersonalityF.getCallee())) 2800b57cec5SDimitry Andric F->setDoesNotThrow(); 281fe6060f1SDimitry Andric 282fe6060f1SDimitry Andric unsigned Index = 0; 283fe6060f1SDimitry Andric for (auto *BB : CatchPads) { 284fe6060f1SDimitry Andric auto *CPI = cast<CatchPadInst>(BB->getFirstNonPHI()); 285fe6060f1SDimitry Andric // In case of a single catch (...), we don't need to emit a personalify 286fe6060f1SDimitry Andric // function call 287bdd1243dSDimitry Andric if (CPI->arg_size() == 1 && 288fe6060f1SDimitry Andric cast<Constant>(CPI->getArgOperand(0))->isNullValue()) 289fe6060f1SDimitry Andric prepareEHPad(BB, false); 290fe6060f1SDimitry Andric else 291fe6060f1SDimitry Andric prepareEHPad(BB, true, Index++); 292fe6060f1SDimitry Andric } 293fe6060f1SDimitry Andric 294fe6060f1SDimitry Andric // Cleanup pads don't need a personality function call. 295fe6060f1SDimitry Andric for (auto *BB : CleanupPads) 296fe6060f1SDimitry Andric prepareEHPad(BB, false); 297fe6060f1SDimitry Andric 298fe6060f1SDimitry Andric return true; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 3015ffd83dbSDimitry Andric // Prepare an EH pad for Wasm EH handling. If NeedPersonality is false, Index is 3020b57cec5SDimitry Andric // ignored. 3035f757f3fSDimitry Andric void WasmEHPrepareImpl::prepareEHPad(BasicBlock *BB, bool NeedPersonality, 304fe6060f1SDimitry Andric unsigned Index) { 3050b57cec5SDimitry Andric assert(BB->isEHPad() && "BB is not an EHPad!"); 3060b57cec5SDimitry Andric IRBuilder<> IRB(BB->getContext()); 3075f757f3fSDimitry Andric IRB.SetInsertPoint(BB, BB->getFirstInsertionPt()); 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric auto *FPI = cast<FuncletPadInst>(BB->getFirstNonPHI()); 3100b57cec5SDimitry Andric Instruction *GetExnCI = nullptr, *GetSelectorCI = nullptr; 3110b57cec5SDimitry Andric for (auto &U : FPI->uses()) { 3120b57cec5SDimitry Andric if (auto *CI = dyn_cast<CallInst>(U.getUser())) { 3135ffd83dbSDimitry Andric if (CI->getCalledOperand() == GetExnF) 3140b57cec5SDimitry Andric GetExnCI = CI; 3155ffd83dbSDimitry Andric if (CI->getCalledOperand() == GetSelectorF) 3160b57cec5SDimitry Andric GetSelectorCI = CI; 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric } 3190b57cec5SDimitry Andric 320fe6060f1SDimitry Andric // Cleanup pads do not have any of wasm.get.exception() or 321fe6060f1SDimitry Andric // wasm.get.ehselector() calls. We need to do nothing. 3220b57cec5SDimitry Andric if (!GetExnCI) { 3230b57cec5SDimitry Andric assert(!GetSelectorCI && 3240b57cec5SDimitry Andric "wasm.get.ehselector() cannot exist w/o wasm.get.exception()"); 3250b57cec5SDimitry Andric return; 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 328e8d8bef9SDimitry Andric // Replace wasm.get.exception intrinsic with wasm.catch intrinsic, which will 329e8d8bef9SDimitry Andric // be lowered to wasm 'catch' instruction. We do this mainly because 330e8d8bef9SDimitry Andric // instruction selection cannot handle wasm.get.exception intrinsic's token 331e8d8bef9SDimitry Andric // argument. 332e8d8bef9SDimitry Andric Instruction *CatchCI = 333e8d8bef9SDimitry Andric IRB.CreateCall(CatchF, {IRB.getInt32(WebAssembly::CPP_EXCEPTION)}, "exn"); 334e8d8bef9SDimitry Andric GetExnCI->replaceAllUsesWith(CatchCI); 3350b57cec5SDimitry Andric GetExnCI->eraseFromParent(); 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric // In case it is a catchpad with single catch (...) or a cleanuppad, we don't 3380b57cec5SDimitry Andric // need to call personality function because we don't need a selector. 3395ffd83dbSDimitry Andric if (!NeedPersonality) { 3400b57cec5SDimitry Andric if (GetSelectorCI) { 3410b57cec5SDimitry Andric assert(GetSelectorCI->use_empty() && 3420b57cec5SDimitry Andric "wasm.get.ehselector() still has uses!"); 3430b57cec5SDimitry Andric GetSelectorCI->eraseFromParent(); 3440b57cec5SDimitry Andric } 3450b57cec5SDimitry Andric return; 3460b57cec5SDimitry Andric } 347e8d8bef9SDimitry Andric IRB.SetInsertPoint(CatchCI->getNextNode()); 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric // This is to create a map of <landingpad EH label, landingpad index> in 3500b57cec5SDimitry Andric // SelectionDAGISel, which is to be used in EHStreamer to emit LSDA tables. 3510b57cec5SDimitry Andric // Pseudocode: wasm.landingpad.index(Index); 3520b57cec5SDimitry Andric IRB.CreateCall(LPadIndexF, {FPI, IRB.getInt32(Index)}); 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric // Pseudocode: __wasm_lpad_context.lpad_index = index; 3550b57cec5SDimitry Andric IRB.CreateStore(IRB.getInt32(Index), LPadIndexField); 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric auto *CPI = cast<CatchPadInst>(FPI); 358fe6060f1SDimitry Andric // TODO Sometimes storing the LSDA address every time is not necessary, in 359fe6060f1SDimitry Andric // case it is already set in a dominating EH pad and there is no function call 360fe6060f1SDimitry Andric // between from that EH pad to here. Consider optimizing those cases. 3610b57cec5SDimitry Andric // Pseudocode: __wasm_lpad_context.lsda = wasm.lsda(); 3620b57cec5SDimitry Andric IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField); 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric // Pseudocode: _Unwind_CallPersonality(exn); 365e8d8bef9SDimitry Andric CallInst *PersCI = IRB.CreateCall(CallPersonalityF, CatchCI, 3660b57cec5SDimitry Andric OperandBundleDef("funclet", CPI)); 3670b57cec5SDimitry Andric PersCI->setDoesNotThrow(); 3680b57cec5SDimitry Andric 369349cc55cSDimitry Andric // Pseudocode: int selector = __wasm_lpad_context.selector; 3700b57cec5SDimitry Andric Instruction *Selector = 3710b57cec5SDimitry Andric IRB.CreateLoad(IRB.getInt32Ty(), SelectorField, "selector"); 3720b57cec5SDimitry Andric 3730b57cec5SDimitry Andric // Replace the return value from wasm.get.ehselector() with the selector value 3740b57cec5SDimitry Andric // loaded from __wasm_lpad_context.selector. 3750b57cec5SDimitry Andric assert(GetSelectorCI && "wasm.get.ehselector() call does not exist"); 3760b57cec5SDimitry Andric GetSelectorCI->replaceAllUsesWith(Selector); 3770b57cec5SDimitry Andric GetSelectorCI->eraseFromParent(); 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric void llvm::calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &EHInfo) { 3810b57cec5SDimitry Andric // If an exception is not caught by a catchpad (i.e., it is a foreign 3820b57cec5SDimitry Andric // exception), it will unwind to its parent catchswitch's unwind destination. 3830b57cec5SDimitry Andric // We don't record an unwind destination for cleanuppads because every 3840b57cec5SDimitry Andric // exception should be caught by it. 3850b57cec5SDimitry Andric for (const auto &BB : *F) { 3860b57cec5SDimitry Andric if (!BB.isEHPad()) 3870b57cec5SDimitry Andric continue; 3880b57cec5SDimitry Andric const Instruction *Pad = BB.getFirstNonPHI(); 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric if (const auto *CatchPad = dyn_cast<CatchPadInst>(Pad)) { 3910b57cec5SDimitry Andric const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest(); 3920b57cec5SDimitry Andric if (!UnwindBB) 3930b57cec5SDimitry Andric continue; 3940b57cec5SDimitry Andric const Instruction *UnwindPad = UnwindBB->getFirstNonPHI(); 3950b57cec5SDimitry Andric if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(UnwindPad)) 3960b57cec5SDimitry Andric // Currently there should be only one handler per a catchswitch. 397fe6060f1SDimitry Andric EHInfo.setUnwindDest(&BB, *CatchSwitch->handlers().begin()); 3980b57cec5SDimitry Andric else // cleanuppad 399fe6060f1SDimitry Andric EHInfo.setUnwindDest(&BB, UnwindBB); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric } 403