279 #include "llvm/IR/IntrinsicsWebAssembly.h"
286 using namespace llvm;
288 #define DEBUG_TYPE "wasm-lower-em-ehsjlj"
292 cl::desc(
"The list of function names in which Emscripten-style "
293 "exception handling is enabled (see emscripten "
294 "EMSCRIPTEN_CATCHING_ALLOWED options)"),
298 class WebAssemblyLowerEmscriptenEHSjLj final :
public ModulePass {
317 Type *LongjmpArgsTy =
nullptr;
325 std::set<std::string> EHAllowlistSet;
330 return "WebAssembly Lower Emscripten Exceptions";
336 void handleLongjmpableCallsForEmscriptenSjLj(
337 Function &
F, InstVector &SetjmpTableInsts,
338 InstVector &SetjmpTableSizeInsts,
341 handleLongjmpableCallsForWasmSjLj(
Function &
F, InstVector &SetjmpTableInsts,
342 InstVector &SetjmpTableSizeInsts,
350 PHINode *&CallEmLongjmpBBThrewPHI,
351 PHINode *&CallEmLongjmpBBThrewValuePHI,
355 bool areAllExceptionsAllowed()
const {
return EHAllowlistSet.empty(); }
356 bool supportsException(
const Function *
F)
const {
357 return EnableEmEH && (areAllExceptionsAllowed() ||
358 EHAllowlistSet.count(std::string(
F->getName())));
367 WebAssemblyLowerEmscriptenEHSjLj()
371 assert(!(EnableEmSjLj && EnableWasmSjLj) &&
372 "Two SjLj modes cannot be turned on at the same time");
373 assert(!(EnableEmEH && EnableWasmSjLj) &&
374 "Wasm SjLj should be only used with Wasm EH");
377 bool runOnModule(
Module &M)
override;
387 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
391 return new WebAssemblyLowerEmscriptenEHSjLj();
395 if (
const auto *
F = dyn_cast<const Function>(V)) {
397 if (
F->isIntrinsic())
401 if (
Name ==
"setjmp" ||
Name ==
"longjmp" ||
Name ==
"emscripten_longjmp")
403 return !
F->doesNotThrow();
415 auto *GV = dyn_cast<GlobalVariable>(
M.getOrInsertGlobal(
Name, Ty));
437 OS <<
"_" << *ParamTy;
453 if (!
F->hasFnAttribute(
"wasm-import-module")) {
455 B.addAttribute(
"wasm-import-module",
"env");
458 if (!
F->hasFnAttribute(
"wasm-import-name")) {
460 B.addAttribute(
"wasm-import-name",
F->getName());
470 return IRB.
getIntNTy(
M->getDataLayout().getPointerSizeInBits());
477 M->getDataLayout().getPointerSizeInBits());
485 return IRB.
getIntN(
M->getDataLayout().getPointerSizeInBits(),
C);
494 WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
495 unsigned NumClauses) {
496 if (FindMatchingCatches.
count(NumClauses))
497 return FindMatchingCatches[NumClauses];
502 FTy,
"__cxa_find_matching_catch_" +
Twine(NumClauses + 2), &M);
503 FindMatchingCatches[NumClauses] =
F;
514 Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(
CallBase *CI) {
519 IRB.SetInsertPoint(CI);
531 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI),
Args);
548 if (FnAttrs.contains(Attribute::AllocSize)) {
553 std::tie(SizeArg, NEltArg) = FnAttrs.getAllocSizeArgs();
557 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
561 FnAttrs.removeAttribute(Attribute::NoReturn);
579 Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(
CallBase *CI) {
585 if (InvokeWrappers.
find(Sig) != InvokeWrappers.
end())
586 return InvokeWrappers[Sig];
596 InvokeWrappers[Sig] =
F;
601 if (
auto *CalleeF = dyn_cast<Function>(
Callee))
602 if (CalleeF->isIntrinsic())
609 if (isa<InlineAsm>(
Callee))
617 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
621 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
622 CalleeName ==
"saveSetjmp" || CalleeName ==
"testSetjmp" ||
623 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
627 if (
Callee->getName().startswith(
"__cxa_find_matching_catch_"))
665 if (CalleeName ==
"__cxa_end_catch")
667 if (CalleeName ==
"__cxa_begin_catch" ||
668 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
669 CalleeName ==
"__clang_call_terminate")
674 if (CalleeName ==
"_ZSt9terminatev")
684 return CalleeName ==
"emscripten_asm_const_int" ||
685 CalleeName ==
"emscripten_asm_const_double" ||
686 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
687 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
688 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
706 void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
715 IRB.SetCurrentDebugLocation(
DL);
718 IRB.SetInsertPoint(
BB);
723 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
724 ThrewValueGV->
getName() +
".val");
725 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
726 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
727 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
730 if (!CallEmLongjmpBB) {
733 IRB.SetInsertPoint(CallEmLongjmpBB);
734 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
735 CallEmLongjmpBBThrewValuePHI =
736 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
737 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
738 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
739 IRB.CreateCall(EmLongjmpF,
740 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
741 IRB.CreateUnreachable();
743 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
744 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
749 IRB.SetInsertPoint(ThenBB1);
754 ThrewPtr->
getName() +
".loaded");
755 Value *ThenLabel = IRB.CreateCall(
756 TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize},
"label");
757 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
758 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
761 IRB.SetInsertPoint(EndBB2);
762 IRB.CreateCall(SetTempRet0F, ThrewValue);
763 IRB.CreateBr(EndBB1);
765 IRB.SetInsertPoint(ElseBB1);
766 IRB.CreateBr(EndBB1);
769 IRB.SetInsertPoint(EndBB1);
770 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
778 LongjmpResult = IRB.CreateCall(GetTempRet0F,
None,
"longjmp_result");
781 void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(
Function &
F) {
782 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
788 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
791 if (
auto *II = dyn_cast<InvokeInst>(&
I))
792 SSA.AddAvailableValue(VarID, II->getNormalDest(), II);
794 SSA.AddAvailableValue(VarID, &
BB, &
I);
795 for (
auto &U :
I.uses()) {
796 auto *
User = cast<Instruction>(U.getUser());
797 if (
auto *UserPN = dyn_cast<PHINode>(
User))
798 if (UserPN->getIncomingBlock(U) == &
BB)
802 SSA.AddUse(VarID, &U);
806 SSA.RewriteAllUses(&DT);
817 void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(
Function *LongjmpF,
819 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
828 auto *CI = dyn_cast<CallInst>(U);
830 IRB.SetInsertPoint(CI);
831 Value *Env =
nullptr;
832 if (NewF == EmLongjmpF)
837 IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getInt8PtrTy(),
"env");
839 ToErase.push_back(CI);
842 for (
auto *
I : ToErase)
843 I->eraseFromParent();
847 if (!LongjmpF->
uses().empty()) {
849 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
855 for (
const auto &
BB : *
F)
856 for (
const auto &
I :
BB)
857 if (
const auto *CB = dyn_cast<CallBase>(&
I))
870 Function *SetjmpF =
M.getFunction(
"setjmp");
874 auto *CB = cast<CallBase>(U);
876 if (
BB->getParent() !=
F)
880 if (
auto *II = dyn_cast<InvokeInst>(CB))
883 CI = cast<CallInst>(CB);
884 ToErase.push_back(CI);
887 for (
auto *
I : ToErase)
888 I->eraseFromParent();
891 bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
892 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
897 Function *SetjmpF =
M.getFunction(
"setjmp");
898 Function *LongjmpF =
M.getFunction(
"longjmp");
903 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
904 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
919 "longjmp and _longjmp have different function types");
927 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
928 assert(TPC &&
"Expected a TargetPassConfig");
944 bool Changed =
false;
964 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
967 if (
auto *CB = dyn_cast<CallBase>(U)) {
968 auto *UserF = CB->getFunction();
973 SetjmpUsers.
insert(UserF);
975 SetjmpUsersToNullify.
insert(UserF);
986 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
987 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
988 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
992 assert(EnableEmSjLj || EnableWasmSjLj);
996 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
998 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
1002 IRB.getVoidTy(), {IRB.getInt8PtrTy(), IRB.getInt32Ty()},
false);
1004 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1020 {getAddrIntType(&M), Type::getInt32PtrTy(C), IRB.getInt32Ty()},
1037 if (
F.isDeclaration())
1039 Changed |= runEHOnFunction(
F);
1047 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1052 runSjLjOnFunction(*
F);
1056 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1059 for (
Function *
F : SetjmpUsersToNullify)
1064 for (
auto *V : {ThrewGV, ThrewValueGV})
1065 if (V && V->use_empty())
1066 V->eraseFromParent();
1067 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1068 SaveSetjmpF, TestSetjmpF, WasmLongjmpF, CatchF})
1069 if (V && V->use_empty())
1070 V->eraseFromParent();
1075 bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(
Function &
F) {
1079 bool Changed =
false;
1087 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1090 auto *II = dyn_cast<InvokeInst>(
BB.getTerminator());
1094 LandingPads.
insert(II->getLandingPadInst());
1095 IRB.SetInsertPoint(II);
1098 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1101 Value *Threw = wrapInvoke(II);
1102 ToErase.push_back(II);
1124 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1127 if (!RethrowLongjmpBB) {
1129 IRB.SetInsertPoint(RethrowLongjmpBB);
1130 RethrowLongjmpBBThrewPHI =
1133 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1134 ThrewValueGV->
getName() +
".val");
1135 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1136 IRB.CreateUnreachable();
1141 IRB.SetInsertPoint(II);
1147 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1148 IRB.CreateCondBr(Or,
Tail, RethrowLongjmpBB);
1149 IRB.SetInsertPoint(
Tail);
1150 BB.replaceSuccessorsPhiUsesWith(&
BB,
Tail);
1155 IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
1168 auto *RI = dyn_cast<ResumeInst>(&
I);
1175 IRB.SetInsertPoint(RI);
1176 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1178 IRB.CreateCall(ResumeF, {
Low});
1180 IRB.CreateUnreachable();
1181 ToErase.push_back(RI);
1188 auto *CI = dyn_cast<CallInst>(&
I);
1194 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1198 IRB.SetInsertPoint(CI);
1202 ToErase.push_back(CI);
1209 if (
auto *LPI = dyn_cast<LandingPadInst>(
I))
1212 Changed |= !LandingPads.
empty();
1217 IRB.SetInsertPoint(LPI);
1219 for (
unsigned I = 0,
E = LPI->getNumClauses();
I <
E; ++
I) {
1223 if (LPI->isCatch(
I))
1224 FMCArgs.push_back(
Clause);
1228 Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
1229 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1231 Value *Pair0 = IRB.CreateInsertValue(
Undef, FMCI, 0,
"pair0");
1232 Value *TempRet0 = IRB.CreateCall(GetTempRet0F,
None,
"tempret0");
1233 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1236 ToErase.push_back(LPI);
1241 I->eraseFromParent();
1267 bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(
Function &
F) {
1268 assert(EnableEmSjLj || EnableWasmSjLj);
1286 SplitBlock(Entry, &*Entry->getFirstInsertionPt());
1290 "setjmpTableSize", Entry->getTerminator());
1294 SetjmpTableSize, IRB.getInt32Ty(), IRB.getInt32Ty(), IRB.getInt32(40),
1295 nullptr,
nullptr,
"setjmpTable");
1300 if (
auto *MallocCallI = dyn_cast<Instruction>(MallocCall)) {
1301 MallocCallI->setDebugLoc(FirstDL);
1304 IRB.SetInsertPoint(SetjmpTableSize);
1305 IRB.CreateStore(IRB.getInt32(0), SetjmpTable);
1306 SetjmpTableInsts.push_back(SetjmpTable);
1307 SetjmpTableSizeInsts.push_back(SetjmpTableSize);
1311 Function *SetjmpF =
M.getFunction(
"setjmp");
1313 auto *CB = cast<CallBase>(U);
1315 if (
BB->getParent() != &
F)
1320 SS <<
"In function " +
F.getName() +
1321 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1328 if (
auto *II = dyn_cast<InvokeInst>(CB))
1331 CI = cast<CallInst>(CB);
1339 IRB.SetInsertPoint(
Tail->getFirstNonPHI());
1340 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1347 SetjmpRetPHIs.push_back(SetjmpRet);
1352 IRB.SetInsertPoint(CI);
1354 SetjmpTable, SetjmpTableSize};
1356 IRB.CreateCall(SaveSetjmpF,
Args,
"setjmpTable");
1358 IRB.CreateCall(GetTempRet0F,
None,
"setjmpTableSize");
1359 SetjmpTableInsts.push_back(NewSetjmpTable);
1360 SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
1361 ToErase.push_back(CI);
1366 handleLongjmpableCallsForEmscriptenSjLj(
1367 F, SetjmpTableInsts, SetjmpTableSizeInsts, SetjmpRetPHIs);
1369 handleLongjmpableCallsForWasmSjLj(
F, SetjmpTableInsts, SetjmpTableSizeInsts,
1374 I->eraseFromParent();
1381 if (isa<ReturnInst>(TI))
1382 ExitingInsts.push_back(TI);
1387 for (
auto &
I :
BB) {
1388 if (
auto *CI = dyn_cast<CallInst>(&
I)) {
1391 IsNoReturn |= CalleeF->hasFnAttribute(Attribute::NoReturn);
1393 ExitingInsts.push_back(&
I);
1397 for (
auto *
I : ExitingInsts) {
1402 if (
auto *CB = dyn_cast<CallBase>(
I))
1409 if (
auto *FreeCallI = dyn_cast<CallInst>(Free)) {
1410 if (
auto *BitCastI = dyn_cast<BitCastInst>(FreeCallI->getArgOperand(0)))
1411 BitCastI->setDebugLoc(
DL);
1437 if (
auto *
I = dyn_cast<Instruction>(U.getUser()))
1438 if (
I->getParent() != Entry)
1441 if (
auto *
I = dyn_cast<Instruction>(U.getUser()))
1442 if (
I->getParent() != Entry)
1462 void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1463 Function &
F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
1475 Instruction *SetjmpTable = *SetjmpTableInsts.begin();
1476 Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
1482 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1485 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1492 std::vector<BasicBlock *> BBs;
1497 for (
unsigned I = 0;
I < BBs.size();
I++) {
1500 if (isa<InvokeInst>(&
I)) {
1503 SS <<
"In function " <<
F.getName()
1504 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1505 "restriction that `setjmp` function call and exception cannot be "
1506 "used within the same function:\n";
1510 auto *CI = dyn_cast<CallInst>(&
I);
1520 ". Please consider using EM_JS, or move the "
1521 "EM_ASM into another function.",
1524 Value *Threw =
nullptr;
1526 if (
Callee->getName().startswith(
"__invoke_")) {
1535 if (
auto *LI = dyn_cast<LoadInst>(
I))
1536 if (
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1537 if (GV == ThrewGV) {
1538 Threw = ThrewLI = LI;
1546 if (
auto *
SI = dyn_cast<StoreInst>(
I)) {
1547 if (
auto *GV = dyn_cast<GlobalVariable>(
SI->getPointerOperand())) {
1548 if (GV == ThrewGV &&
1556 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1557 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1562 Threw = wrapInvoke(CI);
1563 ToErase.push_back(CI);
1587 if (supportsException(&
F) &&
canThrow(Callee)) {
1590 ToErase.push_back(
BB->getTerminator());
1593 if (!RethrowExnBB) {
1595 IRB.SetInsertPoint(RethrowExnBB);
1597 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1598 IRB.CreateCall(ResumeF, {Exn});
1599 IRB.CreateUnreachable();
1602 IRB.SetInsertPoint(CI);
1606 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1608 IRB.SetInsertPoint(NormalBB);
1617 ToErase.push_back(
BB->getTerminator());
1623 Value *LongjmpResult =
nullptr;
1625 wrapTestSetjmp(
BB, CI->
getDebugLoc(), Threw, SetjmpTable, SetjmpTableSize,
1626 Label, LongjmpResult, CallEmLongjmpBB,
1627 CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI,
1629 assert(Label && LongjmpResult && EndBB);
1632 IRB.SetInsertPoint(EndBB);
1633 IRB.SetCurrentDebugLocation(EndBB->
getInstList().back().getDebugLoc());
1639 for (
unsigned I = 0;
I < SetjmpRetPHIs.size();
I++) {
1640 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1641 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1646 BBs.push_back(
Tail);
1651 I->eraseFromParent();
1656 if (
const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1657 return CRI->getUnwindDest();
1666 void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1667 Function &
F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
1677 if (!
F.hasPersonalityFn()) {
1681 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1683 cast<Constant>(IRB.CreateBitCast(PersF, IRB.getInt8PtrTy())));
1689 IRB.SetCurrentDebugLocation(FirstDL);
1693 Instruction *SetjmpTable = *SetjmpTableInsts.begin();
1694 Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
1707 BasicBlock *OrigEntry = Entry->getNextNode();
1710 cast<BranchInst>(Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
1715 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1721 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1722 IRB.SetInsertPoint(CatchLongjmpBB);
1723 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1731 Value *LongjmpArgs =
1732 IRB.CreateBitCast(CatchCI, LongjmpArgsTy->
getPointerTo(),
"longjmp.args");
1734 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1736 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1738 Instruction *Env = IRB.CreateLoad(IRB.getInt8PtrTy(), EnvField,
"env");
1740 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1751 IRB.CreateCall(TestSetjmpF, {SetjmpID, SetjmpTable, SetjmpTableSize},
1753 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1754 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1756 IRB.SetInsertPoint(ThenBB);
1757 CallInst *WasmLongjmpCI = IRB.CreateCall(
1759 IRB.CreateUnreachable();
1761 IRB.SetInsertPoint(EndBB);
1763 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1773 IRB.SetInsertPoint(SetjmpDispatchBB);
1774 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1777 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.size());
1782 for (
unsigned I = 0;
I < SetjmpRetPHIs.size();
I++) {
1783 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1784 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1790 for (
auto *
BB = &*
F.begin();
BB;
BB =
BB->getNextNode()) {
1791 for (
auto &
I : *
BB) {
1792 auto *CI = dyn_cast<CallInst>(&
I);
1801 ". Please consider using EM_JS, or move the "
1802 "EM_ASM into another function.",
1807 if (CI == WasmLongjmpCI)
1809 LongjmpableCalls.push_back(CI);
1813 for (
auto *CI : LongjmpableCalls) {
1819 CalleeF->removeFnAttr(Attribute::NoUnwind);
1828 Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
1829 while (!UnwindDest) {
1830 if (
auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
1831 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1834 if (
auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
1841 Value *ParentPad = CPI->getParentPad();
1842 if (isa<ConstantTokenNone>(ParentPad))
1844 FromPad = cast<Instruction>(ParentPad);
1849 UnwindDest = CatchDispatchLongjmpBB;
1854 for (
auto &
BB :
F) {
1855 if (
auto *CSI = dyn_cast<CatchSwitchInst>(
BB.getFirstNonPHI())) {
1856 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1857 IRB.SetInsertPoint(CSI);
1858 ToErase.push_back(CSI);
1859 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1860 CatchDispatchLongjmpBB, 1);
1861 NewCSI->addHandler(*CSI->handler_begin());
1862 NewCSI->takeName(CSI);
1863 CSI->replaceAllUsesWith(NewCSI);
1867 if (
auto *CRI = dyn_cast<CleanupReturnInst>(
BB.getTerminator())) {
1868 if (CRI->unwindsToCaller()) {
1869 IRB.SetInsertPoint(CRI);
1870 ToErase.push_back(CRI);
1871 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1877 I->eraseFromParent();