279#include "llvm/IR/IntrinsicsWebAssembly.h"
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)"),
298class 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");
385char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
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));
435 OS << *FTy->getReturnType();
436 for (
Type *ParamTy : FTy->params())
437 OS <<
"_" << *ParamTy;
444 std::replace(Sig.begin(), Sig.end(),
',',
'.');
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);
494WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
495 unsigned NumClauses) {
496 if (FindMatchingCatches.
count(NumClauses))
497 return FindMatchingCatches[NumClauses];
500 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
502 FTy,
"__cxa_find_matching_catch_" +
Twine(NumClauses + 2), &M);
503 FindMatchingCatches[NumClauses] =
F;
514Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(
CallBase *CI) {
519 IRB.SetInsertPoint(CI);
531 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
548 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
551 auto [SizeArg, NEltArg] = *
Args;
554 NEltArg = *NEltArg + 1;
555 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
559 FnAttrs.removeAttribute(Attribute::NoReturn);
584 return InvokeWrappers[Sig];
587 ArgTys.
push_back(PointerType::getUnqual(CalleeFTy));
589 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
591 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
592 CalleeFTy->isVarArg());
594 InvokeWrappers[Sig] =
F;
599 if (
auto *CalleeF = dyn_cast<Function>(
Callee))
600 if (CalleeF->isIntrinsic())
607 if (isa<InlineAsm>(
Callee))
615 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
619 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
620 CalleeName ==
"saveSetjmp" || CalleeName ==
"testSetjmp" ||
621 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
625 if (
Callee->getName().startswith(
"__cxa_find_matching_catch_"))
663 if (CalleeName ==
"__cxa_end_catch")
665 if (CalleeName ==
"__cxa_begin_catch" ||
666 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
667 CalleeName ==
"__clang_call_terminate")
672 if (CalleeName ==
"_ZSt9terminatev")
682 return CalleeName ==
"emscripten_asm_const_int" ||
683 CalleeName ==
"emscripten_asm_const_double" ||
684 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
685 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
686 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
704void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
713 IRB.SetCurrentDebugLocation(
DL);
716 IRB.SetInsertPoint(BB);
721 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
722 ThrewValueGV->
getName() +
".val");
723 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
724 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
725 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
728 if (!CallEmLongjmpBB) {
731 IRB.SetInsertPoint(CallEmLongjmpBB);
732 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
733 CallEmLongjmpBBThrewValuePHI =
734 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
735 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
736 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
737 IRB.CreateCall(EmLongjmpF,
738 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
739 IRB.CreateUnreachable();
741 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
742 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
747 IRB.SetInsertPoint(ThenBB1);
752 ThrewPtr->
getName() +
".loaded");
753 Value *ThenLabel = IRB.CreateCall(
754 TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize},
"label");
755 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
756 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
759 IRB.SetInsertPoint(EndBB2);
760 IRB.CreateCall(SetTempRet0F, ThrewValue);
761 IRB.CreateBr(EndBB1);
763 IRB.SetInsertPoint(ElseBB1);
764 IRB.CreateBr(EndBB1);
767 IRB.SetInsertPoint(EndBB1);
768 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
776 LongjmpResult = IRB.CreateCall(GetTempRet0F, std::nullopt,
"longjmp_result");
779void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(
Function &
F) {
780 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
786 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
789 if (
auto *II = dyn_cast<InvokeInst>(&
I))
790 SSA.AddAvailableValue(VarID, II->getNormalDest(), II);
792 SSA.AddAvailableValue(VarID, &BB, &
I);
793 for (
auto &U :
I.uses()) {
794 auto *
User = cast<Instruction>(
U.getUser());
795 if (
auto *UserPN = dyn_cast<PHINode>(
User))
796 if (UserPN->getIncomingBlock(U) == &BB)
800 SSA.AddUse(VarID, &U);
804 SSA.RewriteAllUses(&DT);
815void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(
Function *LongjmpF,
817 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
826 auto *CI = dyn_cast<CallInst>(U);
828 IRB.SetInsertPoint(CI);
829 Value *Env =
nullptr;
830 if (NewF == EmLongjmpF)
835 IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getInt8PtrTy(),
"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.getInt8PtrTy(),
false);
954 FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(),
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);
1000 IRB.getVoidTy(), {IRB.getInt8PtrTy(), IRB.getInt32Ty()},
false);
1002 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1010 {SetjmpFTy->getParamType(0), IRB.getInt32Ty(),
1016 FTy = FunctionType::get(
1018 {getAddrIntType(&M), Type::getInt32PtrTy(C), IRB.getInt32Ty()},
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);
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());
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);
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");
1352 IRB.SetInsertPoint(CI);
1354 SetjmpTable, SetjmpTableSize};
1356 IRB.CreateCall(SaveSetjmpF, Args,
"setjmpTable");
1358 IRB.CreateCall(GetTempRet0F, std::nullopt,
"setjmpTableSize");
1359 SetjmpTableInsts.
push_back(NewSetjmpTable);
1360 SetjmpTableSizeInsts.
push_back(NewSetjmpTableSize);
1366 handleLongjmpableCallsForEmscriptenSjLj(
1367 F, SetjmpTableInsts, SetjmpTableSizeInsts, SetjmpRetPHIs);
1369 handleLongjmpableCallsForWasmSjLj(
F, SetjmpTableInsts, SetjmpTableSizeInsts,
1374 I->eraseFromParent();
1381 if (isa<ReturnInst>(TI))
1387 for (
auto &
I : BB) {
1388 if (
auto *CI = dyn_cast<CallInst>(&
I)) {
1391 IsNoReturn |= CalleeF->hasFnAttribute(Attribute::NoReturn);
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)
1462void 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);
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);
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);
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);
1651 I->eraseFromParent();
1656 if (
const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1657 return CRI->getUnwindDest();
1666void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1667 Function &
F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
1677 if (!
F.hasPersonalityFn()) {
1680 FunctionType::get(IRB.getInt32Ty(),
true);
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)
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);
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);
1871 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1877 I->eraseFromParent();
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
amdgpu Simplify well known AMD library false FunctionCallee Callee
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.
static Instruction * CreateFree(Value *Source, Instruction *InsertBefore)
Generate the IR for a call to the builtin free function.
static Instruction * CreateMalloc(Instruction *InsertBefore, Type *IntPtrTy, Type *AllocTy, Value *AllocSize, Value *ArraySize=nullptr, Function *MallocF=nullptr, const Twine &Name="")
Generate the IR for a call to malloc:
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 PointerType * getInt32PtrTy(LLVMContext &C, unsigned AS=0)
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
static PointerType * getIntNPtrTy(LLVMContext &C, unsigned N, unsigned AS=0)
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
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.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
BasicBlock * SplitBlock(BasicBlock *Old, Instruction *SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="", bool Before=false)
Split the specified block at the specified instruction.