279#include "llvm/IR/IntrinsicsWebAssembly.h"
289#define DEBUG_TYPE "wasm-lower-em-ehsjlj"
293 cl::desc(
"The list of function names in which Emscripten-style "
294 "exception handling is enabled (see emscripten "
295 "EMSCRIPTEN_CATCHING_ALLOWED options)"),
299class WebAssemblyLowerEmscriptenEHSjLj final :
public ModulePass {
318 Type *LongjmpArgsTy =
nullptr;
326 std::set<std::string> EHAllowlistSet;
331 return "WebAssembly Lower Emscripten Exceptions";
337 void handleLongjmpableCallsForEmscriptenSjLj(
338 Function &
F, InstVector &SetjmpTableInsts,
339 InstVector &SetjmpTableSizeInsts,
342 handleLongjmpableCallsForWasmSjLj(
Function &
F, InstVector &SetjmpTableInsts,
343 InstVector &SetjmpTableSizeInsts,
351 PHINode *&CallEmLongjmpBBThrewPHI,
352 PHINode *&CallEmLongjmpBBThrewValuePHI,
356 bool areAllExceptionsAllowed()
const {
return EHAllowlistSet.empty(); }
357 bool supportsException(
const Function *
F)
const {
358 return EnableEmEH && (areAllExceptionsAllowed() ||
359 EHAllowlistSet.count(std::string(
F->getName())));
368 WebAssemblyLowerEmscriptenEHSjLj()
372 assert(!(EnableEmSjLj && EnableWasmSjLj) &&
373 "Two SjLj modes cannot be turned on at the same time");
374 assert(!(EnableEmEH && EnableWasmSjLj) &&
375 "Wasm SjLj should be only used with Wasm EH");
386char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
388 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
392 return new WebAssemblyLowerEmscriptenEHSjLj();
396 if (
const auto *
F = dyn_cast<const Function>(V)) {
398 if (
F->isIntrinsic())
402 if (
Name ==
"setjmp" ||
Name ==
"longjmp" ||
Name ==
"emscripten_longjmp")
404 return !
F->doesNotThrow();
416 auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal(
Name, Ty));
436 OS << *FTy->getReturnType();
437 for (
Type *ParamTy : FTy->params())
438 OS <<
"_" << *ParamTy;
445 std::replace(Sig.begin(), Sig.end(),
',',
'.');
454 if (!
F->hasFnAttribute(
"wasm-import-module")) {
456 B.addAttribute(
"wasm-import-module",
"env");
459 if (!
F->hasFnAttribute(
"wasm-import-name")) {
461 B.addAttribute(
"wasm-import-name",
F->getName());
471 return IRB.
getIntNTy(M->getDataLayout().getPointerSizeInBits());
478 return PointerType::getUnqual(M->getContext());
486 return IRB.
getIntN(M->getDataLayout().getPointerSizeInBits(),
C);
495WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
496 unsigned NumClauses) {
497 if (FindMatchingCatches.
count(NumClauses))
498 return FindMatchingCatches[NumClauses];
499 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
501 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
503 FTy,
"__cxa_find_matching_catch_" +
Twine(NumClauses + 2), &M);
504 FindMatchingCatches[NumClauses] =
F;
515Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(
CallBase *CI) {
520 IRB.SetInsertPoint(CI);
532 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
549 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
552 auto [SizeArg, NEltArg] = *
Args;
555 NEltArg = *NEltArg + 1;
556 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
560 FnAttrs.removeAttribute(Attribute::NoReturn);
585 return InvokeWrappers[Sig];
588 ArgTys.
push_back(PointerType::getUnqual(CalleeFTy));
590 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
592 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
593 CalleeFTy->isVarArg());
595 InvokeWrappers[Sig] =
F;
600 if (
auto *CalleeF = dyn_cast<Function>(Callee))
601 if (CalleeF->isIntrinsic())
608 if (isa<InlineAsm>(Callee))
610 StringRef CalleeName = Callee->getName();
616 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
620 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
621 CalleeName ==
"saveSetjmp" || CalleeName ==
"testSetjmp" ||
622 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
626 if (Callee->getName().startswith(
"__cxa_find_matching_catch_"))
664 if (CalleeName ==
"__cxa_end_catch")
666 if (CalleeName ==
"__cxa_begin_catch" ||
667 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
668 CalleeName ==
"__clang_call_terminate")
673 if (CalleeName ==
"_ZSt9terminatev")
681 StringRef CalleeName = Callee->getName();
683 return CalleeName ==
"emscripten_asm_const_int" ||
684 CalleeName ==
"emscripten_asm_const_double" ||
685 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
686 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
687 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
705void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
714 IRB.SetCurrentDebugLocation(
DL);
717 IRB.SetInsertPoint(BB);
722 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
723 ThrewValueGV->
getName() +
".val");
724 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
725 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
726 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
729 if (!CallEmLongjmpBB) {
732 IRB.SetInsertPoint(CallEmLongjmpBB);
733 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
734 CallEmLongjmpBBThrewValuePHI =
735 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
736 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
737 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
738 IRB.CreateCall(EmLongjmpF,
739 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
740 IRB.CreateUnreachable();
742 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
743 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
748 IRB.SetInsertPoint(ThenBB1);
753 ThrewPtr->
getName() +
".loaded");
754 Value *ThenLabel = IRB.CreateCall(
755 TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize},
"label");
756 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
757 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
760 IRB.SetInsertPoint(EndBB2);
761 IRB.CreateCall(SetTempRet0F, ThrewValue);
762 IRB.CreateBr(EndBB1);
764 IRB.SetInsertPoint(ElseBB1);
765 IRB.CreateBr(EndBB1);
768 IRB.SetInsertPoint(EndBB1);
769 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
777 LongjmpResult = IRB.CreateCall(GetTempRet0F, std::nullopt,
"longjmp_result");
780void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(
Function &
F) {
781 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
787 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
790 if (
auto *II = dyn_cast<InvokeInst>(&
I))
791 SSA.AddAvailableValue(VarID, II->getNormalDest(), II);
793 SSA.AddAvailableValue(VarID, &BB, &
I);
794 for (
auto &U :
I.uses()) {
795 auto *
User = cast<Instruction>(
U.getUser());
796 if (
auto *UserPN = dyn_cast<PHINode>(
User))
797 if (UserPN->getIncomingBlock(U) == &BB)
801 SSA.AddUse(VarID, &U);
805 SSA.RewriteAllUses(&DT);
816void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(
Function *LongjmpF,
818 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
827 auto *CI = dyn_cast<CallInst>(U);
829 IRB.SetInsertPoint(CI);
830 Value *Env =
nullptr;
831 if (NewF == EmLongjmpF)
835 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
840 for (
auto *
I : ToErase)
841 I->eraseFromParent();
845 if (!LongjmpF->
uses().empty()) {
847 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
853 for (
const auto &BB : *
F)
854 for (
const auto &
I : BB)
855 if (
const auto *CB = dyn_cast<CallBase>(&
I))
868 Function *SetjmpF = M.getFunction(
"setjmp");
872 auto *CB = cast<CallBase>(U);
878 if (
auto *II = dyn_cast<InvokeInst>(CB))
881 CI = cast<CallInst>(CB);
885 for (
auto *
I : ToErase)
886 I->eraseFromParent();
889bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
890 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
895 Function *SetjmpF =
M.getFunction(
"setjmp");
896 Function *LongjmpF =
M.getFunction(
"longjmp");
901 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
902 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
917 "longjmp and _longjmp have different function types");
925 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
926 assert(TPC &&
"Expected a TargetPassConfig");
935 FunctionType::get(IRB.getInt32Ty(),
false),
"getTempRet0", &M);
937 FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
942 bool Changed =
false;
948 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
954 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
962 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
965 if (
auto *CB = dyn_cast<CallBase>(U)) {
966 auto *UserF = CB->getFunction();
971 SetjmpUsers.
insert(UserF);
973 SetjmpUsersToNullify.
insert(UserF);
984 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
985 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
986 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
990 assert(EnableEmSjLj || EnableWasmSjLj);
994 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
996 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
998 Type *Int8PtrTy = IRB.getPtrTy();
1001 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
1003 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1007 Type *Int8PtrTy = IRB.getPtrTy();
1008 Type *Int32PtrTy = IRB.getPtrTy();
1014 {SetjmpFTy->getParamType(0),
Int32Ty, Int32PtrTy,
Int32Ty},
false);
1018 FTy = FunctionType::get(
Int32Ty,
1035 if (
F.isDeclaration())
1037 Changed |= runEHOnFunction(
F);
1045 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1050 runSjLjOnFunction(*
F);
1054 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1057 for (
Function *
F : SetjmpUsersToNullify)
1062 for (
auto *V : {ThrewGV, ThrewValueGV})
1063 if (V &&
V->use_empty())
1064 V->eraseFromParent();
1065 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1066 SaveSetjmpF, TestSetjmpF, WasmLongjmpF, CatchF})
1067 if (V &&
V->use_empty())
1068 V->eraseFromParent();
1073bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(
Function &
F) {
1077 bool Changed =
false;
1085 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1088 auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
1092 LandingPads.
insert(II->getLandingPadInst());
1093 IRB.SetInsertPoint(II);
1096 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1099 Value *Threw = wrapInvoke(II);
1122 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1125 if (!RethrowLongjmpBB) {
1127 IRB.SetInsertPoint(RethrowLongjmpBB);
1128 RethrowLongjmpBBThrewPHI =
1130 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1131 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1132 ThrewValueGV->
getName() +
".val");
1133 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1134 IRB.CreateUnreachable();
1136 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1139 IRB.SetInsertPoint(II);
1145 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1146 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1147 IRB.SetInsertPoint(
Tail);
1148 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1153 IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
1166 auto *RI = dyn_cast<ResumeInst>(&
I);
1172 Value *Input = RI->getValue();
1173 IRB.SetInsertPoint(RI);
1174 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1176 IRB.CreateCall(ResumeF, {
Low});
1178 IRB.CreateUnreachable();
1186 auto *CI = dyn_cast<CallInst>(&
I);
1192 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1196 IRB.SetInsertPoint(CI);
1207 if (
auto *LPI = dyn_cast<LandingPadInst>(
I))
1210 Changed |= !LandingPads.
empty();
1215 IRB.SetInsertPoint(LPI);
1217 for (
unsigned I = 0,
E = LPI->getNumClauses();
I <
E; ++
I) {
1221 if (LPI->isCatch(
I))
1226 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1227 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1229 Value *Pair0 = IRB.CreateInsertValue(Poison, FMCI, 0,
"pair0");
1230 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, std::nullopt,
"tempret0");
1231 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1239 I->eraseFromParent();
1261 return DILocation::get(SP->
getContext(), SP->getLine(), 1, SP);
1265bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(
Function &
F) {
1266 assert(EnableEmSjLj || EnableWasmSjLj);
1284 SplitBlock(Entry, &*Entry->getFirstInsertionPt());
1288 "setjmpTableSize", Entry->getTerminator());
1293 IRB.SetInsertPoint(SetjmpTableSize);
1294 auto *SetjmpTable = IRB.CreateMalloc(IntPtrTy, IRB.getInt32Ty(), size,
1295 nullptr,
nullptr,
"setjmpTable");
1296 SetjmpTable->setDebugLoc(FirstDL);
1300 if (
auto *MallocCallI = dyn_cast<Instruction>(MallocCall)) {
1301 MallocCallI->setDebugLoc(FirstDL);
1304 IRB.CreateStore(IRB.getInt32(0), SetjmpTable);
1305 SetjmpTableInsts.
push_back(SetjmpTable);
1306 SetjmpTableSizeInsts.
push_back(SetjmpTableSize);
1310 Function *SetjmpF =
M.getFunction(
"setjmp");
1312 auto *CB = cast<CallBase>(U);
1319 SS <<
"In function " +
F.getName() +
1320 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1327 if (
auto *II = dyn_cast<InvokeInst>(CB))
1330 CI = cast<CallInst>(CB);
1338 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1339 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1351 IRB.SetInsertPoint(CI);
1353 SetjmpTable, SetjmpTableSize};
1355 IRB.CreateCall(SaveSetjmpF, Args,
"setjmpTable");
1357 IRB.CreateCall(GetTempRet0F, std::nullopt,
"setjmpTableSize");
1358 SetjmpTableInsts.
push_back(NewSetjmpTable);
1359 SetjmpTableSizeInsts.
push_back(NewSetjmpTableSize);
1365 handleLongjmpableCallsForEmscriptenSjLj(
1366 F, SetjmpTableInsts, SetjmpTableSizeInsts, SetjmpRetPHIs);
1368 handleLongjmpableCallsForWasmSjLj(
F, SetjmpTableInsts, SetjmpTableSizeInsts,
1373 I->eraseFromParent();
1380 if (isa<ReturnInst>(TI))
1386 for (
auto &
I : BB) {
1387 if (
auto *CI = dyn_cast<CallInst>(&
I)) {
1390 IsNoReturn |= CalleeF->hasFnAttribute(Attribute::NoReturn);
1396 for (
auto *
I : ExitingInsts) {
1401 if (
auto *CB = dyn_cast<CallBase>(
I))
1404 IRB.SetInsertPoint(
I);
1405 auto *
Free = IRB.CreateFree(SetjmpTable, Bundles);
1423 SetjmpTableSSA.
Initialize(PointerType::get(
C, 0),
"setjmpTable");
1431 if (
auto *
I = dyn_cast<Instruction>(
U.getUser()))
1432 if (
I->getParent() != Entry)
1435 if (
auto *
I = dyn_cast<Instruction>(
U.getUser()))
1436 if (
I->getParent() != Entry)
1456void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1457 Function &
F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
1469 Instruction *SetjmpTable = *SetjmpTableInsts.begin();
1470 Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
1476 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1479 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1486 std::vector<BasicBlock *> BBs;
1491 for (
unsigned I = 0;
I < BBs.size();
I++) {
1494 if (isa<InvokeInst>(&
I)) {
1497 SS <<
"In function " <<
F.getName()
1498 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1499 "restriction that `setjmp` function call and exception cannot be "
1500 "used within the same function:\n";
1504 auto *CI = dyn_cast<CallInst>(&
I);
1514 ". Please consider using EM_JS, or move the "
1515 "EM_ASM into another function.",
1518 Value *Threw =
nullptr;
1520 if (
Callee->getName().startswith(
"__invoke_")) {
1529 if (
auto *LI = dyn_cast<LoadInst>(
I))
1530 if (
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1531 if (GV == ThrewGV) {
1532 Threw = ThrewLI = LI;
1540 if (
auto *SI = dyn_cast<StoreInst>(
I)) {
1541 if (
auto *GV = dyn_cast<GlobalVariable>(
SI->getPointerOperand())) {
1542 if (GV == ThrewGV &&
1550 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1551 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1556 Threw = wrapInvoke(CI);
1581 if (supportsException(&
F) &&
canThrow(Callee)) {
1587 if (!RethrowExnBB) {
1589 IRB.SetInsertPoint(RethrowExnBB);
1591 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1592 IRB.CreateCall(ResumeF, {Exn});
1593 IRB.CreateUnreachable();
1596 IRB.SetInsertPoint(CI);
1600 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1602 IRB.SetInsertPoint(NormalBB);
1617 Value *LongjmpResult =
nullptr;
1619 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, SetjmpTable, SetjmpTableSize,
1620 Label, LongjmpResult, CallEmLongjmpBB,
1621 CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI,
1623 assert(Label && LongjmpResult && EndBB);
1626 IRB.SetInsertPoint(EndBB);
1633 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1634 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1635 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1645 I->eraseFromParent();
1650 if (
const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1651 return CRI->getUnwindDest();
1660void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1661 Function &
F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
1671 if (!
F.hasPersonalityFn()) {
1674 FunctionType::get(IRB.getInt32Ty(),
true);
1675 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1677 cast<Constant>(IRB.CreateBitCast(PersF, IRB.getPtrTy())));
1683 IRB.SetCurrentDebugLocation(FirstDL);
1687 Instruction *SetjmpTable = *SetjmpTableInsts.begin();
1688 Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
1701 BasicBlock *OrigEntry = Entry->getNextNode();
1704 cast<BranchInst>(Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
1709 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1715 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1716 IRB.SetInsertPoint(CatchLongjmpBB);
1717 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1726 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1728 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1730 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1732 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1743 IRB.CreateCall(TestSetjmpF, {SetjmpID, SetjmpTable, SetjmpTableSize},
1745 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1746 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1748 IRB.SetInsertPoint(ThenBB);
1749 CallInst *WasmLongjmpCI = IRB.CreateCall(
1751 IRB.CreateUnreachable();
1753 IRB.SetInsertPoint(EndBB);
1755 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1765 IRB.SetInsertPoint(SetjmpDispatchBB);
1766 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1769 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1774 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1775 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1776 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1782 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1783 for (
auto &
I : *BB) {
1784 auto *CI = dyn_cast<CallInst>(&
I);
1793 ". Please consider using EM_JS, or move the "
1794 "EM_ASM into another function.",
1799 if (CI == WasmLongjmpCI)
1805 for (
auto *CI : LongjmpableCalls) {
1811 CalleeF->removeFnAttr(Attribute::NoUnwind);
1820 Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
1821 while (!UnwindDest) {
1822 if (
auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
1823 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1826 if (
auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
1833 Value *ParentPad = CPI->getParentPad();
1834 if (isa<ConstantTokenNone>(ParentPad))
1836 FromPad = cast<Instruction>(ParentPad);
1841 UnwindDest = CatchDispatchLongjmpBB;
1846 for (
auto &BB :
F) {
1847 if (
auto *CSI = dyn_cast<CatchSwitchInst>(BB.getFirstNonPHI())) {
1848 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1849 IRB.SetInsertPoint(CSI);
1851 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1852 CatchDispatchLongjmpBB, 1);
1853 NewCSI->addHandler(*CSI->handler_begin());
1854 NewCSI->takeName(CSI);
1855 CSI->replaceAllUsesWith(NewCSI);
1859 if (
auto *CRI = dyn_cast<CleanupReturnInst>(BB.getTerminator())) {
1860 if (CRI->unwindsToCaller()) {
1861 IRB.SetInsertPoint(CRI);
1863 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1869 I->eraseFromParent();
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Target-Independent Code Generator Pass Configuration Options pass.
static void nullifySetjmp(Function *F)
static bool canLongjmp(const Value *Callee)
static cl::list< std::string > EHAllowlist("emscripten-cxx-exceptions-allowed", cl::desc("The list of function names in which Emscripten-style " "exception handling is enabled (see emscripten " "EMSCRIPTEN_CATCHING_ALLOWED options)"), cl::CommaSeparated)
static Type * getAddrPtrType(Module *M)
static std::string getSignature(FunctionType *FTy)
static Type * getAddrIntType(Module *M)
static bool canThrow(const Value *V)
static BasicBlock * getCleanupRetUnwindDest(const CleanupPadInst *CPI)
static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore, DISubprogram *SP)
static bool containsLongjmpableCalls(const Function *F)
static Value * getAddrSizeInt(Module *M, uint64_t C)
static Function * getEmscriptenFunction(FunctionType *Ty, const Twine &Name, Module *M)
static GlobalVariable * getGlobalVariable(Module &M, Type *Ty, WebAssemblyTargetMachine &TM, const char *Name)
static bool isEmAsmCall(const Value *Callee)
This file provides WebAssembly-specific target descriptions.
This file declares the WebAssembly-specific subclass of TargetMachine.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AttributeSet getFnAttrs() const
The function attributes are returned.
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)
Create an AttributeList with the specified parameters in it.
AttributeSet getRetAttrs() const
The attributes for the ret value are returned.
AttributeSet getParamAttrs(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
static AttributeSet get(LLVMContext &C, const AttrBuilder &B)
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Function * getParent() const
Return the enclosing method, or null if none.
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
const Instruction & back() const
static BinaryOperator * Create(BinaryOps Op, Value *S1, Value *S2, const Twine &Name=Twine(), Instruction *InsertBefore=nullptr)
Construct a binary instruction, given the opcode and the two operands.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
std::optional< OperandBundleUse > getOperandBundle(StringRef Name) const
Return an operand bundle by name, if present.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
Value * getCalledOperand() const
void setAttributes(AttributeList A)
Set the parameter attributes for this call.
Value * getArgOperand(unsigned i) const
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
FunctionType * getFunctionType() const
void removeFnAttr(Attribute::AttrKind Kind)
Removes the attribute from the function.
unsigned arg_size() const
AttributeList getAttributes() const
Return the parameter attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
void addHandler(BasicBlock *Dest)
Add an entry to the switch instruction... Note: This action invalidates handler_end().
static Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
static ConstantTokenNone * get(LLVMContext &Context)
Return the ConstantTokenNone.
This is an important base class in LLVM.
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Module * getParent()
Get the module that this global value is contained inside of...
PointerType * getType() const
Global values are always pointers.
@ ExternalLinkage
Externally visible function.
IntegerType * getIntNTy(unsigned N)
Fetch the type representing an N-bit integer.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
ConstantInt * getIntN(unsigned N, uint64_t C)
Get a constant N-bit value, zero extended or truncated from a 64-bit value.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
This is an important class for using LLVM in a threaded context.
The landingpad instruction holds all of the information necessary to generate correct exception handl...
An instruction for reading from memory.
LLVMContext & getContext() const
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
LLVMContext & getContext() const
Get the global data context.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
static PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Helper class for SSA formation on a set of values defined in multiple blocks.
Helper class for SSA formation on a set of values defined in multiple blocks.
void RewriteUse(Use &U)
Rewrite a use of the symbolic value.
void Initialize(Type *Ty, StringRef Name)
Reset this object to get ready for a new set of SSA updates with type 'Ty'.
void AddAvailableValue(BasicBlock *BB, Value *V)
Indicate that a rewritten value is available in the specified block with the specified value.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
bool contains(StringRef Key) const
contains - Return true if the element is in the map, false otherwise.
StringRef - Represent a constant reference to a string, i.e.
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getInt32Ty(LLVMContext &C)
LLVM Value Representation.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< use_iterator > uses()
StringRef getName() const
Return a constant reference to the value's name.
void takeName(Value *V)
Transfer the name from V to this value.
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
A raw_ostream that writes to an std::string.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ WASM_EmscriptenInvoke
For emscripten __invoke_* functions.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
@ C
The default llvm calling convention, compatible with C.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
cl::opt< bool > WasmEnableSjLj
cl::opt< bool > WasmEnableEmEH
cl::opt< bool > WasmEnableEmSjLj
This is an optimization pass for GlobalISel generic memory operations.
@ Low
Lower the current thread's priority such that it does not affect foreground tasks significantly.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
StringRef getEHPersonalityName(EHPersonality Pers)
BasicBlock * changeToInvokeAndSplitBasicBlock(CallInst *CI, BasicBlock *UnwindEdge, DomTreeUpdater *DTU=nullptr)
Convert the CallInst to InvokeInst with the specified unwind edge basic block.
CallInst * changeToCall(InvokeInst *II, DomTreeUpdater *DTU=nullptr)
This function converts the specified invoke into a normal call.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
OperandBundleDefT< Value * > OperandBundleDef
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
ModulePass * createWebAssemblyLowerEmscriptenEHSjLj()
@ Or
Bitwise or logical OR of integers.
BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="", bool Before=false)
Split the specified block at the specified instruction.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...