273#include "llvm/IR/IntrinsicsWebAssembly.h"
284#define DEBUG_TYPE "wasm-lower-em-ehsjlj"
288 cl::desc(
"The list of function names in which Emscripten-style "
289 "exception handling is enabled (see emscripten "
290 "EMSCRIPTEN_CATCHING_ALLOWED options)"),
294class WebAssemblyLowerEmscriptenEHSjLj final :
public ModulePass {
308 Function *WasmSetjmpTestF =
nullptr;
313 Type *LongjmpArgsTy =
nullptr;
321 std::set<std::string> EHAllowlistSet;
326 return "WebAssembly Lower Emscripten Exceptions";
332 void handleLongjmpableCallsForEmscriptenSjLj(
336 handleLongjmpableCallsForWasmSjLj(
Function &
F,
345 PHINode *&CallEmLongjmpBBThrewPHI,
346 PHINode *&CallEmLongjmpBBThrewValuePHI,
350 bool areAllExceptionsAllowed()
const {
return EHAllowlistSet.empty(); }
351 bool supportsException(
const Function *
F)
const {
352 return EnableEmEH && (areAllExceptionsAllowed() ||
353 EHAllowlistSet.count(std::string(
F->getName())));
362 WebAssemblyLowerEmscriptenEHSjLj()
366 assert(!(EnableEmSjLj && EnableWasmSjLj) &&
367 "Two SjLj modes cannot be turned on at the same time");
368 assert(!(EnableEmEH && EnableWasmSjLj) &&
369 "Wasm SjLj should be only used with Wasm EH");
380char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
382 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
386 return new WebAssemblyLowerEmscriptenEHSjLj();
390 if (
const auto *
F = dyn_cast<const Function>(V)) {
392 if (
F->isIntrinsic())
396 if (
Name ==
"setjmp" ||
Name ==
"longjmp" ||
Name ==
"emscripten_longjmp")
398 return !
F->doesNotThrow();
410 auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal(
Name, Ty));
430 OS << *FTy->getReturnType();
431 for (
Type *ParamTy : FTy->params())
432 OS <<
"_" << *ParamTy;
439 std::replace(Sig.begin(), Sig.end(),
',',
'.');
448 if (!
F->hasFnAttribute(
"wasm-import-module")) {
450 B.addAttribute(
"wasm-import-module",
"env");
453 if (!
F->hasFnAttribute(
"wasm-import-name")) {
455 B.addAttribute(
"wasm-import-name",
F->getName());
465 return IRB.
getIntNTy(M->getDataLayout().getPointerSizeInBits());
472 return PointerType::getUnqual(M->getContext());
480 return IRB.
getIntN(M->getDataLayout().getPointerSizeInBits(),
C);
489WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
490 unsigned NumClauses) {
491 if (FindMatchingCatches.
count(NumClauses))
492 return FindMatchingCatches[NumClauses];
493 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
495 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
497 FTy,
"__cxa_find_matching_catch_" +
Twine(NumClauses + 2), &M);
498 FindMatchingCatches[NumClauses] =
F;
509Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(
CallBase *CI) {
514 IRB.SetInsertPoint(CI);
526 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
539 for (
unsigned I = 0, E = CI->
arg_size();
I < E; ++
I)
543 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
546 auto [SizeArg, NEltArg] = *
Args;
549 NEltArg = *NEltArg + 1;
550 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
554 FnAttrs.removeAttribute(Attribute::NoReturn);
579 return InvokeWrappers[Sig];
582 ArgTys.
push_back(PointerType::getUnqual(CalleeFTy));
584 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
586 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
587 CalleeFTy->isVarArg());
589 InvokeWrappers[Sig] =
F;
594 if (
auto *CalleeF = dyn_cast<Function>(Callee))
595 if (CalleeF->isIntrinsic())
602 if (isa<InlineAsm>(Callee))
604 StringRef CalleeName = Callee->getName();
610 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
614 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
615 CalleeName ==
"__wasm_setjmp" || CalleeName ==
"__wasm_setjmp_test" ||
616 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
620 if (Callee->getName().starts_with(
"__cxa_find_matching_catch_"))
658 if (CalleeName ==
"__cxa_end_catch")
660 if (CalleeName ==
"__cxa_begin_catch" ||
661 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
662 CalleeName ==
"__clang_call_terminate")
667 if (CalleeName ==
"_ZSt9terminatev")
675 StringRef CalleeName = Callee->getName();
677 return CalleeName ==
"emscripten_asm_const_int" ||
678 CalleeName ==
"emscripten_asm_const_double" ||
679 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
680 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
681 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
700void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
703 PHINode *&CallEmLongjmpBBThrewPHI,
PHINode *&CallEmLongjmpBBThrewValuePHI,
709 IRB.SetCurrentDebugLocation(
DL);
712 IRB.SetInsertPoint(BB);
717 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
718 ThrewValueGV->
getName() +
".val");
719 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
720 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
721 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
724 if (!CallEmLongjmpBB) {
727 IRB.SetInsertPoint(CallEmLongjmpBB);
728 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
729 CallEmLongjmpBBThrewValuePHI =
730 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
731 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
732 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
733 IRB.CreateCall(EmLongjmpF,
734 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
735 IRB.CreateUnreachable();
737 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
738 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
743 IRB.SetInsertPoint(ThenBB1);
747 Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF,
748 {ThrewPtr, FunctionInvocationId},
"label");
749 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
750 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
753 IRB.SetInsertPoint(EndBB2);
754 IRB.CreateCall(SetTempRet0F, ThrewValue);
755 IRB.CreateBr(EndBB1);
757 IRB.SetInsertPoint(ElseBB1);
758 IRB.CreateBr(EndBB1);
761 IRB.SetInsertPoint(EndBB1);
762 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
770 LongjmpResult = IRB.CreateCall(GetTempRet0F, std::nullopt,
"longjmp_result");
773void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(
Function &
F) {
774 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
780 if (
I.getType()->isVoidTy())
782 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
785 if (
auto *
II = dyn_cast<InvokeInst>(&
I))
786 SSA.AddAvailableValue(VarID,
II->getNormalDest(),
II);
788 SSA.AddAvailableValue(VarID, &BB, &
I);
789 for (
auto &U :
I.uses()) {
790 auto *
User = cast<Instruction>(
U.getUser());
791 if (
auto *UserPN = dyn_cast<PHINode>(
User))
792 if (UserPN->getIncomingBlock(U) == &BB)
796 SSA.AddUse(VarID, &U);
800 SSA.RewriteAllUses(&DT);
811void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(
Function *LongjmpF,
813 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
822 auto *CI = dyn_cast<CallInst>(U);
824 IRB.SetInsertPoint(CI);
825 Value *Env =
nullptr;
826 if (NewF == EmLongjmpF)
830 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
835 for (
auto *
I : ToErase)
836 I->eraseFromParent();
840 if (!LongjmpF->
uses().empty()) {
842 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
848 for (
const auto &BB : *
F)
849 for (
const auto &
I : BB)
850 if (
const auto *CB = dyn_cast<CallBase>(&
I))
863 Function *SetjmpF = M.getFunction(
"setjmp");
867 auto *CB = cast<CallBase>(U);
873 if (
auto *
II = dyn_cast<InvokeInst>(CB))
876 CI = cast<CallInst>(CB);
880 for (
auto *
I : ToErase)
881 I->eraseFromParent();
884bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
885 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
890 Function *SetjmpF =
M.getFunction(
"setjmp");
891 Function *LongjmpF =
M.getFunction(
"longjmp");
896 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
897 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
912 "longjmp and _longjmp have different function types");
920 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
921 assert(TPC &&
"Expected a TargetPassConfig");
930 FunctionType::get(IRB.getInt32Ty(),
false),
"getTempRet0", &M);
932 FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
937 bool Changed =
false;
943 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
949 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
957 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
960 if (
auto *CB = dyn_cast<CallBase>(U)) {
961 auto *UserF = CB->getFunction();
966 SetjmpUsers.
insert(UserF);
968 SetjmpUsersToNullify.
insert(UserF);
979 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
980 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
981 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
985 assert(EnableEmSjLj || EnableWasmSjLj);
989 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
991 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
993 Type *Int8PtrTy = IRB.getPtrTy();
996 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
998 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1002 Type *Int8PtrTy = IRB.getPtrTy();
1003 Type *Int32PtrTy = IRB.getPtrTy();
1009 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1014 FTy = FunctionType::get(Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1030 if (
F.isDeclaration())
1032 Changed |= runEHOnFunction(
F);
1040 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1045 runSjLjOnFunction(*
F);
1049 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1052 for (
Function *
F : SetjmpUsersToNullify)
1057 for (
auto *V : {ThrewGV, ThrewValueGV})
1058 if (V &&
V->use_empty())
1059 V->eraseFromParent();
1060 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1061 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1062 if (V &&
V->use_empty())
1063 V->eraseFromParent();
1068bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(
Function &
F) {
1072 bool Changed =
false;
1080 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1083 auto *
II = dyn_cast<InvokeInst>(BB.getTerminator());
1087 LandingPads.
insert(
II->getLandingPadInst());
1088 IRB.SetInsertPoint(
II);
1091 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1094 Value *Threw = wrapInvoke(
II);
1117 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1120 if (!RethrowLongjmpBB) {
1122 IRB.SetInsertPoint(RethrowLongjmpBB);
1123 RethrowLongjmpBBThrewPHI =
1125 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1126 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1127 ThrewValueGV->
getName() +
".val");
1128 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1129 IRB.CreateUnreachable();
1131 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1134 IRB.SetInsertPoint(
II);
1140 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1141 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1142 IRB.SetInsertPoint(
Tail);
1143 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1148 IRB.CreateCondBr(Cmp,
II->getUnwindDest(),
II->getNormalDest());
1161 auto *RI = dyn_cast<ResumeInst>(&
I);
1167 Value *Input = RI->getValue();
1168 IRB.SetInsertPoint(RI);
1169 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1171 IRB.CreateCall(ResumeF, {
Low});
1173 IRB.CreateUnreachable();
1181 auto *CI = dyn_cast<CallInst>(&
I);
1187 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1191 IRB.SetInsertPoint(CI);
1202 if (
auto *LPI = dyn_cast<LandingPadInst>(
I))
1205 Changed |= !LandingPads.
empty();
1210 IRB.SetInsertPoint(LPI);
1212 for (
unsigned I = 0, E = LPI->getNumClauses();
I < E; ++
I) {
1216 if (LPI->isCatch(
I))
1221 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1222 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1224 Value *Pair0 = IRB.CreateInsertValue(
Poison, FMCI, 0,
"pair0");
1225 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, std::nullopt,
"tempret0");
1226 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1234 I->eraseFromParent();
1256 return DILocation::get(SP->
getContext(), SP->getLine(), 1, SP);
1260bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(
Function &
F) {
1261 assert(EnableEmSjLj || EnableWasmSjLj);
1273 IRB.SetInsertPoint(
Entry->getTerminator()->getIterator());
1278 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1283 Function *SetjmpF =
M.getFunction(
"setjmp");
1285 auto *CB = cast<CallBase>(U);
1292 SS <<
"In function " +
F.getName() +
1293 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1300 if (
auto *
II = dyn_cast<InvokeInst>(CB))
1303 CI = cast<CallInst>(CB);
1311 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1312 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1324 IRB.SetInsertPoint(CI);
1326 FunctionInvocationId};
1327 IRB.CreateCall(WasmSetjmpF, Args);
1333 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1336 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1340 I->eraseFromParent();
1359void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1371 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1374 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1381 std::vector<BasicBlock *> BBs;
1386 for (
unsigned I = 0;
I < BBs.size();
I++) {
1389 if (isa<InvokeInst>(&
I)) {
1392 SS <<
"In function " <<
F.getName()
1393 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1394 "restriction that `setjmp` function call and exception cannot be "
1395 "used within the same function:\n";
1399 auto *CI = dyn_cast<CallInst>(&
I);
1409 ". Please consider using EM_JS, or move the "
1410 "EM_ASM into another function.",
1413 Value *Threw =
nullptr;
1415 if (
Callee->getName().starts_with(
"__invoke_")) {
1424 if (
auto *LI = dyn_cast<LoadInst>(
I))
1425 if (
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1426 if (GV == ThrewGV) {
1427 Threw = ThrewLI = LI;
1435 if (
auto *SI = dyn_cast<StoreInst>(
I)) {
1436 if (
auto *GV = dyn_cast<GlobalVariable>(
SI->getPointerOperand())) {
1437 if (GV == ThrewGV &&
1445 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1446 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1451 Threw = wrapInvoke(CI);
1476 if (supportsException(&
F) &&
canThrow(Callee)) {
1482 if (!RethrowExnBB) {
1484 IRB.SetInsertPoint(RethrowExnBB);
1486 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1487 IRB.CreateCall(ResumeF, {Exn});
1488 IRB.CreateUnreachable();
1491 IRB.SetInsertPoint(CI);
1495 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1497 IRB.SetInsertPoint(NormalBB);
1512 Value *LongjmpResult =
nullptr;
1514 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1515 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1516 CallEmLongjmpBBThrewValuePHI, EndBB);
1517 assert(Label && LongjmpResult && EndBB);
1520 IRB.SetInsertPoint(EndBB);
1527 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1528 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1529 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1539 I->eraseFromParent();
1544 if (
const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1545 return CRI->getUnwindDest();
1554void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1565 if (!
F.hasPersonalityFn()) {
1568 FunctionType::get(IRB.getInt32Ty(),
true);
1569 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1571 cast<Constant>(IRB.CreateBitCast(PersF, IRB.getPtrTy())));
1577 IRB.SetCurrentDebugLocation(FirstDL);
1593 cast<BranchInst>(
Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
1598 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1604 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1605 IRB.SetInsertPoint(CatchLongjmpBB);
1606 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1615 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1617 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1619 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1621 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1630 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1632 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1633 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1635 IRB.SetInsertPoint(ThenBB);
1636 CallInst *WasmLongjmpCI = IRB.CreateCall(
1638 IRB.CreateUnreachable();
1640 IRB.SetInsertPoint(EndBB);
1642 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1652 IRB.SetInsertPoint(SetjmpDispatchBB);
1653 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1656 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1661 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1662 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1663 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1669 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1670 for (
auto &
I : *BB) {
1671 auto *CI = dyn_cast<CallInst>(&
I);
1680 ". Please consider using EM_JS, or move the "
1681 "EM_ASM into another function.",
1686 if (CI == WasmLongjmpCI)
1693 UnwindDestToNewPreds;
1694 for (
auto *CI : LongjmpableCalls) {
1700 CalleeF->removeFnAttr(Attribute::NoUnwind);
1709 Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
1710 while (!UnwindDest) {
1711 if (
auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
1712 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1715 if (
auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
1722 Value *ParentPad = CPI->getParentPad();
1723 if (isa<ConstantTokenNone>(ParentPad))
1725 FromPad = cast<Instruction>(ParentPad);
1730 UnwindDest = CatchDispatchLongjmpBB;
1740 for (
auto &BB :
F) {
1741 if (
auto *CSI = dyn_cast<CatchSwitchInst>(BB.getFirstNonPHI())) {
1742 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1743 IRB.SetInsertPoint(CSI);
1745 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1746 CatchDispatchLongjmpBB, 1);
1747 NewCSI->addHandler(*CSI->handler_begin());
1748 NewCSI->takeName(CSI);
1749 CSI->replaceAllUsesWith(NewCSI);
1753 if (
auto *CRI = dyn_cast<CleanupReturnInst>(BB.getTerminator())) {
1754 if (CRI->unwindsToCaller()) {
1755 IRB.SetInsertPoint(CRI);
1757 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1763 I->eraseFromParent();
1771 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1773 for (
auto *NewPred : NewPreds) {
1774 assert(PN.getBasicBlockIndex(NewPred) == -1);
1785 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1788 SSA.Initialize(PN.getType(), PN.getName());
1789 for (
unsigned Idx = 0, E = PN.getNumIncomingValues();
Idx != E; ++
Idx) {
1790 if (NewPreds.contains(PN.getIncomingBlock(
Idx)))
1793 if (
auto *
II = dyn_cast<InvokeInst>(V))
1794 SSA.AddAvailableValue(
II->getNormalDest(),
II);
1795 else if (
auto *
I = dyn_cast<Instruction>(V))
1796 SSA.AddAvailableValue(
I->getParent(),
I);
1798 SSA.AddAvailableValue(PN.getIncomingBlock(
Idx), V);
1800 for (
auto *NewPred : NewPreds)
1801 PN.setIncomingValueForBlock(NewPred,
SSA.GetValueAtEndOfBlock(NewPred));
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
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.
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
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 & back() const
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...
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 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.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
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.
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)
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
LLVM Value Representation.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
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.
const ParentTy * getParent() const
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.
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...