LLVM: lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
272#include "llvm/IR/IntrinsicsWebAssembly.h"
279#include
280
281using namespace llvm;
282
283#define DEBUG_TYPE "wasm-lower-em-ehsjlj"
284
287 cl::desc("The list of function names in which Emscripten-style "
288 "exception handling is enabled (see emscripten "
289 "EMSCRIPTEN_CATCHING_ALLOWED options)"),
291
292namespace {
293class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
294 bool EnableEmEH;
295 bool EnableEmSjLj;
296 bool EnableWasmSjLj;
297 bool DoSjLj;
298
299 GlobalVariable *ThrewGV = nullptr;
300 GlobalVariable *ThrewValueGV = nullptr;
301 Function *GetTempRet0F = nullptr;
302 Function *SetTempRet0F = nullptr;
303 Function *ResumeF = nullptr;
304 Function *EHTypeIDF = nullptr;
305 Function *EmLongjmpF = nullptr;
306 Function *WasmSetjmpF = nullptr;
307 Function *WasmSetjmpTestF = nullptr;
308 Function *WasmLongjmpF = nullptr;
309 Function *CatchF = nullptr;
310
311
312 Type *LongjmpArgsTy = nullptr;
313
314
315
317
319
320 std::set<std::string, std::less<>> EHAllowlistSet;
321
323
324 StringRef getPassName() const override {
325 return "WebAssembly Lower Emscripten Exceptions";
326 }
327
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);
334 void
335 handleLongjmpableCallsForWasmSjLj(Function &F,
336 Instruction *FunctionInvocationId,
337 SmallVectorImpl<PHINode *> &SetjmpRetPHIs);
338 Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
339
340 Value *wrapInvoke(CallBase *CI);
341 void wrapTestSetjmp(BasicBlock *BB, DebugLoc DL, Value *Threw,
342 Value *FunctionInvocationId, Value *&Label,
343 Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
344 PHINode *&CallEmLongjmpBBThrewPHI,
345 PHINode *&CallEmLongjmpBBThrewValuePHI,
346 BasicBlock *&EndBB);
347 Function *getInvokeWrapper(CallBase *CI);
348
349 bool areAllExceptionsAllowed() const { return EHAllowlistSet.empty(); }
350 bool supportsException(const Function *F) const {
351 return EnableEmEH &&
352 (areAllExceptionsAllowed() || EHAllowlistSet.count(F->getName()));
353 }
354 void replaceLongjmpWith(Function *LongjmpF, Function *NewF);
355
356 void rebuildSSA(Function &F);
357
358public:
359 static char ID;
360
361 WebAssemblyLowerEmscriptenEHSjLj()
362 : ModulePass(ID), EnableEmEH(WebAssembly::WasmEnableEmEH),
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");
370 }
371 bool runOnModule(Module &M) override;
372
373 void getAnalysisUsage(AnalysisUsage &AU) const override {
374 AU.addRequired();
375 }
376};
377}
378
379char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
381 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
382 false, false)
383
385 return new WebAssemblyLowerEmscriptenEHSjLj();
386}
387
390
391 if (F->isIntrinsic())
392 return false;
394
395 if (Name == "setjmp" || Name == "longjmp" || Name == "emscripten_longjmp")
396 return false;
397 return ->doesNotThrow();
398 }
399
400 return true;
401}
402
403
404
405
408 const char *Name) {
410 if (!GV)
412
413
414
415
416
418 return GV;
419}
420
421
422
423
424
425
427 std::string Sig;
429 OS << *FTy->getReturnType();
430 for (Type *ParamTy : FTy->params())
431 OS << "_" << *ParamTy;
432 if (FTy->isVarArg())
433 OS << "_...";
434 Sig = OS.str();
436
437
439 return Sig;
440}
441
445
447
448
449
450
451 if (->hasFnAttribute("wasm-import-module")) {
452 llvm::AttrBuilder B(F->getParent()->getContext());
453 B.addAttribute("wasm-import-module", "env");
455 }
456 if (->hasFnAttribute("wasm-import-name")) {
457 llvm::AttrBuilder B(F->getParent()->getContext());
458 B.addAttribute("wasm-import-name", F->getName());
460 }
461}
462
463
464
467 return IRB.getIntNTy(M->getDataLayout().getPointerSizeInBits());
468}
469
470
471
472
476
477
478
479
482 return IRB.getIntN(M->getDataLayout().getPointerSizeInBits(), C);
483}
484
485
486
487
488
489
491WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
492 unsigned NumClauses) {
494 if (!Inserted)
495 return It->second;
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);
502 It->second = F;
503 return F;
504}
505
506
507
508
509
510
511
512
513Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
515 LLVMContext &C = M->getContext();
516
518 IRB.SetInsertPoint(CI);
519
520
521
523
524
525 SmallVector<Value *, 16> Args;
526
527
530 CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
532 NewCall->setCallingConv(CallingConv::WASM_EmscriptenInvoke);
534
535
536
538 const AttributeList &InvokeAL = CI->getAttributes();
539
540
541 ArgAttributes.push_back(AttributeSet());
542
543 for (unsigned I = 0, E = CI->arg_size(); I < E; ++I)
544 ArgAttributes.push_back(InvokeAL.getParamAttrs(I));
545
546 AttrBuilder FnAttrs(CI->getContext(), InvokeAL.getFnAttrs());
547 if (auto Args = FnAttrs.getAllocSizeArgs()) {
548
549
550 auto [SizeArg, NEltArg] = *Args;
551 SizeArg += 1;
552 if (NEltArg)
553 NEltArg = *NEltArg + 1;
554 FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
555 }
556
557
558 FnAttrs.removeAttribute(Attribute::NoReturn);
559
560
561 AttributeList NewCallAL = AttributeList::get(
562 C, AttributeSet::get(C, FnAttrs), InvokeAL.getRetAttrs(), ArgAttributes);
564
566
567
568
572 return Threw;
573}
574
575
576Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallBase *CI) {
580
582 auto It = InvokeWrappers.find(Sig);
583 if (It != InvokeWrappers.end())
584 return It->second;
585
586
588
589 ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
590
591 FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
592 CalleeFTy->isVarArg());
595 InvokeWrappers[Sig] = F;
596 return F;
597}
598
601 if (CalleeF->isIntrinsic())
602 return false;
603
604
605
606
607
609 return false;
610 StringRef CalleeName = Callee->getName();
611
612
613
614
615
616 if (CalleeName == "setjmp" || CalleeName == "malloc" || CalleeName == "free")
617 return false;
618
619
620 if (CalleeName == "__resumeException" || CalleeName == "llvm_eh_typeid_for" ||
621 CalleeName == "__wasm_setjmp" || CalleeName == "__wasm_setjmp_test" ||
622 CalleeName == "getTempRet0" || CalleeName == "setTempRet0")
623 return false;
624
625
626 if (Callee->getName().starts_with("__cxa_find_matching_catch_"))
627 return false;
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
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")
666 return false;
667
668
669
670 if (CalleeName == "_ZSt9terminatev")
671 return false;
672
673
674 return true;
675}
676
678 StringRef CalleeName = Callee->getName();
679
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";
685}
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
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);
713
714
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);
725
726
727 if (!CallEmLongjmpBB) {
728
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();
739 } else {
740 CallEmLongjmpBBThrewPHI->addIncoming(Threw, ThenBB1);
741 CallEmLongjmpBBThrewValuePHI->addIncoming(ThrewValue, ThenBB1);
742 }
743
744
745
746 IRB.SetInsertPoint(ThenBB1);
748 Value *ThrewPtr =
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);
754
755
756 IRB.SetInsertPoint(EndBB2);
757 IRB.CreateCall(SetTempRet0F, ThrewValue);
758 IRB.CreateBr(EndBB1);
759
760 IRB.SetInsertPoint(ElseBB1);
761 IRB.CreateBr(EndBB1);
762
763
764 IRB.SetInsertPoint(EndBB1);
765 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label");
766 LabelPHI->addIncoming(ThenLabel, EndBB2);
767
768 LabelPHI->addIncoming(IRB.getInt32(-1), ElseBB1);
769
770
771 Label = LabelPHI;
772 EndBB = EndBB1;
773 LongjmpResult = IRB.CreateCall(GetTempRet0F, {}, "longjmp_result");
774}
775
776void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
777 DominatorTree &DT = getAnalysis(F).getDomTree();
779
780 SSAUpdaterBulk SSA;
781 for (BasicBlock &BB : F) {
782 for (Instruction &I : BB) {
783 if (I.getType()->isVoidTy())
784 continue;
785
787
788
789
790 bool HasNonDominatedLifetimeMarker = any_of(I.users(), [&](User *U) {
791 auto *UserI = cast(U);
792 return UserI->isLifetimeStartOrEnd() && !DT.dominates(&I, UserI);
793 });
794 if (HasNonDominatedLifetimeMarker) {
797 if (UserI->isLifetimeStartOrEnd())
798 UserI->eraseFromParent();
799 }
800 }
801 }
802
803 unsigned VarID = SSA.AddVariable(I.getName(), I.getType());
804
805
807 SSA.AddAvailableValue(VarID, II->getNormalDest(), II);
808 else
809 SSA.AddAvailableValue(VarID, &BB, &I);
810 for (auto &U : I.uses()) {
813 if (UserPN->getIncomingBlock(U) == &BB)
814 continue;
816 continue;
818 }
819 }
820 }
821 SSA.RewriteAllUses(&DT);
822}
823
824
825
826
827
828
829
830
831
832void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(Function *LongjmpF,
833 Function *NewF) {
834 assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
839
840
841
842 for (User *U : LongjmpF->users()) {
845 IRB.SetInsertPoint(CI);
846 Value *Env = nullptr;
847 if (NewF == EmLongjmpF)
848 Env =
850 else
851 Env = IRB.CreateBitCast(CI->getArgOperand(0), IRB.getPtrTy(), "env");
852 IRB.CreateCall(NewF, {Env, CI->getArgOperand(1)});
854 }
855 }
856 for (auto *I : ToErase)
857 I->eraseFromParent();
858
859
860
861 if (!LongjmpF->uses().empty()) {
862 Value *NewLongjmp =
863 IRB.CreateBitCast(NewF, LongjmpF->getType(), "longjmp.cast");
865 }
866}
867
869 for (const auto &BB : *F)
870 for (const auto &I : BB)
872 if (canLongjmp(CB->getCalledOperand()))
873 return true;
874 return false;
875}
876
877
878
879
880
882 Module &M = *F->getParent();
886
891 continue;
893
896 else
900 }
901 for (auto *I : ToErase)
902 I->eraseFromParent();
903}
904
905bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
906 LLVM_DEBUG(dbgs() << "********** Lower Emscripten EH & SjLj **********\n");
907
908 LLVMContext &C = M.getContext();
910
911 Function *SetjmpF = M.getFunction("setjmp");
912 Function *LongjmpF = M.getFunction("longjmp");
913
914
915
916
917 Function *SetjmpF2 = M.getFunction("_setjmp");
918 Function *LongjmpF2 = M.getFunction("_longjmp");
919 if (SetjmpF2) {
920 if (SetjmpF) {
922 report_fatal_error("setjmp and _setjmp have different function types");
923 } else {
926 }
928 }
929 if (LongjmpF2) {
930 if (LongjmpF) {
933 "longjmp and _longjmp have different function types");
934 } else {
937 }
939 }
940
941 auto *TPC = getAnalysisIfAvailable();
942 assert(TPC && "Expected a TargetPassConfig");
943 auto &TM = TPC->getTM();
944
945
946
947
949 ThrewValueGV = getGlobalVariable(M, IRB.getInt32Ty(), TM, "__threwValue");
950 GetTempRet0F = getFunction(FunctionType::get(IRB.getInt32Ty(), false),
951 "getTempRet0", &M);
952 SetTempRet0F =
953 getFunction(FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(), false),
954 "setTempRet0", &M);
957
959
960
961 if (EnableEmEH) {
962
963 FunctionType *ResumeFTy =
964 FunctionType::get(IRB.getVoidTy(), IRB.getPtrTy(), false);
965 ResumeF = getFunction(ResumeFTy, "__resumeException", &M);
966 ResumeF->addFnAttr(Attribute::NoReturn);
967
968
969 FunctionType *EHTypeIDTy =
970 FunctionType::get(IRB.getInt32Ty(), IRB.getPtrTy(), false);
971 EHTypeIDF = getFunction(EHTypeIDTy, "llvm_eh_typeid_for", &M);
972 }
973
974
975
976 SmallPtrSet<Function *, 4> SetjmpUsersToNullify;
977
978 if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
979
980 for (User *U : SetjmpF->users()) {
982 auto *UserF = CB->getFunction();
983
984
985
987 SetjmpUsers.insert(UserF);
988 else
989 SetjmpUsersToNullify.insert(UserF);
990 } else {
991 std::string S;
992 raw_string_ostream SS(S);
994 report_fatal_error(Twine("Indirect use of setjmp is not supported: ") +
995 SS.str());
996 }
997 }
998 }
999
1000 bool SetjmpUsed = SetjmpF && !SetjmpUsers.empty();
1001 bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
1002 DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
1003
1004
1005 if (DoSjLj) {
1006 assert(EnableEmSjLj || EnableWasmSjLj);
1007 if (EnableEmSjLj) {
1008
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);
1013 } else {
1014 Type *Int8PtrTy = IRB.getPtrTy();
1015
1016 FunctionType *FTy = FunctionType::get(
1017 IRB.getVoidTy(), {Int8PtrTy, IRB.getInt32Ty()}, false);
1018 WasmLongjmpF = getFunction(FTy, "__wasm_longjmp", &M);
1019 WasmLongjmpF->addFnAttr(Attribute::NoReturn);
1020 }
1021
1022 if (SetjmpF) {
1023 Type *Int8PtrTy = IRB.getPtrTy();
1024 Type *Int32PtrTy = IRB.getPtrTy();
1026
1027
1029 FunctionType *FTy = FunctionType::get(
1030 IRB.getVoidTy(), {SetjmpFTy->getParamType(0), Int32Ty, Int32PtrTy},
1031 false);
1032 WasmSetjmpF = getFunction(FTy, "__wasm_setjmp", &M);
1033
1034
1035 FTy = FunctionType::get(Int32Ty, {Int32PtrTy, Int32PtrTy}, false);
1036 WasmSetjmpTestF = getFunction(FTy, "__wasm_setjmp_test", &M);
1037
1038
1039
1041
1044 );
1045 }
1046 }
1047
1048
1049 if (EnableEmEH) {
1050 for (Function &F : M) {
1051 if (F.isDeclaration())
1052 continue;
1053 Changed |= runEHOnFunction(F);
1054 }
1055 }
1056
1057
1058 if (DoSjLj) {
1059 Changed = true;
1060 if (LongjmpF)
1061 replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1062
1063
1064 if (SetjmpF)
1065 for (Function *F : SetjmpUsers)
1066 runSjLjOnFunction(*F);
1067 }
1068
1069
1070 if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.empty()) {
1073 for (Function *F : SetjmpUsersToNullify)
1075 }
1076
1077
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();
1085
1087}
1088
1089bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
1091 LLVMContext &C = F.getContext();
1095 SmallPtrSet<LandingPadInst *, 32> LandingPads;
1096
1097
1098 BasicBlock *RethrowLongjmpBB = nullptr;
1099
1100
1101 PHINode *RethrowLongjmpBBThrewPHI = nullptr;
1102
1103 for (BasicBlock &BB : F) {
1105 if ()
1106 continue;
1108 LandingPads.insert(II->getLandingPadInst());
1109 IRB.SetInsertPoint(II);
1110
1112 bool NeedInvoke = supportsException(&F) && canThrow(Callee);
1113 if (NeedInvoke) {
1114
1115 Value *Threw = wrapInvoke(II);
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138 if (DoSjLj && EnableEmSjLj && !SetjmpUsers.count(&F) &&
1140
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();
1151 } else {
1152 RethrowLongjmpBBThrewPHI->addIncoming(Threw, &BB);
1153 }
1154
1155 IRB.SetInsertPoint(II);
1157 Value *CmpEqOne =
1158 IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp.eq.one");
1159 Value *CmpEqZero =
1160 IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 0), "cmp.eq.zero");
1161 Value *Or = IRB.CreateOr(CmpEqZero, CmpEqOne, "or");
1162 IRB.CreateCondBr(Or, Tail, RethrowLongjmpBB);
1163 IRB.SetInsertPoint(Tail);
1164 BB.replaceSuccessorsPhiUsesWith(&BB, Tail);
1165 }
1166
1167
1169 IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
1170
1171 } else {
1172
1173
1175 }
1176 }
1177
1178
1179 for (BasicBlock &BB : F) {
1180
1181 for (Instruction &I : BB) {
1183 if (!RI)
1184 continue;
1186
1187
1188 Value *Input = RI->getValue();
1189 IRB.SetInsertPoint(RI);
1190 Value *Low = IRB.CreateExtractValue(Input, 0, "low");
1191
1192 IRB.CreateCall(ResumeF, {Low});
1193
1194 IRB.CreateUnreachable();
1196 }
1197 }
1198
1199
1200 for (BasicBlock &BB : F) {
1201 for (Instruction &I : BB) {
1203 if (!CI)
1204 continue;
1206 if (!Callee)
1207 continue;
1208 if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1209 continue;
1211
1212 IRB.SetInsertPoint(CI);
1213 CallInst *NewCI =
1214 IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid");
1217 }
1218 }
1219
1220
1221 for (BasicBlock &BB : F) {
1224 LandingPads.insert(LPI);
1225 }
1227
1228
1229
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) {
1234 Constant *Clause = LPI->getClause(I);
1235
1236
1237 if (LPI->isCatch(I))
1239 }
1240
1241
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");
1248
1249 LPI->replaceAllUsesWith(Pair1);
1251 }
1252
1253
1254 for (Instruction *I : ToErase)
1255 I->eraseFromParent();
1256
1258}
1259
1260
1261
1262
1263
1264
1265
1266
1267
1270 assert(InsertBefore);
1276 if (SP)
1277 return DILocation::get(SP->getContext(), SP->getLine(), 1, SP);
1279}
1280
1281bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
1282 assert(EnableEmSjLj || EnableWasmSjLj);
1284 LLVMContext &C = F.getContext();
1287
1288
1289
1291 for (Instruction &I : F.getEntryBlock())
1293 if (AI->isStaticAlloca())
1295
1299
1300
1301 for (AllocaInst *AI : StaticAllocas)
1302 AI->moveBefore(Entry->getTerminator()->getIterator());
1303
1304 IRB.SetInsertPoint(Entry->getTerminator()->getIterator());
1305
1306
1307
1309 IRB.CreateAlloca(IRB.getInt32Ty(), nullptr, "functionInvocationId");
1310 FunctionInvocationId->setDebugLoc(FirstDL);
1311
1312
1314 Function *SetjmpF = M.getFunction("setjmp");
1318 if (BB->getParent() != &F)
1319 continue;
1321 std::string S;
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";
1325 SS << *CB;
1327 }
1328
1329 CallInst *CI = nullptr;
1330
1333 else
1335
1336
1337
1339
1340
1341
1342 IRB.SetInsertPoint(Tail, Tail->getFirstNonPHIIt());
1343 PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2, "setjmp.ret");
1344
1345
1346 SetjmpRet->addIncoming(IRB.getInt32(0), BB);
1347
1349
1350 SetjmpRetPHIs.push_back(SetjmpRet);
1351
1352
1353
1354
1355 IRB.SetInsertPoint(CI);
1357 FunctionInvocationId};
1358 IRB.CreateCall(WasmSetjmpF, Args);
1360 }
1361
1362
1363 if (EnableEmSjLj)
1364 handleLongjmpableCallsForEmscriptenSjLj(F, FunctionInvocationId,
1365 SetjmpRetPHIs);
1366 else
1367 handleLongjmpableCallsForWasmSjLj(F, FunctionInvocationId, SetjmpRetPHIs);
1368
1369
1370 for (Instruction *I : ToErase)
1371 I->eraseFromParent();
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383 rebuildSSA(F);
1384 return true;
1385}
1386
1387
1388
1389
1390void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1391 Function &F, Instruction *FunctionInvocationId,
1392 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1394 LLVMContext &C = F.getContext();
1397
1398
1399 BasicBlock *CallEmLongjmpBB = nullptr;
1400
1401
1402 PHINode *CallEmLongjmpBBThrewPHI = nullptr;
1403
1404
1405 PHINode *CallEmLongjmpBBThrewValuePHI = nullptr;
1406
1408
1409
1410
1411
1412 std::vector<BasicBlock *> BBs;
1413 for (BasicBlock &BB : F)
1414 BBs.push_back(&BB);
1415
1416
1417 for (unsigned I = 0; I < BBs.size(); I++) {
1419 for (Instruction &I : *BB) {
1421 std::string S;
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";
1429 }
1431 if (!CI)
1432 continue;
1433
1436 continue;
1438 report_fatal_error("Cannot use EM_ASM* alongside setjmp/longjmp in " +
1439 F.getName() +
1440 ". Please consider using EM_JS, or move the "
1441 "EM_ASM into another function.",
1442 false);
1443
1444 Value *Threw = nullptr;
1446 if (Callee->getName().starts_with("__invoke_")) {
1447
1448
1449
1450
1451 LoadInst *ThrewLI = nullptr;
1452 StoreInst *ThrewResetSI = nullptr;
1457 if (GV == ThrewGV) {
1458 Threw = ThrewLI = LI;
1459 break;
1460 }
1461 }
1462
1463
1468 if (GV == ThrewGV &&
1470 ThrewResetSI = SI;
1471 break;
1472 }
1473 }
1474 }
1475 }
1476 assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke");
1477 assert(ThrewResetSI && "Cannot find __THREW__ store after invoke");
1479
1480 } else {
1481
1482 Threw = wrapInvoke(CI);
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507 if (supportsException(&F) && canThrow(Callee)) {
1508
1509
1510 ToErase.push_back(BB->getTerminator());
1511
1512
1513 if (!RethrowExnBB) {
1515 IRB.SetInsertPoint(RethrowExnBB);
1516 CallInst *Exn =
1517 IRB.CreateCall(getFindMatchingCatch(M, 0), {}, "exn");
1518 IRB.CreateCall(ResumeF, {Exn});
1519 IRB.CreateUnreachable();
1520 }
1521
1522 IRB.SetInsertPoint(CI);
1524 Value *CmpEqOne =
1525 IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp.eq.one");
1526 IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1527
1528 IRB.SetInsertPoint(NormalBB);
1529 IRB.CreateBr(Tail);
1530 BB = NormalBB;
1531 }
1532 }
1533
1534
1535
1536
1537 ToErase.push_back(BB->getTerminator());
1538
1539
1540
1541
1543 Value *LongjmpResult = nullptr;
1545 wrapTestSetjmp(BB, CI->getDebugLoc(), Threw, FunctionInvocationId, Label,
1546 LongjmpResult, CallEmLongjmpBB, CallEmLongjmpBBThrewPHI,
1547 CallEmLongjmpBBThrewValuePHI, EndBB);
1548 assert(Label && LongjmpResult && EndBB);
1549
1550
1551 IRB.SetInsertPoint(EndBB);
1552 IRB.SetCurrentDebugLocation(EndBB->back().getDebugLoc());
1553 SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size());
1554
1555
1556
1557
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);
1561 }
1562
1563
1564
1565 BBs.push_back(Tail);
1566 }
1567 }
1568
1569 for (Instruction *I : ToErase)
1570 I->eraseFromParent();
1571}
1572
1574 for (const User *U : CPI->users())
1576 return CRI->getUnwindDest();
1577 return nullptr;
1578}
1579
1580
1581
1582
1583
1584
1585void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1586 Function &F, Instruction *FunctionInvocationId,
1587 SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1589 LLVMContext &C = F.getContext();
1591
1592
1593
1594
1595
1596 if (.hasPersonalityFn()) {
1598 FunctionType *PersType =
1599 FunctionType::get(IRB.getInt32Ty(), true);
1600 Value *PersF = M.getOrInsertFunction(PersName, PersType).getCallee();
1601 F.setPersonalityFn(
1602 cast(IRB.CreateBitCast(PersF, IRB.getPtrTy())));
1603 }
1604
1605
1608 IRB.SetCurrentDebugLocation(FirstDL);
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1625
1626
1627 BasicBlock *CatchDispatchLongjmpBB =
1629 IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1630 CatchSwitchInst *CatchSwitchLongjmp =
1632
1633
1635 CatchSwitchLongjmp->addHandler(CatchLongjmpBB);
1636 IRB.SetInsertPoint(CatchLongjmpBB);
1637 CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1638
1639
1640
1641
1642
1645 Value *EnvField =
1646 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0, "env_gep");
1647 Value *ValField =
1648 IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1, "val_gep");
1649
1650 Instruction *Env = IRB.CreateLoad(IRB.getPtrTy(), EnvField, "env");
1651
1652 Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField, "val");
1653
1654
1655
1656
1657
1661 Value *Label = IRB.CreateCall(WasmSetjmpTestF, {EnvP, FunctionInvocationId},
1663 Value *Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1664 IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1665
1666 IRB.SetInsertPoint(ThenBB);
1667 CallInst *WasmLongjmpCI = IRB.CreateCall(
1668 WasmLongjmpF, {Env, Val}, OperandBundleDef("funclet", CatchPad));
1669 IRB.CreateUnreachable();
1670
1671 IRB.SetInsertPoint(EndBB);
1672
1673 IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683 IRB.SetInsertPoint(SetjmpDispatchBB);
1684 PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label.phi");
1686 LabelPHI->addIncoming(IRB.getInt32(-1), Entry);
1687 SwitchInst *SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.size());
1688
1689
1690
1691
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);
1695 }
1696
1697
1698
1700 for (auto *BB = &*F.begin(); BB; BB = BB->getNextNode()) {
1701 for (auto &I : *BB) {
1703 if (!CI)
1704 continue;
1707 continue;
1709 report_fatal_error("Cannot use EM_ASM* alongside setjmp/longjmp in " +
1710 F.getName() +
1711 ". Please consider using EM_JS, or move the "
1712 "EM_ASM into another function.",
1713 false);
1714
1715
1716
1717 if (CI == WasmLongjmpCI)
1718 continue;
1720 }
1721 }
1722
1723 SmallDenseMap<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4>
1724 UnwindDestToNewPreds;
1725 for (auto *CI : LongjmpableCalls) {
1726
1727
1728
1731 CalleeF->removeFnAttr(Attribute::NoUnwind);
1732
1733
1734
1735
1736
1740 while (!UnwindDest) {
1742 UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1743 break;
1744 }
1746
1747
1748
1749
1750
1752 Value *ParentPad = CPI->getParentPad();
1754 break;
1756 }
1757 }
1758 }
1759 if (!UnwindDest)
1760 UnwindDest = CatchDispatchLongjmpBB;
1761
1762
1763
1764
1765 UnwindDestToNewPreds[UnwindDest].insert(CI->getParent());
1767 }
1768
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);
1780 }
1781 }
1782
1784 if (CRI->unwindsToCaller()) {
1785 IRB.SetInsertPoint(CRI);
1787 IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1788 }
1789 }
1790 }
1791
1792 for (Instruction *I : ToErase)
1793 I->eraseFromParent();
1794
1795
1796
1797
1798
1799
1800
1801 for (auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1802 for (PHINode &PN : UnwindDest->phis()) {
1803 for (auto *NewPred : NewPreds) {
1804 assert(PN.getBasicBlockIndex(NewPred) == -1);
1806 }
1807 }
1808 }
1809
1810
1811
1812
1813
1814
1815 for (auto &[UnwindDest, NewPreds] : UnwindDestToNewPreds) {
1816 for (PHINode &PN : UnwindDest->phis()) {
1817 SSAUpdater SSA;
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)))
1821 continue;
1822 Value *V = PN.getIncomingValue(Idx);
1824 SSA.AddAvailableValue(II->getNormalDest(), II);
1826 SSA.AddAvailableValue(I->getParent(), I);
1827 else
1828 SSA.AddAvailableValue(PN.getIncomingBlock(Idx), V);
1829 }
1830 for (auto *NewPred : NewPreds)
1831 PN.setIncomingValueForBlock(NewPred, SSA.GetValueAtEndOfBlock(NewPred));
1832 assert(PN.isComplete());
1833 }
1834 }
1835}
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)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:881
static void markAsImported(Function *F)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:446
static bool canLongjmp(const Value *Callee)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:599
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)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:473
static std::string getSignature(FunctionType *FTy)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:426
static Type * getAddrIntType(Module *M)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:465
static bool canThrow(const Value *V)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:388
static Function * getFunction(FunctionType *Ty, const Twine &Name, Module *M)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:442
static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore, DISubprogram *SP)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:1268
static bool containsLongjmpableCalls(const Function *F)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:868
static Value * getAddrSizeInt(Module *M, uint64_t C)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:480
static GlobalVariable * getGlobalVariable(Module &M, Type *Ty, WebAssemblyTargetMachine &TM, const char *Name)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:406
static bool isEmAsmCall(const Value *Callee)
Definition WebAssemblyLowerEmscriptenEHSjLj.cpp:677
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 - 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 - 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 - 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.