273#include "llvm/IR/IntrinsicsWebAssembly.h"
284#define DEBUG_TYPE "wasm-lower-em-ehsjlj"
288 cl::desc(
"The list of function names in which Emscripten-style "
289 "exception handling is enabled (see emscripten "
290 "EMSCRIPTEN_CATCHING_ALLOWED options)"),
294class WebAssemblyLowerEmscriptenEHSjLj final :
public ModulePass {
308 Function *WasmSetjmpTestF =
nullptr;
313 Type *LongjmpArgsTy =
nullptr;
321 std::set<std::string, std::less<>> EHAllowlistSet;
326 return "WebAssembly Lower Emscripten Exceptions";
329 using InstVector = SmallVectorImpl<Instruction *>;
330 bool runEHOnFunction(Function &
F);
331 bool runSjLjOnFunction(Function &
F);
332 void handleLongjmpableCallsForEmscriptenSjLj(
333 Function &
F, Instruction *FunctionInvocationId,
334 SmallVectorImpl<PHINode *> &SetjmpRetPHIs);
336 handleLongjmpableCallsForWasmSjLj(Function &
F,
337 Instruction *FunctionInvocationId,
338 SmallVectorImpl<PHINode *> &SetjmpRetPHIs);
341 Value *wrapInvoke(CallBase *CI);
344 Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
345 PHINode *&CallEmLongjmpBBThrewPHI,
346 PHINode *&CallEmLongjmpBBThrewValuePHI,
348 Function *getInvokeWrapper(CallBase *CI);
350 bool areAllExceptionsAllowed()
const {
return EHAllowlistSet.empty(); }
351 bool supportsException(
const Function *
F)
const {
353 (areAllExceptionsAllowed() || EHAllowlistSet.count(
F->getName()));
355 void replaceLongjmpWith(Function *LongjmpF, Function *NewF);
357 void rebuildSSA(Function &
F);
362 WebAssemblyLowerEmscriptenEHSjLj()
366 assert(!(EnableEmSjLj && EnableWasmSjLj) &&
367 "Two SjLj modes cannot be turned on at the same time");
368 assert(!(EnableEmEH && EnableWasmSjLj) &&
369 "Wasm SjLj should be only used with Wasm EH");
372 bool runOnModule(
Module &M)
override;
374 void getAnalysisUsage(AnalysisUsage &AU)
const override {
380char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
382 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
386 return new WebAssemblyLowerEmscriptenEHSjLj();
392 if (
F->isIntrinsic())
396 if (Name ==
"setjmp" || Name ==
"longjmp" || Name ==
"emscripten_longjmp")
398 return !
F->doesNotThrow();
430 OS << *FTy->getReturnType();
431 for (
Type *ParamTy : FTy->params())
432 OS <<
"_" << *ParamTy;
452 if (!
F->hasFnAttribute(
"wasm-import-module")) {
453 llvm::AttrBuilder
B(
F->getParent()->getContext());
454 B.addAttribute(
"wasm-import-module",
"env");
457 if (!
F->hasFnAttribute(
"wasm-import-name")) {
458 llvm::AttrBuilder
B(
F->getParent()->getContext());
459 B.addAttribute(
"wasm-import-name",
F->getName());
468 return IRB.
getIntNTy(M->getDataLayout().getPointerSizeInBits());
483 return IRB.
getIntN(M->getDataLayout().getPointerSizeInBits(),
C);
489 Attribute FeaturesAttr =
F.getFnAttribute(
"target-features");
490 return FeaturesAttr.
isValid() &&
500WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(
Module &M,
501 unsigned NumClauses) {
505 PointerType *Int8PtrTy = PointerType::getUnqual(
M.getContext());
507 FunctionType *FTy = FunctionType::get(Int8PtrTy, Args,
false);
509 FTy,
"__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
522Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
524 LLVMContext &
C =
M->getContext();
527 IRB.SetInsertPoint(CI);
534 SmallVector<Value *, 16>
Args;
539 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
553 ArgAttributes.
push_back(InvokeAL.getParamAttrs(
I));
555 AttrBuilder FnAttrs(CI->
getContext(), InvokeAL.getFnAttrs());
556 if (
auto Args = FnAttrs.getAllocSizeArgs()) {
559 auto [SizeArg, NEltArg] = *
Args;
562 NEltArg = *NEltArg + 1;
563 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
567 FnAttrs.removeAttribute(Attribute::NoReturn);
570 AttributeList NewCallAL = AttributeList::get(
585Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallBase *CI) {
591 auto It = InvokeWrappers.
find(Sig);
592 if (It != InvokeWrappers.
end())
598 ArgTys.
append(CalleeFTy->param_begin(), CalleeFTy->param_end());
600 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
601 CalleeFTy->isVarArg());
604 InvokeWrappers[Sig] =
F;
610 if (CalleeF->isIntrinsic())
619 StringRef CalleeName = Callee->getName();
625 if (CalleeName ==
"setjmp" || CalleeName ==
"malloc" || CalleeName ==
"free")
629 if (CalleeName ==
"__resumeException" || CalleeName ==
"llvm_eh_typeid_for" ||
630 CalleeName ==
"__wasm_setjmp" || CalleeName ==
"__wasm_setjmp_test" ||
631 CalleeName ==
"getTempRet0" || CalleeName ==
"setTempRet0")
635 if (Callee->getName().starts_with(
"__cxa_find_matching_catch_"))
670 if (CalleeName ==
"__cxa_end_catch")
672 if (CalleeName ==
"__cxa_begin_catch" ||
673 CalleeName ==
"__cxa_allocate_exception" || CalleeName ==
"__cxa_throw" ||
674 CalleeName ==
"__clang_call_terminate")
679 if (CalleeName ==
"_ZSt9terminatev")
687 StringRef CalleeName = Callee->getName();
689 return CalleeName ==
"emscripten_asm_const_int" ||
690 CalleeName ==
"emscripten_asm_const_double" ||
691 CalleeName ==
"emscripten_asm_const_int_sync_on_main_thread" ||
692 CalleeName ==
"emscripten_asm_const_double_sync_on_main_thread" ||
693 CalleeName ==
"emscripten_asm_const_async_on_main_thread";
712void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
714 Value *&Label,
Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
715 PHINode *&CallEmLongjmpBBThrewPHI, PHINode *&CallEmLongjmpBBThrewValuePHI,
716 BasicBlock *&EndBB) {
719 LLVMContext &
C =
M->getContext();
721 IRB.SetCurrentDebugLocation(
DL);
724 IRB.SetInsertPoint(BB);
729 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
730 ThrewValueGV->
getName() +
".val");
731 Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
732 Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp,
"cmp1");
733 IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
736 if (!CallEmLongjmpBB) {
739 IRB.SetInsertPoint(CallEmLongjmpBB);
740 CallEmLongjmpBBThrewPHI = IRB.CreatePHI(
getAddrIntType(M), 4,
"threw.phi");
741 CallEmLongjmpBBThrewValuePHI =
742 IRB.CreatePHI(IRB.getInt32Ty(), 4,
"threwvalue.phi");
743 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
744 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
745 IRB.CreateCall(EmLongjmpF,
746 {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
747 IRB.CreateUnreachable();
749 CallEmLongjmpBBThrewPHI->
addIncoming(Threw, ThenBB1);
750 CallEmLongjmpBBThrewValuePHI->
addIncoming(ThrewValue, ThenBB1);
755 IRB.SetInsertPoint(ThenBB1);
759 Value *ThenLabel = IRB.CreateCall(WasmSetjmpTestF,
760 {ThrewPtr, FunctionInvocationId},
"label");
761 Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
762 IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
765 IRB.SetInsertPoint(EndBB2);
766 IRB.CreateCall(SetTempRet0F, ThrewValue);
767 IRB.CreateBr(EndBB1);
769 IRB.SetInsertPoint(ElseBB1);
770 IRB.CreateBr(EndBB1);
773 IRB.SetInsertPoint(EndBB1);
774 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label");
782 LongjmpResult = IRB.CreateCall(GetTempRet0F, {},
"longjmp_result");
785void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &
F) {
786 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
790 for (BasicBlock &BB :
F) {
791 for (Instruction &
I : BB) {
792 if (
I.getType()->isVoidTy())
799 bool HasNonDominatedLifetimeMarker =
any_of(
I.users(), [&](User *U) {
800 auto *UserI = cast<Instruction>(U);
801 return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
803 if (HasNonDominatedLifetimeMarker) {
806 if (UserI->isLifetimeStartOrEnd())
807 UserI->eraseFromParent();
812 unsigned VarID =
SSA.AddVariable(
I.getName(),
I.getType());
819 for (
auto &U :
I.uses()) {
822 if (UserPN->getIncomingBlock(U) == &BB)
830 SSA.RewriteAllUses(&DT);
841void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(Function *LongjmpF,
843 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
851 for (User *U : LongjmpF->
users()) {
854 IRB.SetInsertPoint(CI);
855 Value *Env =
nullptr;
856 if (NewF == EmLongjmpF)
860 Env = IRB.CreateBitCast(CI->
getArgOperand(0), IRB.getPtrTy(),
"env");
865 for (
auto *
I : ToErase)
866 I->eraseFromParent();
870 if (!LongjmpF->
uses().empty()) {
872 IRB.CreateBitCast(NewF, LongjmpF->
getType(),
"longjmp.cast");
878 for (
const auto &BB : *
F)
879 for (
const auto &
I : BB)
910 for (
auto *
I : ToErase)
911 I->eraseFromParent();
914bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(
Module &M) {
915 LLVM_DEBUG(
dbgs() <<
"********** Lower Emscripten EH & SjLj **********\n");
917 LLVMContext &
C =
M.getContext();
920 Function *SetjmpF =
M.getFunction(
"setjmp");
921 Function *LongjmpF =
M.getFunction(
"longjmp");
926 Function *SetjmpF2 =
M.getFunction(
"_setjmp");
927 Function *LongjmpF2 =
M.getFunction(
"_longjmp");
942 "longjmp and _longjmp have different function types");
950 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
951 assert(TPC &&
"Expected a TargetPassConfig");
952 auto &TM = TPC->getTM<WebAssemblyTargetMachine>();
959 GetTempRet0F =
getFunction(FunctionType::get(IRB.getInt32Ty(),
false),
962 getFunction(FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(),
false),
972 FunctionType *ResumeFTy =
973 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(),
false);
974 ResumeF =
getFunction(ResumeFTy,
"__resumeException", &M);
978 FunctionType *EHTypeIDTy =
979 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(),
false);
980 EHTypeIDF =
getFunction(EHTypeIDTy,
"llvm_eh_typeid_for", &M);
985 SmallPtrSet<Function *, 4> SetjmpUsersToNullify;
987 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
989 for (User *U : SetjmpF->
users()) {
991 auto *UserF = CB->getFunction();
996 SetjmpUsers.
insert(UserF);
998 SetjmpUsersToNullify.
insert(UserF);
1001 raw_string_ostream
SS(S);
1009 bool SetjmpUsed = SetjmpF && !SetjmpUsers.
empty();
1010 bool LongjmpUsed = LongjmpF && !LongjmpF->
use_empty();
1011 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
1015 assert(EnableEmSjLj || EnableWasmSjLj);
1019 FunctionType *FTy = FunctionType::get(
1020 IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()},
false);
1021 EmLongjmpF =
getFunction(FTy,
"emscripten_longjmp", &M);
1022 EmLongjmpF->
addFnAttr(Attribute::NoReturn);
1024 Type *Int8PtrTy = IRB.getPtrTy();
1026 FunctionType *FTy = FunctionType::get(
1027 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()},
false);
1028 WasmLongjmpF =
getFunction(FTy,
"__wasm_longjmp", &M);
1029 WasmLongjmpF->
addFnAttr(Attribute::NoReturn);
1032 if (EnableWasmSjLj) {
1033 for (
auto *SjLjF : {SetjmpF, LongjmpF}) {
1035 for (User *U : SjLjF->users()) {
1040 " is using setjmp/longjmp but does not have "
1041 "+exception-handling target feature");
1049 Type *Int8PtrTy = IRB.getPtrTy();
1050 Type *Int32PtrTy = IRB.getPtrTy();
1055 FunctionType *FTy = FunctionType::get(
1056 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1058 WasmSetjmpF =
getFunction(FTy,
"__wasm_setjmp", &M);
1061 FTy = FunctionType::get(Int32Ty, {Int32PtrTy, Int32PtrTy},
false);
1062 WasmSetjmpTestF =
getFunction(FTy,
"__wasm_setjmp_test", &M);
1076 for (Function &
F : M) {
1077 if (
F.isDeclaration())
1087 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1091 for (Function *
F : SetjmpUsers)
1092 runSjLjOnFunction(*
F);
1096 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.
empty()) {
1099 for (Function *
F : SetjmpUsersToNullify)
1104 for (
auto *V : {ThrewGV, ThrewValueGV})
1105 if (V &&
V->use_empty())
1106 V->eraseFromParent();
1107 for (
auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1108 WasmSetjmpF, WasmSetjmpTestF, WasmLongjmpF, CatchF})
1109 if (V &&
V->use_empty())
1110 V->eraseFromParent();
1115bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &
F) {
1117 LLVMContext &
C =
F.getContext();
1121 SmallPtrSet<LandingPadInst *, 32> LandingPads;
1127 PHINode *RethrowLongjmpBBThrewPHI =
nullptr;
1129 for (BasicBlock &BB :
F) {
1134 LandingPads.
insert(
II->getLandingPadInst());
1135 IRB.SetInsertPoint(
II);
1138 bool NeedInvoke = supportsException(&
F) &&
canThrow(Callee);
1141 Value *Threw = wrapInvoke(
II);
1164 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.
count(&
F) &&
1167 if (!RethrowLongjmpBB) {
1169 IRB.SetInsertPoint(RethrowLongjmpBB);
1170 RethrowLongjmpBBThrewPHI =
1172 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1173 Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1174 ThrewValueGV->
getName() +
".val");
1175 IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1176 IRB.CreateUnreachable();
1178 RethrowLongjmpBBThrewPHI->
addIncoming(Threw, &BB);
1181 IRB.SetInsertPoint(
II);
1187 Value *
Or = IRB.CreateOr(CmpEqZero, CmpEqOne,
"or");
1188 IRB.CreateCondBr(
Or,
Tail, RethrowLongjmpBB);
1189 IRB.SetInsertPoint(
Tail);
1190 BB.replaceSuccessorsPhiUsesWith(&BB,
Tail);
1195 IRB.CreateCondBr(Cmp,
II->getUnwindDest(),
II->getNormalDest());
1205 for (BasicBlock &BB :
F) {
1207 for (Instruction &
I : BB) {
1214 Value *Input = RI->getValue();
1215 IRB.SetInsertPoint(RI);
1216 Value *
Low = IRB.CreateExtractValue(Input, 0,
"low");
1218 IRB.CreateCall(ResumeF, {
Low});
1220 IRB.CreateUnreachable();
1226 for (BasicBlock &BB :
F) {
1227 for (Instruction &
I : BB) {
1234 if (
Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1238 IRB.SetInsertPoint(CI);
1247 for (BasicBlock &BB :
F) {
1256 for (LandingPadInst *LPI : LandingPads) {
1257 IRB.SetInsertPoint(LPI);
1258 SmallVector<Value *, 16> FMCArgs;
1259 for (
unsigned I = 0,
E = LPI->getNumClauses();
I <
E; ++
I) {
1263 if (LPI->isCatch(
I))
1268 Function *FMCF = getFindMatchingCatch(M, FMCArgs.
size());
1269 CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs,
"fmc");
1271 Value *Pair0 = IRB.CreateInsertValue(
Poison, FMCI, 0,
"pair0");
1272 Value *TempRet0 = IRB.CreateCall(GetTempRet0F, {},
"tempret0");
1273 Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1,
"pair1");
1275 LPI->replaceAllUsesWith(Pair1);
1280 for (Instruction *
I : ToErase)
1281 I->eraseFromParent();
1307bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &
F) {
1308 assert(EnableEmSjLj || EnableWasmSjLj);
1310 LLVMContext &
C =
F.getContext();
1316 SmallVector<AllocaInst *> StaticAllocas;
1317 for (Instruction &
I :
F.getEntryBlock())
1319 if (AI->isStaticAlloca())
1327 for (AllocaInst *AI : StaticAllocas)
1328 AI->moveBefore(
Entry->getTerminator()->getIterator());
1330 IRB.SetInsertPoint(
Entry->getTerminator()->getIterator());
1335 IRB.CreateAlloca(IRB.getInt32Ty(),
nullptr,
"functionInvocationId");
1340 Function *SetjmpF =
M.getFunction(
"setjmp");
1348 raw_string_ostream
SS(S);
1349 SS <<
"In function " +
F.getName() +
1350 ": setjmp within a catch clause is not supported in Wasm EH:\n";
1355 CallInst *CI =
nullptr;
1368 IRB.SetInsertPoint(
Tail,
Tail->getFirstNonPHIIt());
1369 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"setjmp.ret");
1381 IRB.SetInsertPoint(CI);
1383 FunctionInvocationId};
1384 IRB.CreateCall(WasmSetjmpF, Args);
1390 handleLongjmpableCallsForEmscriptenSjLj(
F, FunctionInvocationId,
1393 handleLongjmpableCallsForWasmSjLj(
F, FunctionInvocationId, SetjmpRetPHIs);
1396 for (Instruction *
I : ToErase)
1397 I->eraseFromParent();
1416void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1417 Function &
F, Instruction *FunctionInvocationId,
1418 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1420 LLVMContext &
C =
F.getContext();
1428 PHINode *CallEmLongjmpBBThrewPHI =
nullptr;
1431 PHINode *CallEmLongjmpBBThrewValuePHI =
nullptr;
1438 std::vector<BasicBlock *> BBs;
1439 for (BasicBlock &BB :
F)
1443 for (
unsigned I = 0;
I < BBs.size();
I++) {
1445 for (Instruction &
I : *BB) {
1448 raw_string_ostream
SS(S);
1449 SS <<
"In function " <<
F.getName()
1450 <<
": When using Wasm EH with Emscripten SjLj, there is a "
1451 "restriction that `setjmp` function call and exception cannot be "
1452 "used within the same function:\n";
1466 ". Please consider using EM_JS, or move the "
1467 "EM_ASM into another function.",
1470 Value *Threw =
nullptr;
1472 if (
Callee->getName().starts_with(
"__invoke_")) {
1477 LoadInst *ThrewLI =
nullptr;
1478 StoreInst *ThrewResetSI =
nullptr;
1483 if (GV == ThrewGV) {
1484 Threw = ThrewLI = LI;
1494 if (GV == ThrewGV &&
1502 assert(Threw && ThrewLI &&
"Cannot find __THREW__ load after invoke");
1503 assert(ThrewResetSI &&
"Cannot find __THREW__ store after invoke");
1508 Threw = wrapInvoke(CI);
1533 if (supportsException(&
F) &&
canThrow(Callee)) {
1539 if (!RethrowExnBB) {
1541 IRB.SetInsertPoint(RethrowExnBB);
1543 IRB.CreateCall(getFindMatchingCatch(M, 0), {},
"exn");
1544 IRB.CreateCall(ResumeF, {Exn});
1545 IRB.CreateUnreachable();
1548 IRB.SetInsertPoint(CI);
1552 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1554 IRB.SetInsertPoint(NormalBB);
1569 Value *LongjmpResult =
nullptr;
1571 wrapTestSetjmp(BB, CI->
getDebugLoc(), Threw, FunctionInvocationId, Label,
1572 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1573 CallEmLongjmpBBThrewValuePHI, EndBB);
1574 assert(Label && LongjmpResult && EndBB);
1577 IRB.SetInsertPoint(EndBB);
1579 SwitchInst *
SI = IRB.CreateSwitch(Label,
Tail, SetjmpRetPHIs.
size());
1584 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1585 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1586 SetjmpRetPHIs[
I]->addIncoming(LongjmpResult, EndBB);
1591 BBs.push_back(
Tail);
1595 for (Instruction *
I : ToErase)
1596 I->eraseFromParent();
1602 return CRI->getUnwindDest();
1611void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1612 Function &
F, Instruction *FunctionInvocationId,
1613 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1615 LLVMContext &
C =
F.getContext();
1622 if (!
F.hasPersonalityFn()) {
1624 FunctionType *PersType =
1625 FunctionType::get(IRB.getInt32Ty(),
true);
1626 Value *PersF =
M.getOrInsertFunction(PersName, PersType).getCallee();
1634 IRB.SetCurrentDebugLocation(FirstDL);
1655 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1656 CatchSwitchInst *CatchSwitchLongjmp =
1661 CatchSwitchLongjmp->
addHandler(CatchLongjmpBB);
1662 IRB.SetInsertPoint(CatchLongjmpBB);
1663 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1672 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0,
"env_gep");
1674 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1,
"val_gep");
1676 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField,
"env");
1678 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField,
"val");
1687 Value *
Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1689 Value *
Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1690 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1692 IRB.SetInsertPoint(ThenBB);
1693 CallInst *WasmLongjmpCI = IRB.CreateCall(
1695 IRB.CreateUnreachable();
1697 IRB.SetInsertPoint(EndBB);
1699 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1709 IRB.SetInsertPoint(SetjmpDispatchBB);
1710 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2,
"label.phi");
1713 SwitchInst *
SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.
size());
1718 for (
unsigned I = 0;
I < SetjmpRetPHIs.
size();
I++) {
1719 SI->addCase(IRB.getInt32(
I + 1), SetjmpRetPHIs[
I]->getParent());
1720 SetjmpRetPHIs[
I]->addIncoming(Val, SetjmpDispatchBB);
1726 for (
auto *BB = &*
F.begin(); BB; BB = BB->getNextNode()) {
1727 for (
auto &
I : *BB) {
1737 ". Please consider using EM_JS, or move the "
1738 "EM_ASM into another function.",
1743 if (CI == WasmLongjmpCI)
1749 SmallMapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4>
1750 UnwindDestToNewPreds;
1751 for (
auto *CI : LongjmpableCalls) {
1757 CalleeF->removeFnAttr(Attribute::NoUnwind);
1766 while (!UnwindDest) {
1768 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1778 Value *ParentPad = CPI->getParentPad();
1786 UnwindDest = CatchDispatchLongjmpBB;
1795 SmallVector<Instruction *, 16> ToErase;
1796 for (
auto &BB :
F) {
1798 if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1799 IRB.SetInsertPoint(CSI);
1801 auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1802 CatchDispatchLongjmpBB, 1);
1803 NewCSI->addHandler(*CSI->handler_begin());
1804 NewCSI->takeName(CSI);
1805 CSI->replaceAllUsesWith(NewCSI);
1810 if (CRI->unwindsToCaller()) {
1811 IRB.SetInsertPoint(CRI);
1813 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1818 for (Instruction *
I : ToErase)
1819 I->eraseFromParent();
1827 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1828 for (PHINode &PN : UnwindDest->
phis()) {
1829 for (
auto *NewPred : NewPreds) {
1830 assert(PN.getBasicBlockIndex(NewPred) == -1);
1841 for (
auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1842 for (PHINode &PN : UnwindDest->
phis()) {
1844 SSA.Initialize(PN.getType(), PN.getName());
1845 for (
unsigned Idx = 0,
E = PN.getNumIncomingValues(); Idx !=
E; ++Idx) {
1846 if (NewPreds.contains(PN.getIncomingBlock(Idx)))
1848 Value *
V = PN.getIncomingValue(Idx);
1850 SSA.AddAvailableValue(
II->getNormalDest(),
II);
1852 SSA.AddAvailableValue(
I->getParent(),
I);
1854 SSA.AddAvailableValue(PN.getIncomingBlock(Idx), V);
1856 for (
auto *NewPred : NewPreds)
1857 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
This file implements a map that provides insertion order iteration.
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)
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)
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.
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)
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.
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 * > OverloadTys={})
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.
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...
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...
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.