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()));
356 void replaceLongjmpWith(Function *LongjmpF, Function *NewF);
358 void rebuildSSA(Function &
F);
361 WebAssemblyLowerEmscriptenEHSjLjImpl(
362 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 {
378 StringRef getPassName()
const override {
379 return "WebAssembly Lower Emscripten Exceptions";
385 WebAssemblyLowerEmscriptenEHSjLjLegacy() : ModulePass(ID) {}
386 bool runOnModule(
Module &M)
override;
388 void getAnalysisUsage(AnalysisUsage &AU)
const override {
394char WebAssemblyLowerEmscriptenEHSjLjLegacy::ID = 0;
396 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
400 return new WebAssemblyLowerEmscriptenEHSjLjLegacy();
406 if (
F->isIntrinsic())
410 if (Name ==
"setjmp" || Name ==
"longjmp" || Name ==
"emscripten_longjmp")
412 return !
F->doesNotThrow();
443 OS << *FTy->getReturnType();
444 for (
Type *ParamTy : FTy->params())
445 OS <<
"_" << *ParamTy;
465 if (!
F->hasFnAttribute(
"wasm-import-module")) {
466 llvm::AttrBuilder
B(
F->getParent()->getContext());
467 B.addAttribute(
"wasm-import-module",
"env");
470 if (!
F->hasFnAttribute(
"wasm-import-name")) {
471 llvm::AttrBuilder
B(
F->getParent()->getContext());
472 B.addAttribute(
"wasm-import-name",
F->getName());
481 return IRB.
getIntNTy(M->getDataLayout().getPointerSizeInBits());
496 return IRB.
getIntN(M->getDataLayout().getPointerSizeInBits(),
C);
502 Attribute FeaturesAttr =
F.getFnAttribute(
"target-features");
503 return FeaturesAttr.
isValid() &&
512Function *WebAssemblyLowerEmscriptenEHSjLjImpl::getFindMatchingCatch(
513 Module &M,
unsigned NumClauses) {
517 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
519 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
521 FTy,
"__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
534Value *WebAssemblyLowerEmscriptenEHSjLjImpl::wrapInvoke(CallBase *CI) {
536 LLVMContext &
C =
M->getContext();
539 IRB.SetInsertPoint(CI);
546 SmallVector<Value *, 16>
Args;
551 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
565 ArgAttributes.
push_back(InvokeAL.getParamAttrs(
I));
567 AttrBuilder FnAttrs(CI->
getContext(), InvokeAL.getFnAttrs());
568 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
571 auto [SizeArg, NEltArg] = *
Args;
574 NEltArg = *NEltArg + 1;
575 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
579 FnAttrs.removeAttribute(Attribute::NoReturn);
582 AttributeList NewCallAL = AttributeList::get(
597Function *WebAssemblyLowerEmscriptenEHSjLjImpl::getInvokeWrapper(CallBase *CI) {
603 auto It = InvokeWrappers.
find(Sig);
604 if (It != InvokeWrappers.
end())
610 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
612 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
613 CalleeFTy->isVarArg());
616 InvokeWrappers[Sig] =
F;
622 if (CalleeF->isIntrinsic())
631 StringRef CalleeName = Callee->getName();
637 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
641 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
642 CalleeName ==
"__wasm_setjmp" || CalleeName ==
"__wasm_setjmp_test" ||
643 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
647 if (Callee->getName().starts_with(
"__cxa_find_matching_catch_"))
682 if (CalleeName ==
"__cxa_end_catch")
684 if (CalleeName ==
"__cxa_begin_catch" ||
685 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
686 CalleeName ==
"__clang_call_terminate")
691 if (CalleeName ==
"_ZSt9terminatev")
699 StringRef CalleeName = Callee->getName();
701 return CalleeName ==
"emscripten_asm_const_int" ||
702 CalleeName ==
"emscripten_asm_const_double" ||
703 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
704 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
705 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
724void WebAssemblyLowerEmscriptenEHSjLjImpl::wrapTestSetjmp(
726 Value *&Label,
Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
727 PHINode *&CallEmLongjmpBBThrewPHI, PHINode *&CallEmLongjmpBBThrewValuePHI,
728 BasicBlock *&EndBB) {
731 LLVMContext &
C =
M->getContext();
733 IRB.SetCurrentDebugLocation(
DL);
736 IRB.SetInsertPoint(BB);
741 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
742 ThrewValueGV->
getName() +
".val");
743 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
744 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
745 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
748 if (!CallEmLongjmpBB) {
751 IRB.SetInsertPoint(CallEmLongjmpBB);
752 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
753 CallEmLongjmpBBThrewValuePHI =
754 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
755 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
756 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
757 IRB.CreateCall(EmLongjmpF,
758 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
759 IRB.CreateUnreachable();
761 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
762 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
767 IRB.SetInsertPoint(ThenBB1);
771 Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF,
772 {ThrewPtr, FunctionInvocationId},
"label");
773 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
774 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
777 IRB.SetInsertPoint(EndBB2);
778 IRB.CreateCall(SetTempRet0F, ThrewValue);
779 IRB.CreateBr(EndBB1);
781 IRB.SetInsertPoint(ElseBB1);
782 IRB.CreateBr(EndBB1);
785 IRB.SetInsertPoint(EndBB1);
786 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
794 LongjmpResult = IRB.CreateCall(GetTempRet0F, {},
"longjmp_result");
797void WebAssemblyLowerEmscriptenEHSjLjImpl::rebuildSSA(Function &
F) {
798 DominatorTree &DT = GetDominatorTree(
F);
802 for (BasicBlock &BB :
F) {
803 for (Instruction &
I : BB) {
804 if (
I.getType()->isVoidTy())
811 bool HasNonDominatedLifetimeMarker =
any_of(
I.users(), [&](User *U) {
812 auto *UserI = cast<Instruction>(U);
813 return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
815 if (HasNonDominatedLifetimeMarker) {
818 if (UserI->isLifetimeStartOrEnd())
819 UserI->eraseFromParent();
824 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
831 for (
auto &U :
I.uses()) {
834 if (UserPN->getIncomingBlock(U) == &BB)
842 SSA.RewriteAllUses(&DT);
853void WebAssemblyLowerEmscriptenEHSjLjImpl::replaceLongjmpWith(
854 Function *LongjmpF, Function *NewF) {
855 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
863 for (User *U : LongjmpF->
users()) {
866 IRB.SetInsertPoint(CI);
867 Value *Env =
nullptr;
868 if (NewF == EmLongjmpF)
872 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
877 for (
auto *
I : ToErase)
878 I->eraseFromParent();
882 if (!LongjmpF->
uses().empty()) {
884 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
890 for (
const auto &BB : *
F)
891 for (
const auto &
I : BB)
922 for (
auto *
I : ToErase)
923 I->eraseFromParent();
926bool WebAssemblyLowerEmscriptenEHSjLjImpl::runOnModule(
Module &M) {
927 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
929 LLVMContext &
C =
M.getContext();
932 Function *SetjmpF =
M.getFunction(
"setjmp");
933 Function *LongjmpF =
M.getFunction(
"longjmp");
938 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
939 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
954 "longjmp and _longjmp have different function types");
967 GetTempRet0F =
getFunction(FunctionType::get(IRB.getInt32Ty(),
false),
970 getFunction(FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
980 FunctionType *ResumeFTy =
981 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
982 ResumeF =
getFunction(ResumeFTy,
"__resumeException", &M);
986 FunctionType *EHTypeIDTy =
987 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
988 EHTypeIDF =
getFunction(EHTypeIDTy,
"llvm_eh_typeid_for", &M);
993 SmallPtrSet<Function *, 4> SetjmpUsersToNullify;
995 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
997 for (User *U : SetjmpF->
users()) {
999 auto *UserF = CB->getFunction();
1004 SetjmpUsers.
insert(UserF);
1006 SetjmpUsersToNullify.
insert(UserF);
1009 raw_string_ostream
SS(S);
1017 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
1018 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
1019 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
1023 assert(EnableEmSjLj || EnableWasmSjLj);
1027 FunctionType *FTy = FunctionType::get(
1028 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
1029 EmLongjmpF =
getFunction(FTy,
"emscripten_longjmp", &M);
1030 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
1032 Type *Int8PtrTy = IRB.getPtrTy();
1034 FunctionType *FTy = FunctionType::get(
1035 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
1036 WasmLongjmpF =
getFunction(FTy,
"__wasm_longjmp", &M);
1037 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1040 if (EnableWasmSjLj) {
1041 for (
auto *SjLjF : {SetjmpF, LongjmpF}) {
1043 for (User *U : SjLjF->users()) {
1048 " is using setjmp/longjmp but does not have "
1049 "+exception-handling target feature");
1057 Type *Int8PtrTy = IRB.getPtrTy();
1058 Type *Int32PtrTy = IRB.getPtrTy();
1063 FunctionType *FTy = FunctionType::get(
1064 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1066 WasmSetjmpF =
getFunction(FTy,
"__wasm_setjmp", &M);
1069 FTy = FunctionType::get(Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1070 WasmSetjmpTestF =
getFunction(FTy,
"__wasm_setjmp_test", &M);
1084 for (Function &
F : M) {
1085 if (
F.isDeclaration())
1095 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1099 for (Function *
F : SetjmpUsers)
1100 runSjLjOnFunction(*
F);
1104 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1107 for (Function *
F : SetjmpUsersToNullify)
1112 for (
auto *V : {ThrewGV, ThrewValueGV})
1113 if (V &&
V->use_empty())
1114 V->eraseFromParent();
1115 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1116 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1117 if (V &&
V->use_empty())
1118 V->eraseFromParent();
1123bool WebAssemblyLowerEmscriptenEHSjLjImpl::runEHOnFunction(Function &
F) {
1125 LLVMContext &
C =
F.getContext();
1129 SmallPtrSet<LandingPadInst *, 32> LandingPads;
1135 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1137 for (BasicBlock &BB :
F) {
1142 LandingPads.
insert(
II->getLandingPadInst());
1143 IRB.SetInsertPoint(
II);
1146 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1149 Value *Threw = wrapInvoke(
II);
1172 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1175 if (!RethrowLongjmpBB) {
1177 IRB.SetInsertPoint(RethrowLongjmpBB);
1178 RethrowLongjmpBBThrewPHI =
1180 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1181 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1182 ThrewValueGV->
getName() +
".val");
1183 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1184 IRB.CreateUnreachable();
1186 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1189 IRB.SetInsertPoint(
II);
1195 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1196 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1197 IRB.SetInsertPoint(
Tail);
1198 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1203 IRB.CreateCondBr(Cmp,
II->getUnwindDest(),
II->getNormalDest());
1213 for (BasicBlock &BB :
F) {
1215 for (Instruction &
I : BB) {
1222 Value *Input = RI->getValue();
1223 IRB.SetInsertPoint(RI);
1224 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1226 IRB.CreateCall(ResumeF, {
Low});
1228 IRB.CreateUnreachable();
1234 for (BasicBlock &BB :
F) {
1235 for (Instruction &
I : BB) {
1242 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1246 IRB.SetInsertPoint(CI);
1255 for (BasicBlock &BB :
F) {
1264 for (LandingPadInst *LPI : LandingPads) {
1265 IRB.SetInsertPoint(LPI);
1266 SmallVector<Value *, 16> FMCArgs;
1267 for (
unsigned I = 0,
E = LPI->getNumClauses();
I <
E; ++
I) {
1271 if (LPI->isCatch(
I))
1276 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1277 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1279 Value *Pair0 = IRB.CreateInsertValue(
Poison, FMCI, 0,
"pair0");
1280 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, {},
"tempret0");
1281 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1283 LPI->replaceAllUsesWith(Pair1);
1288 for (Instruction *
I : ToErase)
1289 I->eraseFromParent();
1315bool WebAssemblyLowerEmscriptenEHSjLjImpl::runSjLjOnFunction(Function &
F) {
1316 assert(EnableEmSjLj || EnableWasmSjLj);
1318 LLVMContext &
C =
F.getContext();
1324 SmallVector<AllocaInst *> StaticAllocas;
1325 for (Instruction &
I :
F.getEntryBlock())
1327 if (AI->isStaticAlloca())
1335 for (AllocaInst *AI : StaticAllocas)
1336 AI->moveBefore(
Entry->getTerminator()->getIterator());
1338 IRB.SetInsertPoint(
Entry->getTerminator()->getIterator());
1343 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1348 Function *SetjmpF =
M.getFunction(
"setjmp");
1356 raw_string_ostream
SS(S);
1357 SS <<
"In function " +
F.getName() +
1358 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1363 CallInst *CI =
nullptr;
1376 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1377 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1389 IRB.SetInsertPoint(CI);
1391 FunctionInvocationId};
1392 IRB.CreateCall(WasmSetjmpF, Args);
1398 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1401 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1404 for (Instruction *
I : ToErase)
1405 I->eraseFromParent();
1424void WebAssemblyLowerEmscriptenEHSjLjImpl::
1425 handleLongjmpableCallsForEmscriptenSjLj(
1426 Function &
F, Instruction *FunctionInvocationId,
1427 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1429 LLVMContext &
C =
F.getContext();
1437 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1440 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1447 std::vector<BasicBlock *> BBs;
1448 for (BasicBlock &BB :
F)
1452 for (
unsigned I = 0;
I < BBs.size();
I++) {
1454 for (Instruction &
I : *BB) {
1457 raw_string_ostream
SS(S);
1458 SS <<
"In function " <<
F.getName()
1459 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1460 "restriction that `setjmp` function call and exception cannot be "
1461 "used within the same function:\n";
1475 ". Please consider using EM_JS, or move the "
1476 "EM_ASM into another function.",
1479 Value *Threw =
nullptr;
1481 if (
Callee->getName().starts_with(
"__invoke_")) {
1486 LoadInst *ThrewLI =
nullptr;
1487 StoreInst *ThrewResetSI =
nullptr;
1492 if (GV == ThrewGV) {
1493 Threw = ThrewLI = LI;
1503 if (GV == ThrewGV &&
1511 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1512 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1517 Threw = wrapInvoke(CI);
1542 if (supportsException(&
F) &&
canThrow(Callee)) {
1548 if (!RethrowExnBB) {
1550 IRB.SetInsertPoint(RethrowExnBB);
1552 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1553 IRB.CreateCall(ResumeF, {Exn});
1554 IRB.CreateUnreachable();
1557 IRB.SetInsertPoint(CI);
1561 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1563 IRB.SetInsertPoint(NormalBB);
1578 Value *LongjmpResult =
nullptr;
1580 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1581 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1582 CallEmLongjmpBBThrewValuePHI, EndBB);
1583 assert(Label && LongjmpResult && EndBB);
1586 IRB.SetInsertPoint(EndBB);
1588 SwitchInst *
SI = IRB.CreateSwitch(Label,
Tail, SetjmpRetPHIs.
size());
1593 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1594 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1595 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1600 BBs.push_back(
Tail);
1604 for (Instruction *
I : ToErase)
1605 I->eraseFromParent();
1611 return CRI->getUnwindDest();
1620void WebAssemblyLowerEmscriptenEHSjLjImpl::handleLongjmpableCallsForWasmSjLj(
1621 Function &
F, Instruction *FunctionInvocationId,
1622 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1624 LLVMContext &
C =
F.getContext();
1631 if (!
F.hasPersonalityFn()) {
1633 FunctionType *PersType =
1634 FunctionType::get(IRB.getInt32Ty(),
true);
1635 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1643 IRB.SetCurrentDebugLocation(FirstDL);
1664 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1665 CatchSwitchInst *CatchSwitchLongjmp =
1670 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1671 IRB.SetInsertPoint(CatchLongjmpBB);
1672 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1679 IRB.CreateCall(CatchF, {IRB.getInt32(WebAssembly::C_LONGJMP)},
"thrown");
1681 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1683 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1685 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1687 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1696 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1698 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1699 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1701 IRB.SetInsertPoint(ThenBB);
1702 CallInst *WasmLongjmpCI = IRB.CreateCall(
1704 IRB.CreateUnreachable();
1706 IRB.SetInsertPoint(EndBB);
1708 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1718 IRB.SetInsertPoint(SetjmpDispatchBB);
1719 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1722 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1727 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1728 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1729 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1735 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1736 for (
auto &
I : *BB) {
1746 ". Please consider using EM_JS, or move the "
1747 "EM_ASM into another function.",
1752 if (CI == WasmLongjmpCI)
1758 SmallMapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4>
1759 UnwindDestToNewPreds;
1760 for (
auto *CI : LongjmpableCalls) {
1766 CalleeF->removeFnAttr(Attribute::NoUnwind);
1775 while (!UnwindDest) {
1777 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1787 Value *ParentPad = CPI->getParentPad();
1795 UnwindDest = CatchDispatchLongjmpBB;
1804 SmallVector<Instruction *, 16> ToErase;
1805 for (
auto &BB :
F) {
1807 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1808 IRB.SetInsertPoint(CSI);
1810 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1811 CatchDispatchLongjmpBB, 1);
1812 NewCSI->addHandler(*CSI->handler_begin());
1813 NewCSI->takeName(CSI);
1814 CSI->replaceAllUsesWith(NewCSI);
1819 if (CRI->unwindsToCaller()) {
1820 IRB.SetInsertPoint(CRI);
1822 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1827 for (Instruction *
I : ToErase)
1828 I->eraseFromParent();
1836 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1837 for (PHINode &PN : UnwindDest->
phis()) {
1838 for (
auto *NewPred : NewPreds) {
1839 assert(PN.getBasicBlockIndex(NewPred) == -1);
1850 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1851 for (PHINode &PN : UnwindDest->
phis()) {
1853 SSA.Initialize(PN.getType(), PN.getName());
1854 for (
unsigned Idx = 0,
E = PN.getNumIncomingValues(); Idx !=
E; ++Idx) {
1855 if (NewPreds.contains(PN.getIncomingBlock(Idx)))
1857 Value *
V = PN.getIncomingValue(Idx);
1859 SSA.AddAvailableValue(
II->getNormalDest(),
II);
1861 SSA.AddAvailableValue(
I->getParent(),
I);
1863 SSA.AddAvailableValue(PN.getIncomingBlock(Idx), V);
1865 for (
auto *NewPred : NewPreds)
1866 PN.setIncomingValueForBlock(NewPred,
SSA.GetValueAtEndOfBlock(NewPred));
1872bool WebAssemblyLowerEmscriptenEHSjLjLegacy::runOnModule(
Module &M) {
1873 WebAssemblyLowerEmscriptenEHSjLjImpl Impl(
1874 [&](Function &
F) -> DominatorTree & {
1875 return getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
1877 return Impl.runOnModule(M);
1883 WebAssemblyLowerEmscriptenEHSjLjImpl Impl(
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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 > WasmEnableEmEH
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.
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(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
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...
@ C
The default llvm calling convention, compatible with C.
@ 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.
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.
ModulePass * createWebAssemblyLowerEmscriptenEHSjLjLegacyPass()
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.