272#include "llvm/IR/IntrinsicsWebAssembly.h"
283#define DEBUG_TYPE "wasm-lower-em-ehsjlj"
287 cl::desc(
"The list of function names in which Emscripten-style "
288 "exception handling is enabled (see emscripten "
289 "EMSCRIPTEN_CATCHING_ALLOWED options)"),
293class WebAssemblyLowerEmscriptenEHSjLj final :
public ModulePass {
307 Function *WasmSetjmpTestF =
nullptr;
312 Type *LongjmpArgsTy =
nullptr;
320 std::set<std::string, std::less<>> EHAllowlistSet;
325 return "WebAssembly Lower Emscripten Exceptions";
328 using InstVector = SmallVectorImpl<Instruction *>;
329 bool runEHOnFunction(Function &
F);
330 bool runSjLjOnFunction(Function &
F);
331 void handleLongjmpableCallsForEmscriptenSjLj(
332 Function &
F, Instruction *FunctionInvocationId,
333 SmallVectorImpl<PHINode *> &SetjmpRetPHIs);
335 handleLongjmpableCallsForWasmSjLj(Function &
F,
336 Instruction *FunctionInvocationId,
337 SmallVectorImpl<PHINode *> &SetjmpRetPHIs);
340 Value *wrapInvoke(CallBase *CI);
343 Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
344 PHINode *&CallEmLongjmpBBThrewPHI,
345 PHINode *&CallEmLongjmpBBThrewValuePHI,
347 Function *getInvokeWrapper(CallBase *CI);
349 bool areAllExceptionsAllowed()
const {
return EHAllowlistSet.empty(); }
350 bool supportsException(
const Function *
F)
const {
352 (areAllExceptionsAllowed() || EHAllowlistSet.count(
F->getName()));
354 void replaceLongjmpWith(Function *LongjmpF, Function *NewF);
356 void rebuildSSA(Function &
F);
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");
371 bool runOnModule(
Module &M)
override;
373 void getAnalysisUsage(AnalysisUsage &AU)
const override {
379char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
381 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
385 return new WebAssemblyLowerEmscriptenEHSjLj();
391 if (
F->isIntrinsic())
395 if (Name ==
"setjmp" || Name ==
"longjmp" || Name ==
"emscripten_longjmp")
397 return !
F->doesNotThrow();
429 OS << *FTy->getReturnType();
430 for (
Type *ParamTy : FTy->params())
431 OS <<
"_" << *ParamTy;
451 if (!
F->hasFnAttribute(
"wasm-import-module")) {
452 llvm::AttrBuilder
B(
F->getParent()->getContext());
453 B.addAttribute(
"wasm-import-module",
"env");
456 if (!
F->hasFnAttribute(
"wasm-import-name")) {
457 llvm::AttrBuilder
B(
F->getParent()->getContext());
458 B.addAttribute(
"wasm-import-name",
F->getName());
467 return IRB.
getIntNTy(M->getDataLayout().getPointerSizeInBits());
482 return IRB.
getIntN(M->getDataLayout().getPointerSizeInBits(),
C);
488 Attribute FeaturesAttr =
F.getFnAttribute(
"target-features");
489 return FeaturesAttr.
isValid() &&
499WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
500 unsigned NumClauses) {
504 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
506 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
508 FTy,
"__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
521Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
523 LLVMContext &
C =
M->getContext();
526 IRB.SetInsertPoint(CI);
533 SmallVector<Value *, 16>
Args;
538 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
552 ArgAttributes.
push_back(InvokeAL.getParamAttrs(
I));
554 AttrBuilder FnAttrs(CI->
getContext(), InvokeAL.getFnAttrs());
555 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
558 auto [SizeArg, NEltArg] = *
Args;
561 NEltArg = *NEltArg + 1;
562 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
566 FnAttrs.removeAttribute(Attribute::NoReturn);
569 AttributeList NewCallAL = AttributeList::get(
584Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallBase *CI) {
590 auto It = InvokeWrappers.
find(Sig);
591 if (It != InvokeWrappers.
end())
597 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
599 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
600 CalleeFTy->isVarArg());
603 InvokeWrappers[Sig] =
F;
609 if (CalleeF->isIntrinsic())
618 StringRef CalleeName = Callee->getName();
624 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
628 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
629 CalleeName ==
"__wasm_setjmp" || CalleeName ==
"__wasm_setjmp_test" ||
630 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
634 if (Callee->getName().starts_with(
"__cxa_find_matching_catch_"))
669 if (CalleeName ==
"__cxa_end_catch")
671 if (CalleeName ==
"__cxa_begin_catch" ||
672 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
673 CalleeName ==
"__clang_call_terminate")
678 if (CalleeName ==
"_ZSt9terminatev")
686 StringRef CalleeName = Callee->getName();
688 return CalleeName ==
"emscripten_asm_const_int" ||
689 CalleeName ==
"emscripten_asm_const_double" ||
690 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
691 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
692 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
711void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
713 Value *&Label,
Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
714 PHINode *&CallEmLongjmpBBThrewPHI, PHINode *&CallEmLongjmpBBThrewValuePHI,
715 BasicBlock *&EndBB) {
718 LLVMContext &
C =
M->getContext();
720 IRB.SetCurrentDebugLocation(
DL);
723 IRB.SetInsertPoint(BB);
728 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
729 ThrewValueGV->
getName() +
".val");
730 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
731 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
732 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
735 if (!CallEmLongjmpBB) {
738 IRB.SetInsertPoint(CallEmLongjmpBB);
739 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
740 CallEmLongjmpBBThrewValuePHI =
741 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
742 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
743 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
744 IRB.CreateCall(EmLongjmpF,
745 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
746 IRB.CreateUnreachable();
748 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
749 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
754 IRB.SetInsertPoint(ThenBB1);
758 Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF,
759 {ThrewPtr, FunctionInvocationId},
"label");
760 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
761 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
764 IRB.SetInsertPoint(EndBB2);
765 IRB.CreateCall(SetTempRet0F, ThrewValue);
766 IRB.CreateBr(EndBB1);
768 IRB.SetInsertPoint(ElseBB1);
769 IRB.CreateBr(EndBB1);
772 IRB.SetInsertPoint(EndBB1);
773 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
781 LongjmpResult = IRB.CreateCall(GetTempRet0F, {},
"longjmp_result");
784void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &
F) {
785 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
789 for (BasicBlock &BB :
F) {
790 for (Instruction &
I : BB) {
791 if (
I.getType()->isVoidTy())
798 bool HasNonDominatedLifetimeMarker =
any_of(
I.users(), [&](User *U) {
799 auto *UserI = cast<Instruction>(U);
800 return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
802 if (HasNonDominatedLifetimeMarker) {
805 if (UserI->isLifetimeStartOrEnd())
806 UserI->eraseFromParent();
811 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
818 for (
auto &U :
I.uses()) {
821 if (UserPN->getIncomingBlock(U) == &BB)
829 SSA.RewriteAllUses(&DT);
840void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(Function *LongjmpF,
842 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
850 for (User *U : LongjmpF->
users()) {
853 IRB.SetInsertPoint(CI);
854 Value *Env =
nullptr;
855 if (NewF == EmLongjmpF)
859 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
864 for (
auto *
I : ToErase)
865 I->eraseFromParent();
869 if (!LongjmpF->
uses().empty()) {
871 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
877 for (
const auto &BB : *
F)
878 for (
const auto &
I : BB)
909 for (
auto *
I : ToErase)
910 I->eraseFromParent();
913bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
914 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
916 LLVMContext &
C =
M.getContext();
919 Function *SetjmpF =
M.getFunction(
"setjmp");
920 Function *LongjmpF =
M.getFunction(
"longjmp");
925 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
926 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
941 "longjmp and _longjmp have different function types");
949 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
950 assert(TPC &&
"Expected a TargetPassConfig");
951 auto &TM = TPC->getTM<WebAssemblyTargetMachine>();
958 GetTempRet0F =
getFunction(FunctionType::get(IRB.getInt32Ty(),
false),
961 getFunction(FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
971 FunctionType *ResumeFTy =
972 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
973 ResumeF =
getFunction(ResumeFTy,
"__resumeException", &M);
977 FunctionType *EHTypeIDTy =
978 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
979 EHTypeIDF =
getFunction(EHTypeIDTy,
"llvm_eh_typeid_for", &M);
984 SmallPtrSet<Function *, 4> SetjmpUsersToNullify;
986 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
988 for (User *U : SetjmpF->
users()) {
990 auto *UserF = CB->getFunction();
995 SetjmpUsers.
insert(UserF);
997 SetjmpUsersToNullify.
insert(UserF);
1000 raw_string_ostream
SS(S);
1008 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
1009 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
1010 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
1014 assert(EnableEmSjLj || EnableWasmSjLj);
1018 FunctionType *FTy = FunctionType::get(
1019 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
1020 EmLongjmpF =
getFunction(FTy,
"emscripten_longjmp", &M);
1021 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
1023 Type *Int8PtrTy = IRB.getPtrTy();
1025 FunctionType *FTy = FunctionType::get(
1026 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
1027 WasmLongjmpF =
getFunction(FTy,
"__wasm_longjmp", &M);
1028 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1031 if (EnableWasmSjLj) {
1032 for (
auto *SjLjF : {SetjmpF, LongjmpF}) {
1034 for (User *U : SjLjF->users()) {
1039 " is using setjmp/longjmp but does not have "
1040 "+exception-handling target feature");
1048 Type *Int8PtrTy = IRB.getPtrTy();
1049 Type *Int32PtrTy = IRB.getPtrTy();
1054 FunctionType *FTy = FunctionType::get(
1055 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1057 WasmSetjmpF =
getFunction(FTy,
"__wasm_setjmp", &M);
1060 FTy = FunctionType::get(
Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1061 WasmSetjmpTestF =
getFunction(FTy,
"__wasm_setjmp_test", &M);
1075 for (Function &
F : M) {
1076 if (
F.isDeclaration())
1086 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1090 for (Function *
F : SetjmpUsers)
1091 runSjLjOnFunction(*
F);
1095 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1098 for (Function *
F : SetjmpUsersToNullify)
1103 for (
auto *V : {ThrewGV, ThrewValueGV})
1104 if (V &&
V->use_empty())
1105 V->eraseFromParent();
1106 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1107 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1108 if (V &&
V->use_empty())
1109 V->eraseFromParent();
1114bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &
F) {
1116 LLVMContext &
C =
F.getContext();
1120 SmallPtrSet<LandingPadInst *, 32> LandingPads;
1126 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1128 for (BasicBlock &BB :
F) {
1133 LandingPads.
insert(
II->getLandingPadInst());
1134 IRB.SetInsertPoint(
II);
1137 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1140 Value *Threw = wrapInvoke(
II);
1163 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1166 if (!RethrowLongjmpBB) {
1168 IRB.SetInsertPoint(RethrowLongjmpBB);
1169 RethrowLongjmpBBThrewPHI =
1171 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1172 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1173 ThrewValueGV->
getName() +
".val");
1174 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1175 IRB.CreateUnreachable();
1177 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1180 IRB.SetInsertPoint(
II);
1186 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1187 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1188 IRB.SetInsertPoint(
Tail);
1189 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1194 IRB.CreateCondBr(Cmp,
II->getUnwindDest(),
II->getNormalDest());
1204 for (BasicBlock &BB :
F) {
1206 for (Instruction &
I : BB) {
1213 Value *Input = RI->getValue();
1214 IRB.SetInsertPoint(RI);
1215 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1217 IRB.CreateCall(ResumeF, {
Low});
1219 IRB.CreateUnreachable();
1225 for (BasicBlock &BB :
F) {
1226 for (Instruction &
I : BB) {
1233 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1237 IRB.SetInsertPoint(CI);
1246 for (BasicBlock &BB :
F) {
1255 for (LandingPadInst *LPI : LandingPads) {
1256 IRB.SetInsertPoint(LPI);
1257 SmallVector<Value *, 16> FMCArgs;
1258 for (
unsigned I = 0,
E = LPI->getNumClauses();
I <
E; ++
I) {
1262 if (LPI->isCatch(
I))
1267 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1268 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1270 Value *Pair0 = IRB.CreateInsertValue(
Poison, FMCI, 0,
"pair0");
1271 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, {},
"tempret0");
1272 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1274 LPI->replaceAllUsesWith(Pair1);
1279 for (Instruction *
I : ToErase)
1280 I->eraseFromParent();
1306bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &
F) {
1307 assert(EnableEmSjLj || EnableWasmSjLj);
1309 LLVMContext &
C =
F.getContext();
1316 for (Instruction &
I :
F.getEntryBlock())
1318 if (AI->isStaticAlloca())
1326 for (AllocaInst *AI : StaticAllocas)
1327 AI->moveBefore(
Entry->getTerminator()->getIterator());
1329 IRB.SetInsertPoint(
Entry->getTerminator()->getIterator());
1334 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1339 Function *SetjmpF =
M.getFunction(
"setjmp");
1347 raw_string_ostream
SS(S);
1348 SS <<
"In function " +
F.getName() +
1349 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1354 CallInst *CI =
nullptr;
1367 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1368 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1380 IRB.SetInsertPoint(CI);
1382 FunctionInvocationId};
1383 IRB.CreateCall(WasmSetjmpF, Args);
1389 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1392 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1395 for (Instruction *
I : ToErase)
1396 I->eraseFromParent();
1415void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1416 Function &
F, Instruction *FunctionInvocationId,
1417 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1419 LLVMContext &
C =
F.getContext();
1427 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1430 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1437 std::vector<BasicBlock *> BBs;
1438 for (BasicBlock &BB :
F)
1442 for (
unsigned I = 0;
I < BBs.size();
I++) {
1444 for (Instruction &
I : *BB) {
1447 raw_string_ostream
SS(S);
1448 SS <<
"In function " <<
F.getName()
1449 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1450 "restriction that `setjmp` function call and exception cannot be "
1451 "used within the same function:\n";
1465 ". Please consider using EM_JS, or move the "
1466 "EM_ASM into another function.",
1469 Value *Threw =
nullptr;
1471 if (
Callee->getName().starts_with(
"__invoke_")) {
1476 LoadInst *ThrewLI =
nullptr;
1477 StoreInst *ThrewResetSI =
nullptr;
1482 if (GV == ThrewGV) {
1483 Threw = ThrewLI = LI;
1493 if (GV == ThrewGV &&
1501 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1502 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1507 Threw = wrapInvoke(CI);
1532 if (supportsException(&
F) &&
canThrow(Callee)) {
1538 if (!RethrowExnBB) {
1540 IRB.SetInsertPoint(RethrowExnBB);
1542 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1543 IRB.CreateCall(ResumeF, {Exn});
1544 IRB.CreateUnreachable();
1547 IRB.SetInsertPoint(CI);
1551 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1553 IRB.SetInsertPoint(NormalBB);
1568 Value *LongjmpResult =
nullptr;
1570 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1571 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1572 CallEmLongjmpBBThrewValuePHI, EndBB);
1573 assert(Label && LongjmpResult && EndBB);
1576 IRB.SetInsertPoint(EndBB);
1578 SwitchInst *
SI = IRB.CreateSwitch(Label,
Tail, SetjmpRetPHIs.
size());
1583 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1584 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1585 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1590 BBs.push_back(
Tail);
1594 for (Instruction *
I : ToErase)
1595 I->eraseFromParent();
1601 return CRI->getUnwindDest();
1610void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1611 Function &
F, Instruction *FunctionInvocationId,
1612 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1614 LLVMContext &
C =
F.getContext();
1621 if (!
F.hasPersonalityFn()) {
1623 FunctionType *PersType =
1624 FunctionType::get(IRB.getInt32Ty(),
true);
1625 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1633 IRB.SetCurrentDebugLocation(FirstDL);
1654 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1655 CatchSwitchInst *CatchSwitchLongjmp =
1660 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1661 IRB.SetInsertPoint(CatchLongjmpBB);
1662 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1671 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1673 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1675 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1677 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1686 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1688 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1689 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1691 IRB.SetInsertPoint(ThenBB);
1692 CallInst *WasmLongjmpCI = IRB.CreateCall(
1694 IRB.CreateUnreachable();
1696 IRB.SetInsertPoint(EndBB);
1698 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1708 IRB.SetInsertPoint(SetjmpDispatchBB);
1709 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1712 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1717 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1718 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1719 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1725 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1726 for (
auto &
I : *BB) {
1736 ". Please consider using EM_JS, or move the "
1737 "EM_ASM into another function.",
1742 if (CI == WasmLongjmpCI)
1748 SmallDenseMap<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4>
1749 UnwindDestToNewPreds;
1750 for (
auto *CI : LongjmpableCalls) {
1756 CalleeF->removeFnAttr(Attribute::NoUnwind);
1765 while (!UnwindDest) {
1767 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1777 Value *ParentPad = CPI->getParentPad();
1785 UnwindDest = CatchDispatchLongjmpBB;
1794 SmallVector<Instruction *, 16> ToErase;
1795 for (
auto &BB :
F) {
1797 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1798 IRB.SetInsertPoint(CSI);
1800 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1801 CatchDispatchLongjmpBB, 1);
1802 NewCSI->addHandler(*CSI->handler_begin());
1803 NewCSI->takeName(CSI);
1804 CSI->replaceAllUsesWith(NewCSI);
1809 if (CRI->unwindsToCaller()) {
1810 IRB.SetInsertPoint(CRI);
1812 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1817 for (Instruction *
I : ToErase)
1818 I->eraseFromParent();
1826 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1827 for (PHINode &PN : UnwindDest->
phis()) {
1828 for (
auto *NewPred : NewPreds) {
1829 assert(PN.getBasicBlockIndex(NewPred) == -1);
1840 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1841 for (PHINode &PN : UnwindDest->
phis()) {
1843 SSA.Initialize(PN.getType(), PN.getName());
1844 for (
unsigned Idx = 0,
E = PN.getNumIncomingValues(); Idx !=
E; ++Idx) {
1845 if (NewPreds.contains(PN.getIncomingBlock(Idx)))
1847 Value *
V = PN.getIncomingValue(Idx);
1849 SSA.AddAvailableValue(
II->getNormalDest(),
II);
1851 SSA.AddAvailableValue(
I->getParent(),
I);
1853 SSA.AddAvailableValue(PN.getIncomingBlock(Idx), V);
1855 for (
auto *NewPred : NewPreds)
1856 PN.setIncomingValueForBlock(NewPred,
SSA.GetValueAtEndOfBlock(NewPred));
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.
Machine Check Debug Module
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Target-Independent Code Generator Pass Configuration Options pass.
static void nullifySetjmp(Function *F)
static void markAsImported(Function *F)
static bool canLongjmp(const Value *Callee)
static cl::list< std::string > EHAllowlist("emscripten-cxx-exceptions-allowed", cl::desc("The list of function names in which Emscripten-style " "exception handling is enabled (see emscripten " "EMSCRIPTEN_CATCHING_ALLOWED options)"), cl::CommaSeparated)
static 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 Value * getAddrSizeInt(Module *M, uint64_t C)
static GlobalVariable * getGlobalVariable(Module &M, Type *Ty, WebAssemblyTargetMachine &TM, const char *Name)
static bool isEmAsmCall(const Value *Callee)
This file declares the WebAssembly-specific subclass of TargetMachine.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
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...
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)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
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)
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.
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.
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)
StringRef - 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.
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.
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.
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 * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
cl::opt< bool > WasmEnableSjLj
cl::opt< bool > WasmEnableEmEH
cl::opt< bool > WasmEnableEmSjLj
@ 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.
FunctionAddr VTableAddr Value
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.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
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...
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...
ModulePass * createWebAssemblyLowerEmscriptenEHSjLj()
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.