274#include "llvm/IR/IntrinsicsWebAssembly.h"
287#define DEBUG_TYPE "wasm-lower-em-ehsjlj"
291 cl::desc(
"The list of function names in which Emscripten-style "
292 "exception handling is enabled (see emscripten "
293 "EMSCRIPTEN_CATCHING_ALLOWED options)"),
297class WebAssemblyLowerEmscriptenEHSjLjImpl {
311 Function *WasmSetjmpTestF =
nullptr;
316 Type *LongjmpArgsTy =
nullptr;
324 std::set<std::string, std::less<>> EHAllowlistSet;
333 void handleLongjmpableCallsForEmscriptenSjLj(
337 handleLongjmpableCallsForWasmSjLj(
Function &
F,
346 PHINode *&CallEmLongjmpBBThrewPHI,
347 PHINode *&CallEmLongjmpBBThrewValuePHI,
351 bool areAllExceptionsAllowed()
const {
return EHAllowlistSet.empty(); }
352 bool supportsException(
const Function *
F)
const {
354 (areAllExceptionsAllowed() || EHAllowlistSet.count(
F->getName()));
361 WebAssemblyLowerEmscriptenEHSjLjImpl(
363 std::function<DominatorTree &(
Function &
F)> GetDominatorTree)
366 GetDominatorTree(GetDominatorTree) {
367 assert(!(EnableEmSjLj && EnableWasmSjLj) &&
368 "Two SjLj modes cannot be turned on at the same time");
369 assert(!(EnableEmEH && EnableWasmSjLj) &&
370 "Wasm SjLj should be only used with Wasm EH");
374 bool runOnModule(
Module &M);
377class WebAssemblyLowerEmscriptenEHSjLjLegacy final :
public ModulePass {
380 StringRef getPassName()
const override {
381 return "WebAssembly Lower Emscripten Exceptions";
387 WebAssemblyLowerEmscriptenEHSjLjLegacy(
bool EnableEmEH =
false)
388 : ModulePass(ID), EnableEmEH(EnableEmEH) {}
389 bool runOnModule(
Module &M)
override;
391 void getAnalysisUsage(AnalysisUsage &AU)
const override {
397char WebAssemblyLowerEmscriptenEHSjLjLegacy::ID = 0;
399 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
404 return new WebAssemblyLowerEmscriptenEHSjLjLegacy(EnableEmEH);
411 if (Name ==
"setjmp" || Name ==
"longjmp" || Name ==
"emscripten_longjmp")
413 return !
F->doesNotThrow();
428 return M.getOrInsertGlobal(Name, Ty, [&]() {
444 OS << *FTy->getReturnType();
445 for (
Type *ParamTy : FTy->params())
446 OS <<
"_" << *ParamTy;
466 if (!
F->hasFnAttribute(
"wasm-import-module")) {
467 llvm::AttrBuilder
B(
F->getParent()->getContext());
468 B.addAttribute(
"wasm-import-module",
"env");
471 if (!
F->hasFnAttribute(
"wasm-import-name")) {
472 llvm::AttrBuilder
B(
F->getParent()->getContext());
473 B.addAttribute(
"wasm-import-name",
F->getName());
482 return IRB.
getIntNTy(M->getDataLayout().getPointerSizeInBits());
497 return IRB.
getIntN(M->getDataLayout().getPointerSizeInBits(),
C);
503 Attribute FeaturesAttr =
F.getFnAttribute(
"target-features");
504 return FeaturesAttr.
isValid() &&
513Function *WebAssemblyLowerEmscriptenEHSjLjImpl::getFindMatchingCatch(
514 Module &M,
unsigned NumClauses) {
518 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
520 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
522 FTy,
"__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
535Value *WebAssemblyLowerEmscriptenEHSjLjImpl::wrapInvoke(CallBase *CI) {
537 LLVMContext &
C =
M->getContext();
540 IRB.SetInsertPoint(CI);
547 SmallVector<Value *, 16>
Args;
552 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
566 ArgAttributes.
push_back(InvokeAL.getParamAttrs(
I));
568 AttrBuilder FnAttrs(CI->
getContext(), InvokeAL.getFnAttrs());
569 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
572 auto [SizeArg, NEltArg] = *
Args;
575 NEltArg = *NEltArg + 1;
576 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
580 FnAttrs.removeAttribute(Attribute::NoReturn);
583 AttributeList NewCallAL = AttributeList::get(
598Function *WebAssemblyLowerEmscriptenEHSjLjImpl::getInvokeWrapper(CallBase *CI) {
604 auto It = InvokeWrappers.
find(Sig);
605 if (It != InvokeWrappers.
end())
611 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
613 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
614 CalleeFTy->isVarArg());
617 InvokeWrappers[Sig] =
F;
623 if (CalleeF->isIntrinsic())
632 StringRef CalleeName = Callee->getName();
638 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
642 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
643 CalleeName ==
"__wasm_setjmp" || CalleeName ==
"__wasm_setjmp_test" ||
644 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
648 if (Callee->getName().starts_with(
"__cxa_find_matching_catch_"))
683 if (CalleeName ==
"__cxa_end_catch")
685 if (CalleeName ==
"__cxa_begin_catch" ||
686 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
687 CalleeName ==
"__clang_call_terminate")
692 if (CalleeName ==
"_ZSt9terminatev")
700 StringRef CalleeName = Callee->getName();
702 return CalleeName ==
"emscripten_asm_const_int" ||
703 CalleeName ==
"emscripten_asm_const_double" ||
704 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
705 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
706 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
725void WebAssemblyLowerEmscriptenEHSjLjImpl::wrapTestSetjmp(
727 Value *&Label,
Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
728 PHINode *&CallEmLongjmpBBThrewPHI, PHINode *&CallEmLongjmpBBThrewValuePHI,
729 BasicBlock *&EndBB) {
732 LLVMContext &
C =
M->getContext();
734 IRB.SetCurrentDebugLocation(
DL);
737 IRB.SetInsertPoint(BB);
742 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
743 ThrewValueGV->
getName() +
".val");
744 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
745 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
746 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
749 if (!CallEmLongjmpBB) {
752 IRB.SetInsertPoint(CallEmLongjmpBB);
753 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
754 CallEmLongjmpBBThrewValuePHI =
755 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
756 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
757 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
758 IRB.CreateCall(EmLongjmpF,
759 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
760 IRB.CreateUnreachable();
762 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
763 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
768 IRB.SetInsertPoint(ThenBB1);
772 Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF,
773 {ThrewPtr, FunctionInvocationId},
"label");
774 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
775 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
778 IRB.SetInsertPoint(EndBB2);
779 IRB.CreateCall(SetTempRet0F, ThrewValue);
780 IRB.CreateBr(EndBB1);
782 IRB.SetInsertPoint(ElseBB1);
783 IRB.CreateBr(EndBB1);
786 IRB.SetInsertPoint(EndBB1);
787 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
795 LongjmpResult = IRB.CreateCall(GetTempRet0F, {},
"longjmp_result");
798void WebAssemblyLowerEmscriptenEHSjLjImpl::rebuildSSA(
Function &
F) {
799 DominatorTree &DT = GetDominatorTree(
F);
803 for (BasicBlock &BB :
F) {
804 for (Instruction &
I : BB) {
805 if (
I.getType()->isVoidTy())
812 bool HasNonDominatedLifetimeMarker =
any_of(
I.users(), [&](User *U) {
813 auto *UserI = cast<Instruction>(U);
814 return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
816 if (HasNonDominatedLifetimeMarker) {
819 if (UserI->isLifetimeStartOrEnd())
820 UserI->eraseFromParent();
825 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
832 for (
auto &U :
I.uses()) {
835 if (UserPN->getIncomingBlock(U) == &BB)
843 SSA.RewriteAllUses(&DT);
854void WebAssemblyLowerEmscriptenEHSjLjImpl::replaceLongjmpWith(
856 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
864 for (User *U : LongjmpF->
users()) {
867 IRB.SetInsertPoint(CI);
868 Value *Env =
nullptr;
869 if (NewF == EmLongjmpF)
873 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
878 for (
auto *
I : ToErase)
879 I->eraseFromParent();
883 if (!LongjmpF->
uses().empty()) {
885 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
891 for (
const auto &BB : *
F)
892 for (
const auto &
I : BB)
923 for (
auto *
I : ToErase)
924 I->eraseFromParent();
927bool WebAssemblyLowerEmscriptenEHSjLjImpl::runOnModule(
Module &M) {
928 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
933 EnableEmEH |=
M.getExceptionModel() == ExceptionHandling::Emscripten;
935 LLVMContext &
C =
M.getContext();
938 Function *SetjmpF =
M.getFunction(
"setjmp");
939 Function *LongjmpF =
M.getFunction(
"longjmp");
944 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
945 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
960 "longjmp and _longjmp have different function types");
973 GetTempRet0F =
getFunction(FunctionType::get(IRB.getInt32Ty(),
false),
976 getFunction(FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
986 FunctionType *ResumeFTy =
987 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
988 ResumeF =
getFunction(ResumeFTy,
"__resumeException", &M);
992 FunctionType *EHTypeIDTy =
993 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
994 EHTypeIDF =
getFunction(EHTypeIDTy,
"llvm_eh_typeid_for", &M);
999 SmallPtrSet<Function *, 4> SetjmpUsersToNullify;
1001 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
1003 for (User *U : SetjmpF->
users()) {
1005 auto *UserF = CB->getFunction();
1010 SetjmpUsers.
insert(UserF);
1012 SetjmpUsersToNullify.
insert(UserF);
1015 raw_string_ostream
SS(S);
1023 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
1024 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
1025 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
1029 assert(EnableEmSjLj || EnableWasmSjLj);
1033 FunctionType *FTy = FunctionType::get(
1034 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
1035 EmLongjmpF =
getFunction(FTy,
"emscripten_longjmp", &M);
1036 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
1038 Type *Int8PtrTy = IRB.getPtrTy();
1040 FunctionType *FTy = FunctionType::get(
1041 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
1042 WasmLongjmpF =
getFunction(FTy,
"__wasm_longjmp", &M);
1043 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1046 if (EnableWasmSjLj) {
1047 for (
auto *SjLjF : {SetjmpF, LongjmpF}) {
1049 for (User *U : SjLjF->users()) {
1054 " is using setjmp/longjmp but does not have "
1055 "+exception-handling target feature");
1063 Type *Int8PtrTy = IRB.getPtrTy();
1064 Type *Int32PtrTy = IRB.getPtrTy();
1069 FunctionType *FTy = FunctionType::get(
1070 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1072 WasmSetjmpF =
getFunction(FTy,
"__wasm_setjmp", &M);
1075 FTy = FunctionType::get(Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1076 WasmSetjmpTestF =
getFunction(FTy,
"__wasm_setjmp_test", &M);
1091 if (
F.isDeclaration())
1101 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1106 runSjLjOnFunction(*
F);
1110 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1113 for (
Function *
F : SetjmpUsersToNullify)
1118 for (
auto *V : {ThrewGV, ThrewValueGV})
1119 if (V &&
V->use_empty())
1120 V->eraseFromParent();
1121 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1122 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1123 if (V &&
V->use_empty())
1124 V->eraseFromParent();
1129bool WebAssemblyLowerEmscriptenEHSjLjImpl::runEHOnFunction(
Function &
F) {
1131 LLVMContext &
C =
F.getContext();
1135 SmallPtrSet<LandingPadInst *, 32> LandingPads;
1141 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1143 for (BasicBlock &BB :
F) {
1148 LandingPads.
insert(
II->getLandingPadInst());
1149 IRB.SetInsertPoint(
II);
1152 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1155 Value *Threw = wrapInvoke(
II);
1178 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1181 if (!RethrowLongjmpBB) {
1183 IRB.SetInsertPoint(RethrowLongjmpBB);
1184 RethrowLongjmpBBThrewPHI =
1186 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1187 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1188 ThrewValueGV->
getName() +
".val");
1189 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1190 IRB.CreateUnreachable();
1192 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1195 IRB.SetInsertPoint(
II);
1201 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1202 IRB.CreateCondBr(
Or, Tail, RethrowLongjmpBB);
1203 IRB.SetInsertPoint(Tail);
1204 BB.replaceSuccessorsPhiUsesWith(&BB, Tail);
1209 IRB.CreateCondBr(Cmp,
II->getUnwindDest(),
II->getNormalDest());
1219 for (BasicBlock &BB :
F) {
1221 for (Instruction &
I : BB) {
1228 Value *Input = RI->getValue();
1229 IRB.SetInsertPoint(RI);
1230 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1232 IRB.CreateCall(ResumeF, {
Low});
1234 IRB.CreateUnreachable();
1240 for (BasicBlock &BB :
F) {
1241 for (Instruction &
I : BB) {
1248 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1252 IRB.SetInsertPoint(CI);
1261 for (BasicBlock &BB :
F) {
1270 for (LandingPadInst *LPI : LandingPads) {
1271 IRB.SetInsertPoint(LPI);
1272 SmallVector<Value *, 16> FMCArgs;
1273 for (
unsigned I = 0,
E = LPI->getNumClauses();
I <
E; ++
I) {
1277 if (LPI->isCatch(
I))
1282 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1283 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1285 Value *Pair0 = IRB.CreateInsertValue(
Poison, FMCI, 0,
"pair0");
1286 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, {},
"tempret0");
1287 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1289 LPI->replaceAllUsesWith(Pair1);
1294 for (Instruction *
I : ToErase)
1295 I->eraseFromParent();
1321bool WebAssemblyLowerEmscriptenEHSjLjImpl::runSjLjOnFunction(
Function &
F) {
1322 assert(EnableEmSjLj || EnableWasmSjLj);
1324 LLVMContext &
C =
F.getContext();
1330 SmallVector<AllocaInst *> StaticAllocas;
1331 for (Instruction &
I :
F.getEntryBlock())
1333 if (AI->isStaticAlloca())
1341 for (AllocaInst *AI : StaticAllocas)
1342 AI->moveBefore(
Entry->getTerminator()->getIterator());
1344 IRB.SetInsertPoint(
Entry->getTerminator()->getIterator());
1349 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1354 Function *SetjmpF =
M.getFunction(
"setjmp");
1362 raw_string_ostream
SS(S);
1363 SS <<
"In function " +
F.getName() +
1364 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1369 CallInst *CI =
nullptr;
1382 IRB.SetInsertPoint(Tail,
Tail->getFirstNonPHIIt());
1383 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1395 IRB.SetInsertPoint(CI);
1397 FunctionInvocationId};
1398 IRB.CreateCall(WasmSetjmpF, Args);
1404 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1407 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1410 for (Instruction *
I : ToErase)
1411 I->eraseFromParent();
1430void WebAssemblyLowerEmscriptenEHSjLjImpl::
1431 handleLongjmpableCallsForEmscriptenSjLj(
1432 Function &
F, Instruction *FunctionInvocationId,
1433 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1435 LLVMContext &
C =
F.getContext();
1443 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1446 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1453 std::vector<BasicBlock *> BBs;
1454 for (BasicBlock &BB :
F)
1458 for (
unsigned I = 0;
I < BBs.size();
I++) {
1460 for (Instruction &
I : *BB) {
1463 raw_string_ostream
SS(S);
1464 SS <<
"In function " <<
F.getName()
1465 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1466 "restriction that `setjmp` function call and exception cannot be "
1467 "used within the same function:\n";
1481 ". Please consider using EM_JS, or move the "
1482 "EM_ASM into another function.",
1485 Value *Threw =
nullptr;
1487 if (
Callee->getName().starts_with(
"__invoke_")) {
1492 LoadInst *ThrewLI =
nullptr;
1493 StoreInst *ThrewResetSI =
nullptr;
1498 if (GV == ThrewGV) {
1499 Threw = ThrewLI = LI;
1509 if (GV == ThrewGV &&
1517 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1518 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1523 Threw = wrapInvoke(CI);
1548 if (supportsException(&
F) &&
canThrow(Callee)) {
1554 if (!RethrowExnBB) {
1556 IRB.SetInsertPoint(RethrowExnBB);
1558 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1559 IRB.CreateCall(ResumeF, {Exn});
1560 IRB.CreateUnreachable();
1563 IRB.SetInsertPoint(CI);
1567 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1569 IRB.SetInsertPoint(NormalBB);
1584 Value *LongjmpResult =
nullptr;
1586 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1587 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1588 CallEmLongjmpBBThrewValuePHI, EndBB);
1589 assert(Label && LongjmpResult && EndBB);
1592 IRB.SetInsertPoint(EndBB);
1594 SwitchInst *
SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.
size());
1599 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1600 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1601 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1606 BBs.push_back(Tail);
1610 for (Instruction *
I : ToErase)
1611 I->eraseFromParent();
1617 return CRI->getUnwindDest();
1626void WebAssemblyLowerEmscriptenEHSjLjImpl::handleLongjmpableCallsForWasmSjLj(
1627 Function &
F, Instruction *FunctionInvocationId,
1628 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1630 LLVMContext &
C =
F.getContext();
1637 if (!
F.hasPersonalityFn()) {
1639 FunctionType *PersType =
1640 FunctionType::get(IRB.getInt32Ty(),
true);
1641 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1649 IRB.SetCurrentDebugLocation(FirstDL);
1670 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1671 CatchSwitchInst *CatchSwitchLongjmp =
1676 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1677 IRB.SetInsertPoint(CatchLongjmpBB);
1678 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1685 IRB.CreateCall(CatchF, {IRB.getInt32(WebAssembly::C_LONGJMP)},
"thrown");
1687 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1689 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1691 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1693 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1702 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1704 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1705 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1707 IRB.SetInsertPoint(ThenBB);
1708 CallInst *WasmLongjmpCI = IRB.CreateCall(
1710 IRB.CreateUnreachable();
1712 IRB.SetInsertPoint(EndBB);
1714 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1724 IRB.SetInsertPoint(SetjmpDispatchBB);
1725 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1728 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1733 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1734 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1735 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1741 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1742 for (
auto &
I : *BB) {
1752 ". Please consider using EM_JS, or move the "
1753 "EM_ASM into another function.",
1758 if (CI == WasmLongjmpCI)
1764 SmallMapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4>
1765 UnwindDestToNewPreds;
1766 for (
auto *CI : LongjmpableCalls) {
1772 CalleeF->removeFnAttr(Attribute::NoUnwind);
1781 while (!UnwindDest) {
1783 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1793 Value *ParentPad = CPI->getParentPad();
1801 UnwindDest = CatchDispatchLongjmpBB;
1810 SmallVector<Instruction *, 16> ToErase;
1811 for (
auto &BB :
F) {
1813 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1814 IRB.SetInsertPoint(CSI);
1816 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1817 CatchDispatchLongjmpBB, 1);
1818 NewCSI->addHandler(*CSI->handler_begin());
1819 NewCSI->takeName(CSI);
1820 CSI->replaceAllUsesWith(NewCSI);
1825 if (CRI->unwindsToCaller()) {
1826 IRB.SetInsertPoint(CRI);
1828 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1833 for (Instruction *
I : ToErase)
1834 I->eraseFromParent();
1842 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1843 for (PHINode &PN : UnwindDest->
phis()) {
1844 for (
auto *NewPred : NewPreds) {
1845 assert(PN.getBasicBlockIndex(NewPred) == -1);
1856 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1857 for (PHINode &PN : UnwindDest->
phis()) {
1859 SSA.Initialize(PN.getType(), PN.getName());
1860 for (
unsigned Idx = 0,
E = PN.getNumIncomingValues(); Idx !=
E; ++Idx) {
1861 if (NewPreds.contains(PN.getIncomingBlock(Idx)))
1863 Value *
V = PN.getIncomingValue(Idx);
1865 SSA.AddAvailableValue(
II->getNormalDest(),
II);
1867 SSA.AddAvailableValue(
I->getParent(),
I);
1869 SSA.AddAvailableValue(PN.getIncomingBlock(Idx), V);
1871 for (
auto *NewPred : NewPreds)
1872 PN.setIncomingValueForBlock(NewPred,
SSA.GetValueAtEndOfBlock(NewPred));
1878bool WebAssemblyLowerEmscriptenEHSjLjLegacy::runOnModule(
Module &M) {
1879 WebAssemblyLowerEmscriptenEHSjLjImpl Impl(
1880 EnableEmEH, [&](
Function &
F) -> DominatorTree & {
1881 return getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
1883 return Impl.runOnModule(M);
1889 WebAssemblyLowerEmscriptenEHSjLjImpl Impl(
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
uint64_t IntrinsicInst * II
ModuleAnalysisManager MAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
cl::opt< bool > WasmEnableSjLj
cl::opt< bool > WasmEnableEmSjLj
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 bool hasEHTargetFeatureAttr(const Function &F)
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 DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore, DISubprogram *SP)
static bool containsLongjmpableCalls(const Function *F)
static GlobalVariable * getGlobalVariable(Module &M, Type *Ty, const char *Name)
static Value * getAddrSizeInt(Module *M, uint64_t C)
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.
static BasicBlock * getCleanupRetUnwindDest(const CleanupPadInst *CleanupPad)
AnalysisUsage & addRequired()
static LLVM_ABI AttributeSet get(LLVMContext &C, const AttrBuilder &B)
Functions, function parameters, and return types can have attributes to indicate how they should be t...
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
bool isValid() const
Return true if the attribute is any kind of attribute.
LLVM Basic Block Representation.
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
const Function * getParent() const
Return the enclosing method, or null if none.
const Instruction & back() const
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
InstListType::iterator iterator
Instruction iterators...
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.
Subprogram description. Uses SubclassData1.
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Analysis pass which computes a DominatorTree.
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
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.
const Function & getFunction() const
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 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...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
iterator_range< user_iterator > users()
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
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.
static PointerType * getUnqual(LLVMContext &C)
This constructs an opaque pointer to an object in the default address space (address space zero).
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
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.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
iterator find(StringRef Key)
Represent a constant reference to a string, i.e.
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
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.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
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.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
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.
std::string & str()
Returns the string's reference.
Pass manager infrastructure for declaring and invalidating analyses.
cl::opt< bool > WasmEnableSjLj
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
@ BasicBlock
Various leaf nodes.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
@ User
could "use" a pointer
friend class Instruction
Iterator for Instructions in a `BasicBlock.
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.
std::tuple< const DIScope *, const DIScope *, const DILocalVariable * > VarID
A unique key that represents a debug variable.
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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.
ModulePass * createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(bool EnableEmEH)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
OperandBundleDefT< Value * > OperandBundleDef
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.
@ Or
Bitwise or logical OR of integers.
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the specified block at the specified instruction.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
bool isSpace(char C)
Checks whether character C is whitespace in the "C" locale.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.