272#include "llvm/IR/IntrinsicsWebAssembly.h"
283#define DEBUG_TYPE "wasm-lower-em-ehsjlj"
287 cl::desc(
"The list of function names in which Emscripten-style "
288 "exception handling is enabled (see emscripten "
289 "EMSCRIPTEN_CATCHING_ALLOWED options)"),
293class WebAssemblyLowerEmscriptenEHSjLj final :
public ModulePass {
307 Function *WasmSetjmpTestF =
nullptr;
312 Type *LongjmpArgsTy =
nullptr;
320 std::set<std::string, std::less<>> EHAllowlistSet;
325 return "WebAssembly Lower Emscripten Exceptions";
331 void handleLongjmpableCallsForEmscriptenSjLj(
335 handleLongjmpableCallsForWasmSjLj(
Function &
F,
344 PHINode *&CallEmLongjmpBBThrewPHI,
345 PHINode *&CallEmLongjmpBBThrewValuePHI,
349 bool areAllExceptionsAllowed()
const {
return EHAllowlistSet.empty(); }
350 bool supportsException(
const Function *
F)
const {
352 (areAllExceptionsAllowed() || EHAllowlistSet.count(
F->getName()));
361 WebAssemblyLowerEmscriptenEHSjLj()
365 assert(!(EnableEmSjLj && EnableWasmSjLj) &&
366 "Two SjLj modes cannot be turned on at the same time");
367 assert(!(EnableEmEH && EnableWasmSjLj) &&
368 "Wasm SjLj should be only used with Wasm EH");
379char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
381 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
385 return new WebAssemblyLowerEmscriptenEHSjLj();
389 if (
const auto *
F = dyn_cast<const Function>(V)) {
391 if (
F->isIntrinsic())
395 if (
Name ==
"setjmp" ||
Name ==
"longjmp" ||
Name ==
"emscripten_longjmp")
397 return !
F->doesNotThrow();
409 auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal(
Name, Ty));
429 OS << *FTy->getReturnType();
430 for (
Type *ParamTy : FTy->params())
431 OS <<
"_" << *ParamTy;
451 if (!
F->hasFnAttribute(
"wasm-import-module")) {
453 B.addAttribute(
"wasm-import-module",
"env");
456 if (!
F->hasFnAttribute(
"wasm-import-name")) {
458 B.addAttribute(
"wasm-import-name",
F->getName());
467 return IRB.
getIntNTy(M->getDataLayout().getPointerSizeInBits());
474 return PointerType::getUnqual(M->getContext());
482 return IRB.
getIntN(M->getDataLayout().getPointerSizeInBits(),
C);
491WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
492 unsigned NumClauses) {
496 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
498 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
500 FTy,
"__cxa_find_matching_catch_" +
Twine(NumClauses + 2), &M);
513Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(
CallBase *CI) {
518 IRB.SetInsertPoint(CI);
530 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
543 for (
unsigned I = 0, E = CI->
arg_size();
I < E; ++
I)
547 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
550 auto [SizeArg, NEltArg] = *
Args;
553 NEltArg = *NEltArg + 1;
554 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
558 FnAttrs.removeAttribute(Attribute::NoReturn);
582 auto It = InvokeWrappers.
find(Sig);
583 if (It != InvokeWrappers.
end())
589 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
591 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
592 CalleeFTy->isVarArg());
595 InvokeWrappers[Sig] =
F;
600 if (
auto *CalleeF = dyn_cast<Function>(Callee))
601 if (CalleeF->isIntrinsic())
608 if (isa<InlineAsm>(Callee))
610 StringRef CalleeName = Callee->getName();
616 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
620 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
621 CalleeName ==
"__wasm_setjmp" || CalleeName ==
"__wasm_setjmp_test" ||
622 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
626 if (Callee->getName().starts_with(
"__cxa_find_matching_catch_"))
661 if (CalleeName ==
"__cxa_end_catch")
663 if (CalleeName ==
"__cxa_begin_catch" ||
664 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
665 CalleeName ==
"__clang_call_terminate")
670 if (CalleeName ==
"_ZSt9terminatev")
678 StringRef CalleeName = Callee->getName();
680 return CalleeName ==
"emscripten_asm_const_int" ||
681 CalleeName ==
"emscripten_asm_const_double" ||
682 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
683 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
684 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
703void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
706 PHINode *&CallEmLongjmpBBThrewPHI,
PHINode *&CallEmLongjmpBBThrewValuePHI,
712 IRB.SetCurrentDebugLocation(
DL);
715 IRB.SetInsertPoint(BB);
720 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
721 ThrewValueGV->
getName() +
".val");
722 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
723 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
724 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
727 if (!CallEmLongjmpBB) {
730 IRB.SetInsertPoint(CallEmLongjmpBB);
731 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
732 CallEmLongjmpBBThrewValuePHI =
733 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
734 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
735 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
736 IRB.CreateCall(EmLongjmpF,
737 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
738 IRB.CreateUnreachable();
740 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
741 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
746 IRB.SetInsertPoint(ThenBB1);
750 Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF,
751 {ThrewPtr, FunctionInvocationId},
"label");
752 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
753 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
756 IRB.SetInsertPoint(EndBB2);
757 IRB.CreateCall(SetTempRet0F, ThrewValue);
758 IRB.CreateBr(EndBB1);
760 IRB.SetInsertPoint(ElseBB1);
761 IRB.CreateBr(EndBB1);
764 IRB.SetInsertPoint(EndBB1);
765 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
773 LongjmpResult = IRB.CreateCall(GetTempRet0F, {},
"longjmp_result");
776void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(
Function &
F) {
777 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
783 if (
I.getType()->isVoidTy())
786 if (isa<AllocaInst>(&
I)) {
790 bool HasNonDominatedLifetimeMarker =
any_of(
I.users(), [&](
User *U) {
791 auto *UserI = cast<Instruction>(U);
792 return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
794 if (HasNonDominatedLifetimeMarker) {
796 auto *UserI = cast<Instruction>(U);
797 if (UserI->isLifetimeStartOrEnd())
798 UserI->eraseFromParent();
803 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
806 if (
auto *
II = dyn_cast<InvokeInst>(&
I))
810 for (
auto &U :
I.uses()) {
811 auto *
User = cast<Instruction>(
U.getUser());
812 if (
auto *UserPN = dyn_cast<PHINode>(
User))
813 if (UserPN->getIncomingBlock(U) == &BB)
821 SSA.RewriteAllUses(&DT);
832void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(
Function *LongjmpF,
834 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
843 auto *CI = dyn_cast<CallInst>(U);
845 IRB.SetInsertPoint(CI);
846 Value *Env =
nullptr;
847 if (NewF == EmLongjmpF)
851 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
856 for (
auto *
I : ToErase)
857 I->eraseFromParent();
861 if (!LongjmpF->
uses().empty()) {
863 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
869 for (
const auto &BB : *
F)
870 for (
const auto &
I : BB)
871 if (
const auto *CB = dyn_cast<CallBase>(&
I))
884 Function *SetjmpF = M.getFunction(
"setjmp");
888 auto *CB = cast<CallBase>(U);
894 if (
auto *
II = dyn_cast<InvokeInst>(CB))
897 CI = cast<CallInst>(CB);
901 for (
auto *
I : ToErase)
902 I->eraseFromParent();
905bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
906 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
911 Function *SetjmpF =
M.getFunction(
"setjmp");
912 Function *LongjmpF =
M.getFunction(
"longjmp");
917 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
918 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
933 "longjmp and _longjmp have different function types");
941 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
942 assert(TPC &&
"Expected a TargetPassConfig");
950 GetTempRet0F =
getFunction(FunctionType::get(IRB.getInt32Ty(),
false),
953 getFunction(FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
958 bool Changed =
false;
964 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
965 ResumeF =
getFunction(ResumeFTy,
"__resumeException", &M);
970 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
971 EHTypeIDF =
getFunction(EHTypeIDTy,
"llvm_eh_typeid_for", &M);
978 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
981 if (
auto *CB = dyn_cast<CallBase>(U)) {
982 auto *UserF = CB->getFunction();
987 SetjmpUsers.
insert(UserF);
989 SetjmpUsersToNullify.
insert(UserF);
1000 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
1001 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
1002 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
1006 assert(EnableEmSjLj || EnableWasmSjLj);
1010 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
1011 EmLongjmpF =
getFunction(FTy,
"emscripten_longjmp", &M);
1012 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
1014 Type *Int8PtrTy = IRB.getPtrTy();
1017 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
1018 WasmLongjmpF =
getFunction(FTy,
"__wasm_longjmp", &M);
1019 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1023 Type *Int8PtrTy = IRB.getPtrTy();
1024 Type *Int32PtrTy = IRB.getPtrTy();
1030 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1032 WasmSetjmpF =
getFunction(FTy,
"__wasm_setjmp", &M);
1035 FTy = FunctionType::get(Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1036 WasmSetjmpTestF =
getFunction(FTy,
"__wasm_setjmp_test", &M);
1051 if (
F.isDeclaration())
1053 Changed |= runEHOnFunction(
F);
1061 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1066 runSjLjOnFunction(*
F);
1070 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1073 for (
Function *
F : SetjmpUsersToNullify)
1078 for (
auto *V : {ThrewGV, ThrewValueGV})
1079 if (V &&
V->use_empty())
1080 V->eraseFromParent();
1081 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1082 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1083 if (V &&
V->use_empty())
1084 V->eraseFromParent();
1089bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(
Function &
F) {
1093 bool Changed =
false;
1101 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1104 auto *
II = dyn_cast<InvokeInst>(BB.getTerminator());
1108 LandingPads.
insert(
II->getLandingPadInst());
1109 IRB.SetInsertPoint(
II);
1112 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1115 Value *Threw = wrapInvoke(
II);
1138 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1141 if (!RethrowLongjmpBB) {
1143 IRB.SetInsertPoint(RethrowLongjmpBB);
1144 RethrowLongjmpBBThrewPHI =
1146 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1147 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1148 ThrewValueGV->
getName() +
".val");
1149 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1150 IRB.CreateUnreachable();
1152 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1155 IRB.SetInsertPoint(
II);
1161 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1162 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1163 IRB.SetInsertPoint(
Tail);
1164 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1169 IRB.CreateCondBr(Cmp,
II->getUnwindDest(),
II->getNormalDest());
1182 auto *RI = dyn_cast<ResumeInst>(&
I);
1188 Value *Input = RI->getValue();
1189 IRB.SetInsertPoint(RI);
1190 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1192 IRB.CreateCall(ResumeF, {
Low});
1194 IRB.CreateUnreachable();
1202 auto *CI = dyn_cast<CallInst>(&
I);
1208 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1212 IRB.SetInsertPoint(CI);
1223 if (
auto *LPI = dyn_cast<LandingPadInst>(
I))
1226 Changed |= !LandingPads.
empty();
1231 IRB.SetInsertPoint(LPI);
1233 for (
unsigned I = 0, E = LPI->getNumClauses();
I < E; ++
I) {
1237 if (LPI->isCatch(
I))
1242 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1243 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1245 Value *Pair0 = IRB.CreateInsertValue(
Poison, FMCI, 0,
"pair0");
1246 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, {},
"tempret0");
1247 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1255 I->eraseFromParent();
1277 return DILocation::get(SP->getContext(), SP->getLine(), 1, SP);
1281bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(
Function &
F) {
1282 assert(EnableEmSjLj || EnableWasmSjLj);
1292 if (
auto *AI = dyn_cast<AllocaInst>(&
I))
1293 if (AI->isStaticAlloca())
1302 AI->moveBefore(
Entry->getTerminator()->getIterator());
1304 IRB.SetInsertPoint(
Entry->getTerminator()->getIterator());
1309 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1314 Function *SetjmpF =
M.getFunction(
"setjmp");
1316 auto *CB = cast<CallBase>(U);
1323 SS <<
"In function " +
F.getName() +
1324 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1331 if (
auto *
II = dyn_cast<InvokeInst>(CB))
1334 CI = cast<CallInst>(CB);
1342 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1343 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1355 IRB.SetInsertPoint(CI);
1357 FunctionInvocationId};
1358 IRB.CreateCall(WasmSetjmpF, Args);
1364 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1367 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1371 I->eraseFromParent();
1390void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1402 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1405 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1412 std::vector<BasicBlock *> BBs;
1417 for (
unsigned I = 0;
I < BBs.size();
I++) {
1420 if (isa<InvokeInst>(&
I)) {
1423 SS <<
"In function " <<
F.getName()
1424 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1425 "restriction that `setjmp` function call and exception cannot be "
1426 "used within the same function:\n";
1430 auto *CI = dyn_cast<CallInst>(&
I);
1440 ". Please consider using EM_JS, or move the "
1441 "EM_ASM into another function.",
1444 Value *Threw =
nullptr;
1446 if (
Callee->getName().starts_with(
"__invoke_")) {
1455 if (
auto *LI = dyn_cast<LoadInst>(
I))
1456 if (
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1457 if (GV == ThrewGV) {
1458 Threw = ThrewLI = LI;
1466 if (
auto *SI = dyn_cast<StoreInst>(
I)) {
1467 if (
auto *GV = dyn_cast<GlobalVariable>(
SI->getPointerOperand())) {
1468 if (GV == ThrewGV &&
1476 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1477 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1482 Threw = wrapInvoke(CI);
1507 if (supportsException(&
F) &&
canThrow(Callee)) {
1513 if (!RethrowExnBB) {
1515 IRB.SetInsertPoint(RethrowExnBB);
1517 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1518 IRB.CreateCall(ResumeF, {Exn});
1519 IRB.CreateUnreachable();
1522 IRB.SetInsertPoint(CI);
1526 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1528 IRB.SetInsertPoint(NormalBB);
1543 Value *LongjmpResult =
nullptr;
1545 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1546 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1547 CallEmLongjmpBBThrewValuePHI, EndBB);
1548 assert(Label && LongjmpResult && EndBB);
1551 IRB.SetInsertPoint(EndBB);
1558 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1559 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1560 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1570 I->eraseFromParent();
1575 if (
const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1576 return CRI->getUnwindDest();
1585void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1596 if (!
F.hasPersonalityFn()) {
1599 FunctionType::get(IRB.getInt32Ty(),
true);
1600 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1602 cast<Constant>(IRB.CreateBitCast(PersF, IRB.getPtrTy())));
1608 IRB.SetCurrentDebugLocation(FirstDL);
1624 cast<BranchInst>(
Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
1629 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1635 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1636 IRB.SetInsertPoint(CatchLongjmpBB);
1637 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1646 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1648 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1650 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1652 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1661 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1663 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1664 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1666 IRB.SetInsertPoint(ThenBB);
1667 CallInst *WasmLongjmpCI = IRB.CreateCall(
1669 IRB.CreateUnreachable();
1671 IRB.SetInsertPoint(EndBB);
1673 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1683 IRB.SetInsertPoint(SetjmpDispatchBB);
1684 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1687 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1692 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1693 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1694 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1700 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1701 for (
auto &
I : *BB) {
1702 auto *CI = dyn_cast<CallInst>(&
I);
1711 ". Please consider using EM_JS, or move the "
1712 "EM_ASM into another function.",
1717 if (CI == WasmLongjmpCI)
1724 UnwindDestToNewPreds;
1725 for (
auto *CI : LongjmpableCalls) {
1731 CalleeF->removeFnAttr(Attribute::NoUnwind);
1739 Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
1740 while (!UnwindDest) {
1741 if (
auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
1742 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1745 if (
auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
1752 Value *ParentPad = CPI->getParentPad();
1753 if (isa<ConstantTokenNone>(ParentPad))
1755 FromPad = cast<Instruction>(ParentPad);
1760 UnwindDest = CatchDispatchLongjmpBB;
1770 for (
auto &BB :
F) {
1771 if (
auto *CSI = dyn_cast<CatchSwitchInst>(BB.getFirstNonPHIIt())) {
1772 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1773 IRB.SetInsertPoint(CSI);
1775 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1776 CatchDispatchLongjmpBB, 1);
1777 NewCSI->addHandler(*CSI->handler_begin());
1778 NewCSI->takeName(CSI);
1779 CSI->replaceAllUsesWith(NewCSI);
1783 if (
auto *CRI = dyn_cast<CleanupReturnInst>(BB.getTerminator())) {
1784 if (CRI->unwindsToCaller()) {
1785 IRB.SetInsertPoint(CRI);
1787 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1793 I->eraseFromParent();
1801 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1803 for (
auto *NewPred : NewPreds) {
1804 assert(PN.getBasicBlockIndex(NewPred) == -1);
1815 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1818 SSA.Initialize(PN.getType(), PN.getName());
1819 for (
unsigned Idx = 0, E = PN.getNumIncomingValues();
Idx != E; ++
Idx) {
1820 if (NewPreds.contains(PN.getIncomingBlock(
Idx)))
1823 if (
auto *
II = dyn_cast<InvokeInst>(V))
1824 SSA.AddAvailableValue(
II->getNormalDest(),
II);
1825 else if (
auto *
I = dyn_cast<Instruction>(V))
1826 SSA.AddAvailableValue(
I->getParent(),
I);
1828 SSA.AddAvailableValue(PN.getIncomingBlock(
Idx), V);
1830 for (
auto *NewPred : NewPreds)
1831 PN.setIncomingValueForBlock(NewPred,
SSA.GetValueAtEndOfBlock(NewPred));
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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)
Target-Independent Code Generator Pass Configuration Options pass.
static void nullifySetjmp(Function *F)
static void markAsImported(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 Function * getFunction(FunctionType *Ty, const Twine &Name, Module *M)
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 GlobalVariable * getGlobalVariable(Module &M, Type *Ty, WebAssemblyTargetMachine &TM, const char *Name)
static bool isEmAsmCall(const Value *Callee)
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.
an instruction to allocate memory on the stack
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
LLVM_ABI AttributeSet getFnAttrs() const
The function attributes are returned.
static LLVM_ABI AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)
Create an AttributeList with the specified parameters in it.
LLVM_ABI AttributeSet getRetAttrs() const
The attributes for the ret value are returned.
LLVM_ABI AttributeSet getParamAttrs(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
static LLVM_ABI 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.
LLVM_ABI void addHandler(BasicBlock *Dest)
Add an entry to the switch instruction... Note: This action invalidates handler_end().
static LLVM_ABI ConstantTokenNone * get(LLVMContext &Context)
Return the ConstantTokenNone.
This is an important base class in LLVM.
Subprogram description. Uses SubclassData1.
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
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.
LLVM_ABI 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.
LLVM_ABI 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.
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 LLVM_ABI 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 LLVM_ABI 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 LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
LLVM Value Representation.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI StringRef getEHPersonalityName(EHPersonality Pers)
LLVM_ABI BasicBlock * changeToInvokeAndSplitBasicBlock(CallInst *CI, BasicBlock *UnwindEdge, DomTreeUpdater *DTU=nullptr)
Convert the CallInst to InvokeInst with the specified unwind edge basic block.
LLVM_ABI 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
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI 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.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
ModulePass * createWebAssemblyLowerEmscriptenEHSjLj()
void replace(R &&Range, const T &OldValue, const T &NewValue)
Provide wrappers to std::replace which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI 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...