273#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> 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 {
351 return EnableEmEH && (areAllExceptionsAllowed() ||
352 EHAllowlistSet.count(std::string(
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;
438 std::replace(Sig.begin(), Sig.end(),
',',
'.');
447 if (!
F->hasFnAttribute(
"wasm-import-module")) {
449 B.addAttribute(
"wasm-import-module",
"env");
452 if (!
F->hasFnAttribute(
"wasm-import-name")) {
454 B.addAttribute(
"wasm-import-name",
F->getName());
464 return IRB.
getIntNTy(M->getDataLayout().getPointerSizeInBits());
471 return PointerType::getUnqual(M->getContext());
479 return IRB.
getIntN(M->getDataLayout().getPointerSizeInBits(),
C);
488WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
489 unsigned NumClauses) {
490 if (FindMatchingCatches.
count(NumClauses))
491 return FindMatchingCatches[NumClauses];
492 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
494 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
496 FTy,
"__cxa_find_matching_catch_" +
Twine(NumClauses + 2), &M);
497 FindMatchingCatches[NumClauses] =
F;
508Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(
CallBase *CI) {
513 IRB.SetInsertPoint(CI);
525 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
538 for (
unsigned I = 0, E = CI->
arg_size();
I < E; ++
I)
542 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
545 auto [SizeArg, NEltArg] = *
Args;
548 NEltArg = *NEltArg + 1;
549 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
553 FnAttrs.removeAttribute(Attribute::NoReturn);
578 return InvokeWrappers[Sig];
581 ArgTys.
push_back(PointerType::getUnqual(CalleeFTy));
583 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
585 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
586 CalleeFTy->isVarArg());
588 InvokeWrappers[Sig] =
F;
593 if (
auto *CalleeF = dyn_cast<Function>(Callee))
594 if (CalleeF->isIntrinsic())
601 if (isa<InlineAsm>(Callee))
603 StringRef CalleeName = Callee->getName();
609 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
613 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
614 CalleeName ==
"__wasm_setjmp" || CalleeName ==
"__wasm_setjmp_test" ||
615 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
619 if (Callee->getName().starts_with(
"__cxa_find_matching_catch_"))
657 if (CalleeName ==
"__cxa_end_catch")
659 if (CalleeName ==
"__cxa_begin_catch" ||
660 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
661 CalleeName ==
"__clang_call_terminate")
666 if (CalleeName ==
"_ZSt9terminatev")
674 StringRef CalleeName = Callee->getName();
676 return CalleeName ==
"emscripten_asm_const_int" ||
677 CalleeName ==
"emscripten_asm_const_double" ||
678 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
679 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
680 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
699void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
702 PHINode *&CallEmLongjmpBBThrewPHI,
PHINode *&CallEmLongjmpBBThrewValuePHI,
708 IRB.SetCurrentDebugLocation(
DL);
711 IRB.SetInsertPoint(BB);
716 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
717 ThrewValueGV->
getName() +
".val");
718 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
719 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
720 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
723 if (!CallEmLongjmpBB) {
726 IRB.SetInsertPoint(CallEmLongjmpBB);
727 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
728 CallEmLongjmpBBThrewValuePHI =
729 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
730 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
731 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
732 IRB.CreateCall(EmLongjmpF,
733 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
734 IRB.CreateUnreachable();
736 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
737 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
742 IRB.SetInsertPoint(ThenBB1);
746 Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF,
747 {ThrewPtr, FunctionInvocationId},
"label");
748 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
749 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
752 IRB.SetInsertPoint(EndBB2);
753 IRB.CreateCall(SetTempRet0F, ThrewValue);
754 IRB.CreateBr(EndBB1);
756 IRB.SetInsertPoint(ElseBB1);
757 IRB.CreateBr(EndBB1);
760 IRB.SetInsertPoint(EndBB1);
761 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
769 LongjmpResult = IRB.CreateCall(GetTempRet0F, std::nullopt,
"longjmp_result");
772void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(
Function &
F) {
773 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
779 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
782 if (
auto *II = dyn_cast<InvokeInst>(&
I))
783 SSA.AddAvailableValue(VarID, II->getNormalDest(), II);
785 SSA.AddAvailableValue(VarID, &BB, &
I);
786 for (
auto &U :
I.uses()) {
787 auto *
User = cast<Instruction>(
U.getUser());
788 if (
auto *UserPN = dyn_cast<PHINode>(
User))
789 if (UserPN->getIncomingBlock(U) == &BB)
793 SSA.AddUse(VarID, &U);
797 SSA.RewriteAllUses(&DT);
808void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(
Function *LongjmpF,
810 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
819 auto *CI = dyn_cast<CallInst>(U);
821 IRB.SetInsertPoint(CI);
822 Value *Env =
nullptr;
823 if (NewF == EmLongjmpF)
827 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
832 for (
auto *
I : ToErase)
833 I->eraseFromParent();
837 if (!LongjmpF->
uses().empty()) {
839 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
845 for (
const auto &BB : *
F)
846 for (
const auto &
I : BB)
847 if (
const auto *CB = dyn_cast<CallBase>(&
I))
860 Function *SetjmpF = M.getFunction(
"setjmp");
864 auto *CB = cast<CallBase>(U);
870 if (
auto *II = dyn_cast<InvokeInst>(CB))
873 CI = cast<CallInst>(CB);
877 for (
auto *
I : ToErase)
878 I->eraseFromParent();
881bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
882 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
887 Function *SetjmpF =
M.getFunction(
"setjmp");
888 Function *LongjmpF =
M.getFunction(
"longjmp");
893 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
894 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
909 "longjmp and _longjmp have different function types");
917 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
918 assert(TPC &&
"Expected a TargetPassConfig");
927 FunctionType::get(IRB.getInt32Ty(),
false),
"getTempRet0", &M);
929 FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
934 bool Changed =
false;
940 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
946 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
954 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
957 if (
auto *CB = dyn_cast<CallBase>(U)) {
958 auto *UserF = CB->getFunction();
963 SetjmpUsers.
insert(UserF);
965 SetjmpUsersToNullify.
insert(UserF);
976 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
977 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
978 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
982 assert(EnableEmSjLj || EnableWasmSjLj);
986 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
988 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
990 Type *Int8PtrTy = IRB.getPtrTy();
993 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
995 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
999 Type *Int8PtrTy = IRB.getPtrTy();
1000 Type *Int32PtrTy = IRB.getPtrTy();
1006 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1011 FTy = FunctionType::get(
Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1027 if (
F.isDeclaration())
1029 Changed |= runEHOnFunction(
F);
1037 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1042 runSjLjOnFunction(*
F);
1046 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1049 for (
Function *
F : SetjmpUsersToNullify)
1054 for (
auto *V : {ThrewGV, ThrewValueGV})
1055 if (V &&
V->use_empty())
1056 V->eraseFromParent();
1057 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1058 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1059 if (V &&
V->use_empty())
1060 V->eraseFromParent();
1065bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(
Function &
F) {
1069 bool Changed =
false;
1077 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1080 auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
1084 LandingPads.
insert(II->getLandingPadInst());
1085 IRB.SetInsertPoint(II);
1088 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1091 Value *Threw = wrapInvoke(II);
1114 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1117 if (!RethrowLongjmpBB) {
1119 IRB.SetInsertPoint(RethrowLongjmpBB);
1120 RethrowLongjmpBBThrewPHI =
1122 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1123 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1124 ThrewValueGV->
getName() +
".val");
1125 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1126 IRB.CreateUnreachable();
1128 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1131 IRB.SetInsertPoint(II);
1137 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1138 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1139 IRB.SetInsertPoint(
Tail);
1140 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1145 IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
1158 auto *RI = dyn_cast<ResumeInst>(&
I);
1164 Value *Input = RI->getValue();
1165 IRB.SetInsertPoint(RI);
1166 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1168 IRB.CreateCall(ResumeF, {
Low});
1170 IRB.CreateUnreachable();
1178 auto *CI = dyn_cast<CallInst>(&
I);
1184 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1188 IRB.SetInsertPoint(CI);
1199 if (
auto *LPI = dyn_cast<LandingPadInst>(
I))
1202 Changed |= !LandingPads.
empty();
1207 IRB.SetInsertPoint(LPI);
1209 for (
unsigned I = 0, E = LPI->getNumClauses();
I < E; ++
I) {
1213 if (LPI->isCatch(
I))
1218 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1219 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1221 Value *Pair0 = IRB.CreateInsertValue(Poison, FMCI, 0,
"pair0");
1222 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, std::nullopt,
"tempret0");
1223 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1231 I->eraseFromParent();
1253 return DILocation::get(SP->
getContext(), SP->getLine(), 1, SP);
1257bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(
Function &
F) {
1258 assert(EnableEmSjLj || EnableWasmSjLj);
1268 SplitBlock(Entry, &*Entry->getFirstInsertionPt());
1270 IRB.SetInsertPoint(Entry->getTerminator()->getIterator());
1275 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1280 Function *SetjmpF =
M.getFunction(
"setjmp");
1282 auto *CB = cast<CallBase>(U);
1289 SS <<
"In function " +
F.getName() +
1290 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1297 if (
auto *II = dyn_cast<InvokeInst>(CB))
1300 CI = cast<CallInst>(CB);
1308 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1309 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1321 IRB.SetInsertPoint(CI);
1323 FunctionInvocationId};
1324 IRB.CreateCall(WasmSetjmpF, Args);
1330 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1333 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1337 I->eraseFromParent();
1356void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1368 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1371 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1378 std::vector<BasicBlock *> BBs;
1383 for (
unsigned I = 0;
I < BBs.size();
I++) {
1386 if (isa<InvokeInst>(&
I)) {
1389 SS <<
"In function " <<
F.getName()
1390 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1391 "restriction that `setjmp` function call and exception cannot be "
1392 "used within the same function:\n";
1396 auto *CI = dyn_cast<CallInst>(&
I);
1406 ". Please consider using EM_JS, or move the "
1407 "EM_ASM into another function.",
1410 Value *Threw =
nullptr;
1412 if (
Callee->getName().starts_with(
"__invoke_")) {
1421 if (
auto *LI = dyn_cast<LoadInst>(
I))
1422 if (
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1423 if (GV == ThrewGV) {
1424 Threw = ThrewLI = LI;
1432 if (
auto *SI = dyn_cast<StoreInst>(
I)) {
1433 if (
auto *GV = dyn_cast<GlobalVariable>(
SI->getPointerOperand())) {
1434 if (GV == ThrewGV &&
1442 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1443 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1448 Threw = wrapInvoke(CI);
1473 if (supportsException(&
F) &&
canThrow(Callee)) {
1479 if (!RethrowExnBB) {
1481 IRB.SetInsertPoint(RethrowExnBB);
1483 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1484 IRB.CreateCall(ResumeF, {Exn});
1485 IRB.CreateUnreachable();
1488 IRB.SetInsertPoint(CI);
1492 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1494 IRB.SetInsertPoint(NormalBB);
1509 Value *LongjmpResult =
nullptr;
1511 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1512 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1513 CallEmLongjmpBBThrewValuePHI, EndBB);
1514 assert(Label && LongjmpResult && EndBB);
1517 IRB.SetInsertPoint(EndBB);
1524 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1525 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1526 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1536 I->eraseFromParent();
1541 if (
const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1542 return CRI->getUnwindDest();
1551void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1562 if (!
F.hasPersonalityFn()) {
1565 FunctionType::get(IRB.getInt32Ty(),
true);
1566 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1568 cast<Constant>(IRB.CreateBitCast(PersF, IRB.getPtrTy())));
1574 IRB.SetCurrentDebugLocation(FirstDL);
1587 BasicBlock *OrigEntry = Entry->getNextNode();
1590 cast<BranchInst>(Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
1595 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1601 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1602 IRB.SetInsertPoint(CatchLongjmpBB);
1603 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1612 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1614 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1616 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1618 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1627 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1629 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1630 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1632 IRB.SetInsertPoint(ThenBB);
1633 CallInst *WasmLongjmpCI = IRB.CreateCall(
1635 IRB.CreateUnreachable();
1637 IRB.SetInsertPoint(EndBB);
1639 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1649 IRB.SetInsertPoint(SetjmpDispatchBB);
1650 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1653 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1658 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1659 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1660 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1666 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1667 for (
auto &
I : *BB) {
1668 auto *CI = dyn_cast<CallInst>(&
I);
1677 ". Please consider using EM_JS, or move the "
1678 "EM_ASM into another function.",
1683 if (CI == WasmLongjmpCI)
1689 for (
auto *CI : LongjmpableCalls) {
1695 CalleeF->removeFnAttr(Attribute::NoUnwind);
1704 Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
1705 while (!UnwindDest) {
1706 if (
auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
1707 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1710 if (
auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
1717 Value *ParentPad = CPI->getParentPad();
1718 if (isa<ConstantTokenNone>(ParentPad))
1720 FromPad = cast<Instruction>(ParentPad);
1725 UnwindDest = CatchDispatchLongjmpBB;
1730 for (
auto &BB :
F) {
1731 if (
auto *CSI = dyn_cast<CatchSwitchInst>(BB.getFirstNonPHI())) {
1732 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1733 IRB.SetInsertPoint(CSI);
1735 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1736 CatchDispatchLongjmpBB, 1);
1737 NewCSI->addHandler(*CSI->handler_begin());
1738 NewCSI->takeName(CSI);
1739 CSI->replaceAllUsesWith(NewCSI);
1743 if (
auto *CRI = dyn_cast<CleanupReturnInst>(BB.getTerminator())) {
1744 if (CRI->unwindsToCaller()) {
1745 IRB.SetInsertPoint(CRI);
1747 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1753 I->eraseFromParent();
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Target-Independent Code Generator Pass Configuration Options pass.
static void nullifySetjmp(Function *F)
static bool canLongjmp(const Value *Callee)
static cl::list< std::string > EHAllowlist("emscripten-cxx-exceptions-allowed", cl::desc("The list of function names in which Emscripten-style " "exception handling is enabled (see emscripten " "EMSCRIPTEN_CATCHING_ALLOWED options)"), cl::CommaSeparated)
static Type * getAddrPtrType(Module *M)
static std::string getSignature(FunctionType *FTy)
static Type * getAddrIntType(Module *M)
static bool canThrow(const Value *V)
static BasicBlock * getCleanupRetUnwindDest(const CleanupPadInst *CPI)
static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore, DISubprogram *SP)
static bool containsLongjmpableCalls(const Function *F)
static Value * getAddrSizeInt(Module *M, uint64_t C)
static Function * getEmscriptenFunction(FunctionType *Ty, const Twine &Name, Module *M)
static GlobalVariable * getGlobalVariable(Module &M, Type *Ty, WebAssemblyTargetMachine &TM, const char *Name)
static bool isEmAsmCall(const Value *Callee)
This file provides WebAssembly-specific target descriptions.
This file declares the WebAssembly-specific subclass of TargetMachine.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AttributeSet getFnAttrs() const
The function attributes are returned.
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)
Create an AttributeList with the specified parameters in it.
AttributeSet getRetAttrs() const
The attributes for the ret value are returned.
AttributeSet getParamAttrs(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
static AttributeSet get(LLVMContext &C, const AttrBuilder &B)
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Function * getParent() const
Return the enclosing method, or null if none.
InstListType::iterator iterator
Instruction iterators...
const Instruction & 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.
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...