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, std::less<>> 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 {
353 (areAllExceptionsAllowed() || EHAllowlistSet.count(
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);
578 auto It = InvokeWrappers.
find(Sig);
579 if (It != InvokeWrappers.
end())
583 ArgTys.
push_back(PointerType::getUnqual(CalleeFTy));
585 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
587 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
588 CalleeFTy->isVarArg());
590 InvokeWrappers[Sig] =
F;
595 if (
auto *CalleeF = dyn_cast<Function>(Callee))
596 if (CalleeF->isIntrinsic())
603 if (isa<InlineAsm>(Callee))
605 StringRef CalleeName = Callee->getName();
611 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
615 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
616 CalleeName ==
"__wasm_setjmp" || CalleeName ==
"__wasm_setjmp_test" ||
617 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
621 if (Callee->getName().starts_with(
"__cxa_find_matching_catch_"))
659 if (CalleeName ==
"__cxa_end_catch")
661 if (CalleeName ==
"__cxa_begin_catch" ||
662 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
663 CalleeName ==
"__clang_call_terminate")
668 if (CalleeName ==
"_ZSt9terminatev")
676 StringRef CalleeName = Callee->getName();
678 return CalleeName ==
"emscripten_asm_const_int" ||
679 CalleeName ==
"emscripten_asm_const_double" ||
680 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
681 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
682 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
701void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
704 PHINode *&CallEmLongjmpBBThrewPHI,
PHINode *&CallEmLongjmpBBThrewValuePHI,
710 IRB.SetCurrentDebugLocation(
DL);
713 IRB.SetInsertPoint(BB);
718 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
719 ThrewValueGV->
getName() +
".val");
720 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
721 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
722 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
725 if (!CallEmLongjmpBB) {
728 IRB.SetInsertPoint(CallEmLongjmpBB);
729 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
730 CallEmLongjmpBBThrewValuePHI =
731 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
732 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
733 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
734 IRB.CreateCall(EmLongjmpF,
735 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
736 IRB.CreateUnreachable();
738 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
739 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
744 IRB.SetInsertPoint(ThenBB1);
748 Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF,
749 {ThrewPtr, FunctionInvocationId},
"label");
750 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
751 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
754 IRB.SetInsertPoint(EndBB2);
755 IRB.CreateCall(SetTempRet0F, ThrewValue);
756 IRB.CreateBr(EndBB1);
758 IRB.SetInsertPoint(ElseBB1);
759 IRB.CreateBr(EndBB1);
762 IRB.SetInsertPoint(EndBB1);
763 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
771 LongjmpResult = IRB.CreateCall(GetTempRet0F, {},
"longjmp_result");
774void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(
Function &
F) {
775 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
781 if (
I.getType()->isVoidTy())
783 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
786 if (
auto *
II = dyn_cast<InvokeInst>(&
I))
790 for (
auto &U :
I.uses()) {
791 auto *
User = cast<Instruction>(
U.getUser());
792 if (
auto *UserPN = dyn_cast<PHINode>(
User))
793 if (UserPN->getIncomingBlock(U) == &BB)
801 SSA.RewriteAllUses(&DT);
812void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(
Function *LongjmpF,
814 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
823 auto *CI = dyn_cast<CallInst>(U);
825 IRB.SetInsertPoint(CI);
826 Value *Env =
nullptr;
827 if (NewF == EmLongjmpF)
831 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
836 for (
auto *
I : ToErase)
837 I->eraseFromParent();
841 if (!LongjmpF->
uses().empty()) {
843 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
849 for (
const auto &BB : *
F)
850 for (
const auto &
I : BB)
851 if (
const auto *CB = dyn_cast<CallBase>(&
I))
864 Function *SetjmpF = M.getFunction(
"setjmp");
868 auto *CB = cast<CallBase>(U);
874 if (
auto *
II = dyn_cast<InvokeInst>(CB))
877 CI = cast<CallInst>(CB);
881 for (
auto *
I : ToErase)
882 I->eraseFromParent();
885bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
886 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
891 Function *SetjmpF =
M.getFunction(
"setjmp");
892 Function *LongjmpF =
M.getFunction(
"longjmp");
897 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
898 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
913 "longjmp and _longjmp have different function types");
921 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
922 assert(TPC &&
"Expected a TargetPassConfig");
931 FunctionType::get(IRB.getInt32Ty(),
false),
"getTempRet0", &M);
933 FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
938 bool Changed =
false;
944 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
950 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
958 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
961 if (
auto *CB = dyn_cast<CallBase>(U)) {
962 auto *UserF = CB->getFunction();
967 SetjmpUsers.
insert(UserF);
969 SetjmpUsersToNullify.
insert(UserF);
980 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
981 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
982 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
986 assert(EnableEmSjLj || EnableWasmSjLj);
990 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
992 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
994 Type *Int8PtrTy = IRB.getPtrTy();
997 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
999 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1003 Type *Int8PtrTy = IRB.getPtrTy();
1004 Type *Int32PtrTy = IRB.getPtrTy();
1010 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1015 FTy = FunctionType::get(Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1031 if (
F.isDeclaration())
1033 Changed |= runEHOnFunction(
F);
1041 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1046 runSjLjOnFunction(*
F);
1050 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1053 for (
Function *
F : SetjmpUsersToNullify)
1058 for (
auto *V : {ThrewGV, ThrewValueGV})
1059 if (V &&
V->use_empty())
1060 V->eraseFromParent();
1061 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1062 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1063 if (V &&
V->use_empty())
1064 V->eraseFromParent();
1069bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(
Function &
F) {
1073 bool Changed =
false;
1081 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1084 auto *
II = dyn_cast<InvokeInst>(BB.getTerminator());
1088 LandingPads.
insert(
II->getLandingPadInst());
1089 IRB.SetInsertPoint(
II);
1092 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1095 Value *Threw = wrapInvoke(
II);
1118 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1121 if (!RethrowLongjmpBB) {
1123 IRB.SetInsertPoint(RethrowLongjmpBB);
1124 RethrowLongjmpBBThrewPHI =
1126 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1127 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1128 ThrewValueGV->
getName() +
".val");
1129 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1130 IRB.CreateUnreachable();
1132 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1135 IRB.SetInsertPoint(
II);
1141 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1142 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1143 IRB.SetInsertPoint(
Tail);
1144 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1149 IRB.CreateCondBr(Cmp,
II->getUnwindDest(),
II->getNormalDest());
1162 auto *RI = dyn_cast<ResumeInst>(&
I);
1168 Value *Input = RI->getValue();
1169 IRB.SetInsertPoint(RI);
1170 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1172 IRB.CreateCall(ResumeF, {
Low});
1174 IRB.CreateUnreachable();
1182 auto *CI = dyn_cast<CallInst>(&
I);
1188 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1192 IRB.SetInsertPoint(CI);
1203 if (
auto *LPI = dyn_cast<LandingPadInst>(
I))
1206 Changed |= !LandingPads.
empty();
1211 IRB.SetInsertPoint(LPI);
1213 for (
unsigned I = 0, E = LPI->getNumClauses();
I < E; ++
I) {
1217 if (LPI->isCatch(
I))
1222 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1223 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1225 Value *Pair0 = IRB.CreateInsertValue(
Poison, FMCI, 0,
"pair0");
1226 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, {},
"tempret0");
1227 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1235 I->eraseFromParent();
1257 return DILocation::get(SP->
getContext(), SP->getLine(), 1, SP);
1261bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(
Function &
F) {
1262 assert(EnableEmSjLj || EnableWasmSjLj);
1274 IRB.SetInsertPoint(
Entry->getTerminator()->getIterator());
1279 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1284 Function *SetjmpF =
M.getFunction(
"setjmp");
1286 auto *CB = cast<CallBase>(U);
1293 SS <<
"In function " +
F.getName() +
1294 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1301 if (
auto *
II = dyn_cast<InvokeInst>(CB))
1304 CI = cast<CallInst>(CB);
1312 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1313 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1325 IRB.SetInsertPoint(CI);
1327 FunctionInvocationId};
1328 IRB.CreateCall(WasmSetjmpF, Args);
1334 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1337 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1341 I->eraseFromParent();
1360void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1372 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1375 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1382 std::vector<BasicBlock *> BBs;
1387 for (
unsigned I = 0;
I < BBs.size();
I++) {
1390 if (isa<InvokeInst>(&
I)) {
1393 SS <<
"In function " <<
F.getName()
1394 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1395 "restriction that `setjmp` function call and exception cannot be "
1396 "used within the same function:\n";
1400 auto *CI = dyn_cast<CallInst>(&
I);
1410 ". Please consider using EM_JS, or move the "
1411 "EM_ASM into another function.",
1414 Value *Threw =
nullptr;
1416 if (
Callee->getName().starts_with(
"__invoke_")) {
1425 if (
auto *LI = dyn_cast<LoadInst>(
I))
1426 if (
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1427 if (GV == ThrewGV) {
1428 Threw = ThrewLI = LI;
1436 if (
auto *SI = dyn_cast<StoreInst>(
I)) {
1437 if (
auto *GV = dyn_cast<GlobalVariable>(
SI->getPointerOperand())) {
1438 if (GV == ThrewGV &&
1446 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1447 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1452 Threw = wrapInvoke(CI);
1477 if (supportsException(&
F) &&
canThrow(Callee)) {
1483 if (!RethrowExnBB) {
1485 IRB.SetInsertPoint(RethrowExnBB);
1487 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1488 IRB.CreateCall(ResumeF, {Exn});
1489 IRB.CreateUnreachable();
1492 IRB.SetInsertPoint(CI);
1496 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1498 IRB.SetInsertPoint(NormalBB);
1513 Value *LongjmpResult =
nullptr;
1515 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1516 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1517 CallEmLongjmpBBThrewValuePHI, EndBB);
1518 assert(Label && LongjmpResult && EndBB);
1521 IRB.SetInsertPoint(EndBB);
1528 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1529 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1530 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1540 I->eraseFromParent();
1545 if (
const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1546 return CRI->getUnwindDest();
1555void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1566 if (!
F.hasPersonalityFn()) {
1569 FunctionType::get(IRB.getInt32Ty(),
true);
1570 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1572 cast<Constant>(IRB.CreateBitCast(PersF, IRB.getPtrTy())));
1578 IRB.SetCurrentDebugLocation(FirstDL);
1594 cast<BranchInst>(
Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
1599 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1605 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1606 IRB.SetInsertPoint(CatchLongjmpBB);
1607 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1616 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1618 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1620 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1622 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1631 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1633 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1634 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1636 IRB.SetInsertPoint(ThenBB);
1637 CallInst *WasmLongjmpCI = IRB.CreateCall(
1639 IRB.CreateUnreachable();
1641 IRB.SetInsertPoint(EndBB);
1643 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1653 IRB.SetInsertPoint(SetjmpDispatchBB);
1654 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1657 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1662 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1663 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1664 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1670 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1671 for (
auto &
I : *BB) {
1672 auto *CI = dyn_cast<CallInst>(&
I);
1681 ". Please consider using EM_JS, or move the "
1682 "EM_ASM into another function.",
1687 if (CI == WasmLongjmpCI)
1694 UnwindDestToNewPreds;
1695 for (
auto *CI : LongjmpableCalls) {
1701 CalleeF->removeFnAttr(Attribute::NoUnwind);
1710 Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
1711 while (!UnwindDest) {
1712 if (
auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
1713 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1716 if (
auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
1723 Value *ParentPad = CPI->getParentPad();
1724 if (isa<ConstantTokenNone>(ParentPad))
1726 FromPad = cast<Instruction>(ParentPad);
1731 UnwindDest = CatchDispatchLongjmpBB;
1741 for (
auto &BB :
F) {
1742 if (
auto *CSI = dyn_cast<CatchSwitchInst>(BB.getFirstNonPHI())) {
1743 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1744 IRB.SetInsertPoint(CSI);
1746 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1747 CatchDispatchLongjmpBB, 1);
1748 NewCSI->addHandler(*CSI->handler_begin());
1749 NewCSI->takeName(CSI);
1750 CSI->replaceAllUsesWith(NewCSI);
1754 if (
auto *CRI = dyn_cast<CleanupReturnInst>(BB.getTerminator())) {
1755 if (CRI->unwindsToCaller()) {
1756 IRB.SetInsertPoint(CRI);
1758 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1764 I->eraseFromParent();
1772 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1774 for (
auto *NewPred : NewPreds) {
1775 assert(PN.getBasicBlockIndex(NewPred) == -1);
1786 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1789 SSA.Initialize(PN.getType(), PN.getName());
1790 for (
unsigned Idx = 0, E = PN.getNumIncomingValues();
Idx != E; ++
Idx) {
1791 if (NewPreds.contains(PN.getIncomingBlock(
Idx)))
1794 if (
auto *
II = dyn_cast<InvokeInst>(V))
1795 SSA.AddAvailableValue(
II->getNormalDest(),
II);
1796 else if (
auto *
I = dyn_cast<Instruction>(V))
1797 SSA.AddAvailableValue(
I->getParent(),
I);
1799 SSA.AddAvailableValue(PN.getIncomingBlock(
Idx), V);
1801 for (
auto *NewPred : NewPreds)
1802 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
#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 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 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",...
iterator find(StringRef Key)
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.
@ 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 * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
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.
std::tuple< const DIScope *, const DIScope *, const DILocalVariable * > VarID
A unique key that represents a debug variable.
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...