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 F->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 (F->hasFnAttribute("wasm-import-module")) {

452 llvm::AttrBuilder B(F->getParent()->getContext());

453 B.addAttribute("wasm-import-module", "env");

454 F->addFnAttrs(B);

455 }

456 if (F->hasFnAttribute("wasm-import-name")) {

457 llvm::AttrBuilder B(F->getParent()->getContext());

458 B.addAttribute("wasm-import-name", F->getName());

459 F->addFnAttrs(B);

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

890 if (BB->getParent() != F)

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);

993 SS << *U;

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 (II)

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";

1427 SS << I;

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;

1454 I != IE; ++I) {

1457 if (GV == ThrewGV) {

1458 Threw = ThrewLI = LI;

1459 break;

1460 }

1461 }

1462

1463

1465 I != IE; ++I) {

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 (F.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.