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 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
783 if (
auto *
II = dyn_cast<InvokeInst>(&
I))
784 SSA.AddAvailableValue(VarID,
II->getNormalDest(),
II);
786 SSA.AddAvailableValue(VarID, &BB, &
I);
787 for (
auto &U :
I.uses()) {
788 auto *
User = cast<Instruction>(
U.getUser());
789 if (
auto *UserPN = dyn_cast<PHINode>(
User))
790 if (UserPN->getIncomingBlock(U) == &BB)
794 SSA.AddUse(VarID, &U);
798 SSA.RewriteAllUses(&DT);
809void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(
Function *LongjmpF,
811 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
820 auto *CI = dyn_cast<CallInst>(U);
822 IRB.SetInsertPoint(CI);
823 Value *Env =
nullptr;
824 if (NewF == EmLongjmpF)
828 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
833 for (
auto *
I : ToErase)
834 I->eraseFromParent();
838 if (!LongjmpF->
uses().empty()) {
840 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
846 for (
const auto &BB : *
F)
847 for (
const auto &
I : BB)
848 if (
const auto *CB = dyn_cast<CallBase>(&
I))
861 Function *SetjmpF = M.getFunction(
"setjmp");
865 auto *CB = cast<CallBase>(U);
871 if (
auto *
II = dyn_cast<InvokeInst>(CB))
874 CI = cast<CallInst>(CB);
878 for (
auto *
I : ToErase)
879 I->eraseFromParent();
882bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
883 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
888 Function *SetjmpF =
M.getFunction(
"setjmp");
889 Function *LongjmpF =
M.getFunction(
"longjmp");
894 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
895 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
910 "longjmp and _longjmp have different function types");
918 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
919 assert(TPC &&
"Expected a TargetPassConfig");
928 FunctionType::get(IRB.getInt32Ty(),
false),
"getTempRet0", &M);
930 FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
935 bool Changed =
false;
941 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
947 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
955 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
958 if (
auto *CB = dyn_cast<CallBase>(U)) {
959 auto *UserF = CB->getFunction();
964 SetjmpUsers.
insert(UserF);
966 SetjmpUsersToNullify.
insert(UserF);
977 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
978 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
979 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
983 assert(EnableEmSjLj || EnableWasmSjLj);
987 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
989 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
991 Type *Int8PtrTy = IRB.getPtrTy();
994 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
996 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1000 Type *Int8PtrTy = IRB.getPtrTy();
1001 Type *Int32PtrTy = IRB.getPtrTy();
1007 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1012 FTy = FunctionType::get(Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1028 if (
F.isDeclaration())
1030 Changed |= runEHOnFunction(
F);
1038 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1043 runSjLjOnFunction(*
F);
1047 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1050 for (
Function *
F : SetjmpUsersToNullify)
1055 for (
auto *V : {ThrewGV, ThrewValueGV})
1056 if (V &&
V->use_empty())
1057 V->eraseFromParent();
1058 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1059 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1060 if (V &&
V->use_empty())
1061 V->eraseFromParent();
1066bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(
Function &
F) {
1070 bool Changed =
false;
1078 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1081 auto *
II = dyn_cast<InvokeInst>(BB.getTerminator());
1085 LandingPads.
insert(
II->getLandingPadInst());
1086 IRB.SetInsertPoint(
II);
1089 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1092 Value *Threw = wrapInvoke(
II);
1115 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1118 if (!RethrowLongjmpBB) {
1120 IRB.SetInsertPoint(RethrowLongjmpBB);
1121 RethrowLongjmpBBThrewPHI =
1123 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1124 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1125 ThrewValueGV->
getName() +
".val");
1126 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1127 IRB.CreateUnreachable();
1129 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1132 IRB.SetInsertPoint(
II);
1138 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1139 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1140 IRB.SetInsertPoint(
Tail);
1141 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1146 IRB.CreateCondBr(Cmp,
II->getUnwindDest(),
II->getNormalDest());
1159 auto *RI = dyn_cast<ResumeInst>(&
I);
1165 Value *Input = RI->getValue();
1166 IRB.SetInsertPoint(RI);
1167 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1169 IRB.CreateCall(ResumeF, {
Low});
1171 IRB.CreateUnreachable();
1179 auto *CI = dyn_cast<CallInst>(&
I);
1185 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1189 IRB.SetInsertPoint(CI);
1200 if (
auto *LPI = dyn_cast<LandingPadInst>(
I))
1203 Changed |= !LandingPads.
empty();
1208 IRB.SetInsertPoint(LPI);
1210 for (
unsigned I = 0, E = LPI->getNumClauses();
I < E; ++
I) {
1214 if (LPI->isCatch(
I))
1219 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1220 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1222 Value *Pair0 = IRB.CreateInsertValue(Poison, FMCI, 0,
"pair0");
1223 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, std::nullopt,
"tempret0");
1224 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1232 I->eraseFromParent();
1254 return DILocation::get(SP->
getContext(), SP->getLine(), 1, SP);
1258bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(
Function &
F) {
1259 assert(EnableEmSjLj || EnableWasmSjLj);
1271 IRB.SetInsertPoint(
Entry->getTerminator()->getIterator());
1276 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1281 Function *SetjmpF =
M.getFunction(
"setjmp");
1283 auto *CB = cast<CallBase>(U);
1290 SS <<
"In function " +
F.getName() +
1291 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1298 if (
auto *
II = dyn_cast<InvokeInst>(CB))
1301 CI = cast<CallInst>(CB);
1309 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1310 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1322 IRB.SetInsertPoint(CI);
1324 FunctionInvocationId};
1325 IRB.CreateCall(WasmSetjmpF, Args);
1331 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1334 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1338 I->eraseFromParent();
1357void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1369 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1372 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1379 std::vector<BasicBlock *> BBs;
1384 for (
unsigned I = 0;
I < BBs.size();
I++) {
1387 if (isa<InvokeInst>(&
I)) {
1390 SS <<
"In function " <<
F.getName()
1391 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1392 "restriction that `setjmp` function call and exception cannot be "
1393 "used within the same function:\n";
1397 auto *CI = dyn_cast<CallInst>(&
I);
1407 ". Please consider using EM_JS, or move the "
1408 "EM_ASM into another function.",
1411 Value *Threw =
nullptr;
1413 if (
Callee->getName().starts_with(
"__invoke_")) {
1422 if (
auto *LI = dyn_cast<LoadInst>(
I))
1423 if (
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1424 if (GV == ThrewGV) {
1425 Threw = ThrewLI = LI;
1433 if (
auto *SI = dyn_cast<StoreInst>(
I)) {
1434 if (
auto *GV = dyn_cast<GlobalVariable>(
SI->getPointerOperand())) {
1435 if (GV == ThrewGV &&
1443 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1444 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1449 Threw = wrapInvoke(CI);
1474 if (supportsException(&
F) &&
canThrow(Callee)) {
1480 if (!RethrowExnBB) {
1482 IRB.SetInsertPoint(RethrowExnBB);
1484 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1485 IRB.CreateCall(ResumeF, {Exn});
1486 IRB.CreateUnreachable();
1489 IRB.SetInsertPoint(CI);
1493 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1495 IRB.SetInsertPoint(NormalBB);
1510 Value *LongjmpResult =
nullptr;
1512 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1513 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1514 CallEmLongjmpBBThrewValuePHI, EndBB);
1515 assert(Label && LongjmpResult && EndBB);
1518 IRB.SetInsertPoint(EndBB);
1525 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1526 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1527 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1537 I->eraseFromParent();
1542 if (
const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1543 return CRI->getUnwindDest();
1552void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1563 if (!
F.hasPersonalityFn()) {
1566 FunctionType::get(IRB.getInt32Ty(),
true);
1567 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1569 cast<Constant>(IRB.CreateBitCast(PersF, IRB.getPtrTy())));
1575 IRB.SetCurrentDebugLocation(FirstDL);
1591 cast<BranchInst>(
Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
1596 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1602 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1603 IRB.SetInsertPoint(CatchLongjmpBB);
1604 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1613 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1615 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1617 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1619 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1628 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1630 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1631 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1633 IRB.SetInsertPoint(ThenBB);
1634 CallInst *WasmLongjmpCI = IRB.CreateCall(
1636 IRB.CreateUnreachable();
1638 IRB.SetInsertPoint(EndBB);
1640 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1650 IRB.SetInsertPoint(SetjmpDispatchBB);
1651 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1654 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1659 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1660 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1661 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1667 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1668 for (
auto &
I : *BB) {
1669 auto *CI = dyn_cast<CallInst>(&
I);
1678 ". Please consider using EM_JS, or move the "
1679 "EM_ASM into another function.",
1684 if (CI == WasmLongjmpCI)
1690 for (
auto *CI : LongjmpableCalls) {
1696 CalleeF->removeFnAttr(Attribute::NoUnwind);
1705 Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
1706 while (!UnwindDest) {
1707 if (
auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
1708 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1711 if (
auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
1718 Value *ParentPad = CPI->getParentPad();
1719 if (isa<ConstantTokenNone>(ParentPad))
1721 FromPad = cast<Instruction>(ParentPad);
1726 UnwindDest = CatchDispatchLongjmpBB;
1731 for (
auto &BB :
F) {
1732 if (
auto *CSI = dyn_cast<CatchSwitchInst>(BB.getFirstNonPHI())) {
1733 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1734 IRB.SetInsertPoint(CSI);
1736 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1737 CatchDispatchLongjmpBB, 1);
1738 NewCSI->addHandler(*CSI->handler_begin());
1739 NewCSI->takeName(CSI);
1740 CSI->replaceAllUsesWith(NewCSI);
1744 if (
auto *CRI = dyn_cast<CleanupReturnInst>(BB.getTerminator())) {
1745 if (CRI->unwindsToCaller()) {
1746 IRB.SetInsertPoint(CRI);
1748 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1754 I->eraseFromParent();
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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.
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.
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.
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()
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.
@ 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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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...