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);
491WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
492 unsigned NumClauses) {
496 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
498 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
500 FTy,
"__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
513Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
515 LLVMContext &
C =
M->getContext();
518 IRB.SetInsertPoint(CI);
525 SmallVector<Value *, 16>
Args;
530 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
544 ArgAttributes.
push_back(InvokeAL.getParamAttrs(
I));
546 AttrBuilder FnAttrs(CI->
getContext(), InvokeAL.getFnAttrs());
547 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
550 auto [SizeArg, NEltArg] = *
Args;
553 NEltArg = *NEltArg + 1;
554 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
558 FnAttrs.removeAttribute(Attribute::NoReturn);
561 AttributeList NewCallAL = AttributeList::get(
576Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallBase *CI) {
582 auto It = InvokeWrappers.
find(Sig);
583 if (It != InvokeWrappers.
end())
589 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
591 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
592 CalleeFTy->isVarArg());
595 InvokeWrappers[Sig] =
F;
601 if (CalleeF->isIntrinsic())
610 StringRef CalleeName = Callee->getName();
616 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
620 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
621 CalleeName ==
"__wasm_setjmp" || CalleeName ==
"__wasm_setjmp_test" ||
622 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
626 if (Callee->getName().starts_with(
"__cxa_find_matching_catch_"))
661 if (CalleeName ==
"__cxa_end_catch")
663 if (CalleeName ==
"__cxa_begin_catch" ||
664 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
665 CalleeName ==
"__clang_call_terminate")
670 if (CalleeName ==
"_ZSt9terminatev")
678 StringRef CalleeName = Callee->getName();
680 return CalleeName ==
"emscripten_asm_const_int" ||
681 CalleeName ==
"emscripten_asm_const_double" ||
682 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
683 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
684 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
703void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
705 Value *&Label,
Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
706 PHINode *&CallEmLongjmpBBThrewPHI, PHINode *&CallEmLongjmpBBThrewValuePHI,
707 BasicBlock *&EndBB) {
710 LLVMContext &
C =
M->getContext();
712 IRB.SetCurrentDebugLocation(
DL);
715 IRB.SetInsertPoint(BB);
720 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
721 ThrewValueGV->
getName() +
".val");
722 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
723 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
724 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
727 if (!CallEmLongjmpBB) {
730 IRB.SetInsertPoint(CallEmLongjmpBB);
731 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
732 CallEmLongjmpBBThrewValuePHI =
733 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
734 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
735 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
736 IRB.CreateCall(EmLongjmpF,
737 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
738 IRB.CreateUnreachable();
740 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
741 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
746 IRB.SetInsertPoint(ThenBB1);
750 Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF,
751 {ThrewPtr, FunctionInvocationId},
"label");
752 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
753 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
756 IRB.SetInsertPoint(EndBB2);
757 IRB.CreateCall(SetTempRet0F, ThrewValue);
758 IRB.CreateBr(EndBB1);
760 IRB.SetInsertPoint(ElseBB1);
761 IRB.CreateBr(EndBB1);
764 IRB.SetInsertPoint(EndBB1);
765 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
773 LongjmpResult = IRB.CreateCall(GetTempRet0F, {},
"longjmp_result");
776void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &
F) {
777 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
781 for (BasicBlock &BB :
F) {
782 for (Instruction &
I : BB) {
783 if (
I.getType()->isVoidTy())
790 bool HasNonDominatedLifetimeMarker =
any_of(
I.users(), [&](User *U) {
791 auto *UserI = cast<Instruction>(U);
792 return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
794 if (HasNonDominatedLifetimeMarker) {
797 if (UserI->isLifetimeStartOrEnd())
798 UserI->eraseFromParent();
803 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
810 for (
auto &U :
I.uses()) {
813 if (UserPN->getIncomingBlock(U) == &BB)
821 SSA.RewriteAllUses(&DT);
832void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(Function *LongjmpF,
834 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
842 for (User *U : LongjmpF->
users()) {
845 IRB.SetInsertPoint(CI);
846 Value *Env =
nullptr;
847 if (NewF == EmLongjmpF)
851 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
856 for (
auto *
I : ToErase)
857 I->eraseFromParent();
861 if (!LongjmpF->
uses().empty()) {
863 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
869 for (
const auto &BB : *
F)
870 for (
const auto &
I : BB)
901 for (
auto *
I : ToErase)
902 I->eraseFromParent();
905bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
906 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
908 LLVMContext &
C =
M.getContext();
911 Function *SetjmpF =
M.getFunction(
"setjmp");
912 Function *LongjmpF =
M.getFunction(
"longjmp");
917 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
918 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
933 "longjmp and _longjmp have different function types");
941 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
942 assert(TPC &&
"Expected a TargetPassConfig");
943 auto &
TM = TPC->getTM<WebAssemblyTargetMachine>();
950 GetTempRet0F =
getFunction(FunctionType::get(IRB.getInt32Ty(),
false),
953 getFunction(FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
963 FunctionType *ResumeFTy =
964 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
965 ResumeF =
getFunction(ResumeFTy,
"__resumeException", &M);
969 FunctionType *EHTypeIDTy =
970 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
971 EHTypeIDF =
getFunction(EHTypeIDTy,
"llvm_eh_typeid_for", &M);
976 SmallPtrSet<Function *, 4> SetjmpUsersToNullify;
978 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
980 for (User *U : SetjmpF->
users()) {
982 auto *UserF = CB->getFunction();
987 SetjmpUsers.
insert(UserF);
989 SetjmpUsersToNullify.
insert(UserF);
992 raw_string_ostream
SS(S);
1000 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
1001 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
1002 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
1006 assert(EnableEmSjLj || EnableWasmSjLj);
1009 FunctionType *FTy = FunctionType::get(
1010 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
1011 EmLongjmpF =
getFunction(FTy,
"emscripten_longjmp", &M);
1012 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
1014 Type *Int8PtrTy = IRB.getPtrTy();
1016 FunctionType *FTy = FunctionType::get(
1017 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
1018 WasmLongjmpF =
getFunction(FTy,
"__wasm_longjmp", &M);
1019 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1023 Type *Int8PtrTy = IRB.getPtrTy();
1024 Type *Int32PtrTy = IRB.getPtrTy();
1029 FunctionType *FTy = FunctionType::get(
1030 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1032 WasmSetjmpF =
getFunction(FTy,
"__wasm_setjmp", &M);
1035 FTy = FunctionType::get(
Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1036 WasmSetjmpTestF =
getFunction(FTy,
"__wasm_setjmp_test", &M);
1050 for (Function &
F : M) {
1051 if (
F.isDeclaration())
1061 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1065 for (Function *
F : SetjmpUsers)
1066 runSjLjOnFunction(*
F);
1070 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1073 for (Function *
F : SetjmpUsersToNullify)
1078 for (
auto *V : {ThrewGV, ThrewValueGV})
1079 if (V &&
V->use_empty())
1080 V->eraseFromParent();
1081 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1082 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1083 if (V &&
V->use_empty())
1084 V->eraseFromParent();
1089bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &
F) {
1091 LLVMContext &
C =
F.getContext();
1095 SmallPtrSet<LandingPadInst *, 32> LandingPads;
1101 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1103 for (BasicBlock &BB :
F) {
1108 LandingPads.
insert(
II->getLandingPadInst());
1109 IRB.SetInsertPoint(
II);
1112 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1115 Value *Threw = wrapInvoke(
II);
1138 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1141 if (!RethrowLongjmpBB) {
1143 IRB.SetInsertPoint(RethrowLongjmpBB);
1144 RethrowLongjmpBBThrewPHI =
1146 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1147 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1148 ThrewValueGV->
getName() +
".val");
1149 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1150 IRB.CreateUnreachable();
1152 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1155 IRB.SetInsertPoint(
II);
1161 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1162 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1163 IRB.SetInsertPoint(
Tail);
1164 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1169 IRB.CreateCondBr(Cmp,
II->getUnwindDest(),
II->getNormalDest());
1179 for (BasicBlock &BB :
F) {
1181 for (Instruction &
I : BB) {
1188 Value *Input = RI->getValue();
1189 IRB.SetInsertPoint(RI);
1190 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1192 IRB.CreateCall(ResumeF, {
Low});
1194 IRB.CreateUnreachable();
1200 for (BasicBlock &BB :
F) {
1201 for (Instruction &
I : BB) {
1208 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1212 IRB.SetInsertPoint(CI);
1221 for (BasicBlock &BB :
F) {
1230 for (LandingPadInst *LPI : LandingPads) {
1231 IRB.SetInsertPoint(LPI);
1232 SmallVector<Value *, 16> FMCArgs;
1233 for (
unsigned I = 0,
E = LPI->getNumClauses();
I <
E; ++
I) {
1237 if (LPI->isCatch(
I))
1242 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1243 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1245 Value *Pair0 = IRB.CreateInsertValue(
Poison, FMCI, 0,
"pair0");
1246 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, {},
"tempret0");
1247 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1249 LPI->replaceAllUsesWith(Pair1);
1254 for (Instruction *
I : ToErase)
1255 I->eraseFromParent();
1281bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &
F) {
1282 assert(EnableEmSjLj || EnableWasmSjLj);
1284 LLVMContext &
C =
F.getContext();
1291 for (Instruction &
I :
F.getEntryBlock())
1293 if (AI->isStaticAlloca())
1301 for (AllocaInst *AI : StaticAllocas)
1302 AI->moveBefore(
Entry->getTerminator()->getIterator());
1304 IRB.SetInsertPoint(
Entry->getTerminator()->getIterator());
1309 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1314 Function *SetjmpF =
M.getFunction(
"setjmp");
1322 raw_string_ostream
SS(S);
1323 SS <<
"In function " +
F.getName() +
1324 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1329 CallInst *CI =
nullptr;
1342 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1343 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1355 IRB.SetInsertPoint(CI);
1357 FunctionInvocationId};
1358 IRB.CreateCall(WasmSetjmpF, Args);
1364 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1367 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1370 for (Instruction *
I : ToErase)
1371 I->eraseFromParent();
1390void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1391 Function &
F, Instruction *FunctionInvocationId,
1392 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1394 LLVMContext &
C =
F.getContext();
1402 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1405 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1412 std::vector<BasicBlock *> BBs;
1413 for (BasicBlock &BB :
F)
1417 for (
unsigned I = 0;
I < BBs.size();
I++) {
1419 for (Instruction &
I : *BB) {
1422 raw_string_ostream
SS(S);
1423 SS <<
"In function " <<
F.getName()
1424 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1425 "restriction that `setjmp` function call and exception cannot be "
1426 "used within the same function:\n";
1440 ". Please consider using EM_JS, or move the "
1441 "EM_ASM into another function.",
1444 Value *Threw =
nullptr;
1446 if (
Callee->getName().starts_with(
"__invoke_")) {
1451 LoadInst *ThrewLI =
nullptr;
1452 StoreInst *ThrewResetSI =
nullptr;
1457 if (GV == ThrewGV) {
1458 Threw = ThrewLI = LI;
1468 if (GV == ThrewGV &&
1476 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1477 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1482 Threw = wrapInvoke(CI);
1507 if (supportsException(&
F) &&
canThrow(Callee)) {
1513 if (!RethrowExnBB) {
1515 IRB.SetInsertPoint(RethrowExnBB);
1517 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1518 IRB.CreateCall(ResumeF, {Exn});
1519 IRB.CreateUnreachable();
1522 IRB.SetInsertPoint(CI);
1526 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1528 IRB.SetInsertPoint(NormalBB);
1543 Value *LongjmpResult =
nullptr;
1545 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1546 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1547 CallEmLongjmpBBThrewValuePHI, EndBB);
1548 assert(Label && LongjmpResult && EndBB);
1551 IRB.SetInsertPoint(EndBB);
1553 SwitchInst *
SI = IRB.CreateSwitch(Label,
Tail, SetjmpRetPHIs.
size());
1558 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1559 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1560 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1565 BBs.push_back(
Tail);
1569 for (Instruction *
I : ToErase)
1570 I->eraseFromParent();
1576 return CRI->getUnwindDest();
1585void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1586 Function &
F, Instruction *FunctionInvocationId,
1587 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1589 LLVMContext &
C =
F.getContext();
1596 if (!
F.hasPersonalityFn()) {
1598 FunctionType *PersType =
1599 FunctionType::get(IRB.getInt32Ty(),
true);
1600 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1608 IRB.SetCurrentDebugLocation(FirstDL);
1629 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1630 CatchSwitchInst *CatchSwitchLongjmp =
1635 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1636 IRB.SetInsertPoint(CatchLongjmpBB);
1637 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1646 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1648 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1650 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1652 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1661 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1663 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1664 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1666 IRB.SetInsertPoint(ThenBB);
1667 CallInst *WasmLongjmpCI = IRB.CreateCall(
1669 IRB.CreateUnreachable();
1671 IRB.SetInsertPoint(EndBB);
1673 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1683 IRB.SetInsertPoint(SetjmpDispatchBB);
1684 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1687 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1692 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1693 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1694 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1700 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1701 for (
auto &
I : *BB) {
1711 ". Please consider using EM_JS, or move the "
1712 "EM_ASM into another function.",
1717 if (CI == WasmLongjmpCI)
1723 SmallDenseMap<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4>
1724 UnwindDestToNewPreds;
1725 for (
auto *CI : LongjmpableCalls) {
1731 CalleeF->removeFnAttr(Attribute::NoUnwind);
1740 while (!UnwindDest) {
1742 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1752 Value *ParentPad = CPI->getParentPad();
1760 UnwindDest = CatchDispatchLongjmpBB;
1769 SmallVector<Instruction *, 16> ToErase;
1770 for (
auto &BB :
F) {
1772 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1773 IRB.SetInsertPoint(CSI);
1775 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1776 CatchDispatchLongjmpBB, 1);
1777 NewCSI->addHandler(*CSI->handler_begin());
1778 NewCSI->takeName(CSI);
1779 CSI->replaceAllUsesWith(NewCSI);
1784 if (CRI->unwindsToCaller()) {
1785 IRB.SetInsertPoint(CRI);
1787 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1792 for (Instruction *
I : ToErase)
1793 I->eraseFromParent();
1801 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1802 for (PHINode &PN : UnwindDest->
phis()) {
1803 for (
auto *NewPred : NewPreds) {
1804 assert(PN.getBasicBlockIndex(NewPred) == -1);
1815 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1816 for (PHINode &PN : UnwindDest->
phis()) {
1818 SSA.Initialize(PN.getType(), PN.getName());
1819 for (
unsigned Idx = 0,
E = PN.getNumIncomingValues(); Idx !=
E; ++Idx) {
1820 if (NewPreds.contains(PN.getIncomingBlock(Idx)))
1822 Value *
V = PN.getIncomingValue(Idx);
1824 SSA.AddAvailableValue(
II->getNormalDest(),
II);
1826 SSA.AddAvailableValue(
I->getParent(),
I);
1828 SSA.AddAvailableValue(PN.getIncomingBlock(Idx), V);
1830 for (
auto *NewPred : NewPreds)
1831 PN.setIncomingValueForBlock(NewPred,
SSA.GetValueAtEndOfBlock(NewPred));
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< 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 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)
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 or truncated from a 64-bit value.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
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.
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.
iterator_range< user_iterator > users()
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
const ParentTy * getParent() const
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
A raw_ostream that writes to an std::string.
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.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="", bool Before=false)
Split the specified block at the specified instruction.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
bool isSpace(char C)
Checks whether character C is whitespace in the "C" locale.