LLVM: lib/Transforms/IPO/WholeProgramDevirt.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

97#include

98#include

99#include

100#include

101#include

102

103using namespace llvm;

104using namespace wholeprogramdevirt;

105

106#define DEBUG_TYPE "wholeprogramdevirt"

107

108STATISTIC(NumDevirtTargets, "Number of whole program devirtualization targets");

109STATISTIC(NumSingleImpl, "Number of single implementation devirtualizations");

110STATISTIC(NumBranchFunnel, "Number of branch funnels");

111STATISTIC(NumUniformRetVal, "Number of uniform return value optimizations");

112STATISTIC(NumUniqueRetVal, "Number of unique return value optimizations");

114 "Number of 1 bit virtual constant propagations");

115STATISTIC(NumVirtConstProp, "Number of virtual constant propagations");

116

118 "wholeprogramdevirt-summary-action",

119 cl::desc("What to do with the summary when running this pass"),

121 clEnumValN(PassSummaryAction::Import, "import",

122 "Import typeid resolutions from summary and globals"),

123 clEnumValN(PassSummaryAction::Export, "export",

124 "Export typeid resolutions to summary and globals")),

126

128 "wholeprogramdevirt-read-summary",

130 "Read summary from given bitcode or YAML file before running pass"),

132

134 "wholeprogramdevirt-write-summary",

135 cl::desc("Write summary to given bitcode or YAML file after running pass. "

136 "Output file format is deduced from extension: *.bc means writing "

137 "bitcode, otherwise YAML"),

139

143 cl::desc("Maximum number of call targets per "

144 "call site to enable branch funnels"));

145

148 cl::desc("Print index-based devirtualization messages"));

149

150

151

152

153

156 cl::desc("Enable whole program visibility"));

157

158

159

161 "disable-whole-program-visibility", cl::Hidden,

162 cl::desc("Disable whole program visibility (overrides enabling options)"));

163

164

167 cl::desc("Prevent function(s) from being devirtualized"),

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

188 "wholeprogramdevirt-keep-unreachable-function",

189 cl::desc("Regard unreachable functions as possible devirtualize targets."),

191

192

193

194

196 "wholeprogramdevirt-cutoff",

197 cl::desc("Max number of devirtualizations for devirt module pass"),

199

200

201

202

203

204

207 "wholeprogramdevirt-check", cl::Hidden,

208 cl::desc("Type of checking for incorrect devirtualizations"),

212 "Fallback to indirect when incorrect")));

213

214namespace {

215struct PatternList {

216 std::vector Patterns;

217 template void init(const T &StringList) {

218 for (const auto &S : StringList)

220 Patterns.push_back(std::move(*Pat));

221 }

224 if (P.match(S))

225 return true;

226 return false;

227 }

228};

229}

230

231

232

233

237

240 if (IsAfter)

241 MinByte = std::max(MinByte, Target.minAfterBytes());

242 else

243 MinByte = std::max(MinByte, Target.minBeforeBytes());

244 }

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266 std::vector<ArrayRef<uint8_t>> Used;

269 : Target.TM->Bits->Before.BytesUsed;

271 : MinByte - Target.minBeforeBytes();

272

273

274

277 }

278

279 if (Size == 1) {

280

281 for (unsigned I = 0;; ++I) {

283 for (auto &&B : Used)

284 if (I < B.size())

285 BitsUsed |= B[I];

286 if (BitsUsed != 0xff)

288 }

289 } else {

290

291

292 for (unsigned I = 0;; ++I) {

293 for (auto &&B : Used) {

294 unsigned Byte = 0;

295 while ((I + Byte) < B.size() && Byte < (Size / 8)) {

296 if (B[I + Byte])

297 goto NextI;

298 ++Byte;

299 }

300 }

301 return (MinByte + I) * 8;

302 NextI:;

303 }

304 }

305}

306

309 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {

311 OffsetByte = -(AllocBefore / 8 + 1);

312 else

313 OffsetByte = -((AllocBefore + 7) / 8 + (BitWidth + 7) / 8);

314 OffsetBit = AllocBefore % 8;

315

318 Target.setBeforeBit(AllocBefore);

319 else

320 Target.setBeforeBytes(AllocBefore, (BitWidth + 7) / 8);

321 }

322}

323

326 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {

328 OffsetByte = AllocAfter / 8;

329 else

330 OffsetByte = (AllocAfter + 7) / 8;

331 OffsetBit = AllocAfter % 8;

332

335 Target.setAfterBit(AllocAfter);

336 else

337 Target.setAfterBytes(AllocAfter, (BitWidth + 7) / 8);

338 }

339}

340

342 : Fn(Fn), TM(TM),

343 IsBigEndian(Fn->getDataLayout().isBigEndian()),

344 WasDevirt(false) {}

345

346namespace {

347

348

349static unsigned NumDevirtCalls = 0;

350

351

352

353

354struct VTableSlot {

357};

358

359}

360

361namespace llvm {

362

367 }

371 }

375 }

377 const VTableSlot &RHS) {

378 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;

379 }

380};

381

386 }

390 }

394 }

397 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;

398 }

399};

400

401}

402

403

404

405

406

407

408

409

412 return false;

413

414 if ((!TheFnVI) || TheFnVI.getSummaryList().empty()) {

415

416

417 return false;

418 }

419

420 for (const auto &Summary : TheFnVI.getSummaryList()) {

421

422

423 if (!Summary->isLive())

424 return false;

425 if (auto *FS = dyn_cast(Summary->getBaseObject())) {

426 if (!FS->fflags().MustBeUnreachable)

427 return false;

428 }

429

430 else

431 return false;

432 }

433

434

435 return true;

436}

437

438namespace {

439

440

441struct VirtualCallSite {

444

445

446

447

448 unsigned *NumUnsafeUses = nullptr;

449

450 void

456

457 using namespace ore;

459 << NV("Optimization", OptName)

460 << ": devirtualized a call to "

461 << NV("FunctionName", TargetName));

462 }

463

464 void replaceAndErase(

465 const StringRef OptName, const StringRef TargetName, bool RemarksEnabled,

468 if (RemarksEnabled)

469 emitRemark(OptName, TargetName, OREGetter);

471 if (auto *II = dyn_cast(&CB)) {

473 II->getUnwindDest()->removePredecessor(II->getParent());

474 }

476

477 if (NumUnsafeUses)

478 --*NumUnsafeUses;

479 }

480};

481

482

483

484

486

487

488

489

490 std::vector CallSites;

491

492

493

494

495 bool AllCallSitesDevirted = true;

496

497

498

499

500

501

502 bool SummaryHasTypeTestAssumeUsers = false;

503

504

505

506

507

508

509

510

511 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;

512 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;

513

514 bool isExported() const {

515 return SummaryHasTypeTestAssumeUsers ||

516 !SummaryTypeCheckedLoadUsers.empty();

517 }

518

519 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {

520 SummaryTypeCheckedLoadUsers.push_back(FS);

521 AllCallSitesDevirted = false;

522 }

523

525 SummaryTypeTestAssumeUsers.push_back(FS);

526 SummaryHasTypeTestAssumeUsers = true;

527 AllCallSitesDevirted = false;

528 }

529

530 void markDevirt() {

531 AllCallSitesDevirted = true;

532

533

534 SummaryTypeCheckedLoadUsers.clear();

535 }

536};

537

538

539struct VTableSlotInfo {

540

541

543

544

545

546 std::map<std::vector<uint64_t>, CallSiteInfo> ConstCSInfo;

547

548 void addCallSite(Value *VTable, CallBase &CB, unsigned *NumUnsafeUses);

549

550private:

552};

553

555 std::vector<uint64_t> Args;

556 auto *CBType = dyn_cast(CB.getType());

557 if (!CBType || CBType->getBitWidth() > 64 || CB.arg_empty())

558 return CSInfo;

560 auto *CI = dyn_cast(Arg);

561 if (!CI || CI->getBitWidth() > 64)

562 return CSInfo;

563 Args.push_back(CI->getZExtValue());

564 }

565 return ConstCSInfo[Args];

566}

567

568void VTableSlotInfo::addCallSite(Value *VTable, CallBase &CB,

569 unsigned *NumUnsafeUses) {

570 auto &CSI = findCallSiteInfo(CB);

571 CSI.AllCallSitesDevirted = false;

572 CSI.CallSites.push_back({VTable, CB, NumUnsafeUses});

573}

574

575struct DevirtModule {

579

582

588

589

590

592

593 bool RemarksEnabled;

595

597

598

599

600

602

603

604

606

607

608

609

610

611

612

613

614

615 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;

616 PatternList FunctionsToSkip;

617

623 : M(M), AARGetter(AARGetter), LookupDomTree(LookupDomTree),

624 ExportSummary(ExportSummary), ImportSummary(ImportSummary),

625 Int8Ty(Type::getInt8Ty(M.getContext())),

626 Int8PtrTy(PointerType::getUnqual(M.getContext())),

627 Int32Ty(Type::getInt32Ty(M.getContext())),

628 Int64Ty(Type::getInt64Ty(M.getContext())),

629 IntPtrTy(M.getDataLayout().getIntPtrType(M.getContext(), 0)),

631 RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter) {

632 assert(!(ExportSummary && ImportSummary));

634 }

635

636 bool areRemarksEnabled();

637

638 void

639 scanTypeTestUsers(Function *TypeTestFunc,

641 void scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc);

642

643 void buildTypeIdentifierMap(

644 std::vector &Bits,

646

647 bool

648 tryFindVirtualCallTargets(std::vector &TargetsForSlot,

649 const std::set &TypeMemberInfos,

652

653 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,

654 bool &IsExported);

657 VTableSlotInfo &SlotInfo,

659

660 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Constant *JT,

661 bool &IsExported);

663 VTableSlotInfo &SlotInfo,

665

666 bool tryEvaluateFunctionsWithArgs(

669

670 void applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,

673 CallSiteInfo &CSInfo,

675

676

677

680

681 bool shouldExportConstantsAsAbsoluteSymbols();

682

683

684

685

690

691

692

698

700

701 void applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, bool IsOne,

703 bool tryUniqueRetValOpt(unsigned BitWidth,

705 CallSiteInfo &CSInfo,

708

709 void applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName,

712 VTableSlotInfo &SlotInfo,

714

716

717

718 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);

719

720

721

722 void removeRedundantTypeTests();

723

724 bool run();

725

726

727

728

731

732

733

734

735

736

737

738

739

742

743

744

745 static bool

749};

750

751struct DevirtIndex {

753

754

755 std::setGlobalValue::GUID &ExportedGUIDs;

756

757

758

759 std::map<ValueInfo, std::vector> &LocalWPDTargetsMap;

760

762

763 PatternList FunctionsToSkip;

764

765 DevirtIndex(

767 std::setGlobalValue::GUID &ExportedGUIDs,

768 std::map<ValueInfo, std::vector> &LocalWPDTargetsMap)

769 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),

770 LocalWPDTargetsMap(LocalWPDTargetsMap) {

772 }

773

774 bool tryFindVirtualCallTargets(std::vector &TargetsForSlot,

777

780 VTableSlotInfo &SlotInfo,

782 std::set &DevirtTargets);

783

784 void run();

785};

786}

787

793 };

796 };

799 };

800 if (UseCommandLine) {

801 if (!DevirtModule::runForTesting(M, AARGetter, OREGetter, LookupDomTree))

804 }

805 if (!DevirtModule(M, AARGetter, OREGetter, LookupDomTree, ExportSummary,

806 ImportSummary)

807 .run())

810}

811

812

813

817}

818

819static bool

822

823

824

825 if (TypeID.ends_with(".virtual"))

826 return false;

827

828

829

830

831 if (TypeID.consume_front("_ZTS"))

832 return false;

833

834

835

836

837

838

839 std::string typeInfo = ("_ZTI" + TypeID).str();

840 return IsVisibleToRegularObj(typeInfo);

841}

842

843static bool

847 GV.getMetadata(LLVMContext::MD_type, Types);

848

849 for (auto Type : Types)

850 if (auto *TypeID = dyn_cast(Type->getOperand(1).get()))

852 IsVisibleToRegularObj);

853

854 return false;

855}

856

857

858

859

861 Module &M, bool WholeProgramVisibilityEnabledInLTO,

863 bool ValidateAllVtablesHaveTypeInfos,

866 return;

868

869

870

871 if (GV.hasMetadata(LLVMContext::MD_type) &&

873

874

876

877

878

879

880 !(ValidateAllVtablesHaveTypeInfos &&

883 }

884}

885

887 bool WholeProgramVisibilityEnabledInLTO) {

888 Function *PublicTypeTestFunc =

890 if (!PublicTypeTestFunc)

891 return;

896 auto *CI = cast(U.getUser());

898 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {}, "",

900 CI->replaceAllUsesWith(NewCI);

901 CI->eraseFromParent();

902 }

903 } else {

906 auto *CI = cast(U.getUser());

907 CI->replaceAllUsesWith(True);

908 CI->eraseFromParent();

909 }

910 }

911}

912

913

914

919 for (const auto &typeID : Index.typeIdCompatibleVtableMap()) {

922 VisibleToRegularObjSymbols.insert(P.VTableVI.getGUID());

923 }

924}

925

926

927

928

934 return;

935 for (auto &P : Index) {

936

937

938 if (DynamicExportSymbols.count(P.first))

939 continue;

940 for (auto &S : P.second.SummaryList) {

941 auto *GVar = dyn_cast(S.get());

942 if (!GVar ||

944 continue;

945

946

947

948

949 if (VisibleToRegularObjSymbols.count(P.first))

950 continue;

952 }

953 }

954}

955

957 ModuleSummaryIndex &Summary, std::setGlobalValue::GUID &ExportedGUIDs,

958 std::map<ValueInfo, std::vector> &LocalWPDTargetsMap) {

959 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap).run();

960}

961

965 std::map<ValueInfo, std::vector> &LocalWPDTargetsMap) {

966 for (auto &T : LocalWPDTargetsMap) {

967 auto &VI = T.first;

968

969 assert(VI.getSummaryList().size() == 1 &&

970 "Devirt of local target has more than one copy");

971 auto &S = VI.getSummaryList()[0];

972 if (!isExported(S->modulePath(), VI))

973 continue;

974

975

976 for (auto &SlotSummary : T.second) {

977 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);

979 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);

980 assert(WPDRes != TIdSum->WPDRes.end());

982 WPDRes->second.SingleImplName,

983 Summary.getModuleHash(S->modulePath()));

984 }

985 }

986}

987

989

990

991

992

993 const auto &ModPaths = Summary->modulePaths();

998 "combined summary should contain Regular LTO module");

1000}

1001

1002bool DevirtModule::runForTesting(

1006 std::unique_ptr Summary =

1007 std::make_unique(false);

1008

1009

1010

1013 ": ");

1014 auto ReadSummaryFile =

1016 if (Expected<std::unique_ptr> SummaryOrErr =

1018 Summary = std::move(*SummaryOrErr);

1020 } else {

1021

1023 yaml::Input In(ReadSummaryFile->getBuffer());

1026 }

1027 }

1028

1029 bool Changed =

1030 DevirtModule(M, AARGetter, OREGetter, LookupDomTree,

1032 : nullptr,

1034 : nullptr)

1035 .run();

1036

1039 "-wholeprogramdevirt-write-summary: " + ClWriteSummary + ": ");

1040 std::error_code EC;

1045 } else {

1048 yaml::Output Out(OS);

1050 }

1051 }

1052

1053 return Changed;

1054}

1055

1056void DevirtModule::buildTypeIdentifierMap(

1057 std::vector &Bits,

1058 DenseMap<Metadata *, std::set> &TypeIdMap) {

1060 Bits.reserve(M.global_size());

1064 GV.getMetadata(LLVMContext::MD_type, Types);

1066 continue;

1067

1068 VTableBits *&BitsPtr = GVToBits[&GV];

1069 if (!BitsPtr) {

1070 Bits.emplace_back();

1071 Bits.back().GV = &GV;

1072 Bits.back().ObjectSize =

1074 BitsPtr = &Bits.back();

1075 }

1076

1078 auto TypeID = Type->getOperand(1).get();

1079

1081 cast(

1082 cast(Type->getOperand(0))->getValue())

1083 ->getZExtValue();

1084

1085 TypeIdMap[TypeID].insert({BitsPtr, Offset});

1086 }

1087 }

1088}

1089

1090bool DevirtModule::tryFindVirtualCallTargets(

1091 std::vector &TargetsForSlot,

1092 const std::set &TypeMemberInfos, uint64_t ByteOffset,

1095 if (TM.Bits->GV->isConstant())

1096 return false;

1097

1098

1099

1100 if (TM.Bits->GV->getVCallVisibility() ==

1102 return false;

1103

1106 std::tie(Fn, C) =

1108

1109 if (!Fn)

1110 return false;

1111

1112 if (FunctionsToSkip.match(Fn->getName()))

1113 return false;

1114

1115

1116

1117 if (Fn->getName() == "__cxa_pure_virtual")

1118 continue;

1119

1120

1121

1123 continue;

1124

1125

1126

1127 auto GV = dyn_cast(C);

1129 TargetsForSlot.push_back({GV, &TM});

1130 }

1131

1132

1133 return !TargetsForSlot.empty();

1134}

1135

1136bool DevirtIndex::tryFindVirtualCallTargets(

1137 std::vector &TargetsForSlot,

1140

1141

1142

1143

1144

1145

1146

1147

1148

1149

1151 bool LocalFound = false;

1152 for (const auto &S : P.VTableVI.getSummaryList()) {

1154 if (LocalFound)

1155 return false;

1156 LocalFound = true;

1157 }

1158 auto *CurVS = cast(S->getBaseObject());

1159 if (!CurVS->vTableFuncs().empty() ||

1160

1161

1162

1163

1164

1165

1166

1168 VS = CurVS;

1169

1170

1172 return false;

1173 }

1174 }

1175

1176

1177 if (!VS)

1178 return false;

1179 if (VS->isLive())

1180 continue;

1181 for (auto VTP : VS->vTableFuncs()) {

1182 if (VTP.VTableOffset != P.AddressPointOffset + ByteOffset)

1183 continue;

1184

1186 continue;

1187

1188 TargetsForSlot.push_back(VTP.FuncVI);

1189 }

1190 }

1191

1192

1193 return !TargetsForSlot.empty();

1194}

1195

1196void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,

1197 Constant *TheFn, bool &IsExported) {

1198

1199

1201 return;

1203 for (auto &&VCallSite : CSInfo.CallSites) {

1204 if (!OptimizedCalls.insert(&VCallSite.CB).second)

1205 continue;

1206

1207

1210 return;

1211

1212 if (RemarksEnabled)

1213 VCallSite.emitRemark("single-impl",

1215 NumSingleImpl++;

1216 NumDevirtCalls++;

1217 auto &CB = VCallSite.CB;

1222

1223

1224

1225

1229 Cond, &CB, false,

1231 Builder.SetInsertPoint(ThenTerm);

1234 auto *CallTrap = Builder.CreateCall(TrapFn);

1235 CallTrap->setDebugLoc(CB.getDebugLoc());

1236 }

1237

1238

1239

1240

1243

1244

1245

1248

1249

1250

1251 NewInst.setMetadata(LLVMContext::MD_prof, nullptr);

1252 NewInst.setMetadata(LLVMContext::MD_callees, nullptr);

1253

1254

1255 CB.setMetadata(LLVMContext::MD_prof, nullptr);

1256 CB.setMetadata(LLVMContext::MD_callees, nullptr);

1257 }

1258

1259

1260 else {

1261

1263

1264

1265

1266 CB.setMetadata(LLVMContext::MD_prof, nullptr);

1267 CB.setMetadata(LLVMContext::MD_callees, nullptr);

1273

1274 CallsWithPtrAuthBundleRemoved.push_back(&CB);

1275 }

1276 }

1277

1278

1279 if (VCallSite.NumUnsafeUses)

1280 --*VCallSite.NumUnsafeUses;

1281 }

1282 if (CSInfo.isExported())

1283 IsExported = true;

1284 CSInfo.markDevirt();

1285 };

1286 Apply(SlotInfo.CSInfo);

1287 for (auto &P : SlotInfo.ConstCSInfo)

1288 Apply(P.second);

1289}

1290

1292

1293 if (Callee.getSummaryList().empty())

1294 return false;

1295

1296

1297

1298

1299

1300 bool IsExported = false;

1301 auto &S = Callee.getSummaryList()[0];

1303 0);

1305 for (auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {

1306 FS->addCall({Callee, CI});

1307 IsExported |= S->modulePath() != FS->modulePath();

1308 }

1309 for (auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {

1310 FS->addCall({Callee, CI});

1311 IsExported |= S->modulePath() != FS->modulePath();

1312 }

1313 };

1315 for (auto &P : SlotInfo.ConstCSInfo)

1317 return IsExported;

1318}

1319

1320bool DevirtModule::trySingleImplDevirt(

1324

1325

1326 auto *TheFn = TargetsForSlot[0].Fn;

1327 for (auto &&Target : TargetsForSlot)

1328 if (TheFn != Target.Fn)

1329 return false;

1330

1331

1333 TargetsForSlot[0].WasDevirt = true;

1334

1335 bool IsExported = false;

1336 applySingleImplDevirt(SlotInfo, TheFn, IsExported);

1337 if (!IsExported)

1338 return false;

1339

1340

1341

1342

1343 if (TheFn->hasLocalLinkage()) {

1344 std::string NewName = (TheFn->getName() + ".llvm.merged").str();

1345

1346

1347

1348

1349 if (Comdat *C = TheFn->getComdat()) {

1350 if (C->getName() == TheFn->getName()) {

1351 Comdat *NewC = M.getOrInsertComdat(NewName);

1354 if (GO.getComdat() == C)

1355 GO.setComdat(NewC);

1356 }

1357 }

1358

1361 TheFn->setName(NewName);

1362 }

1364

1365

1366 AddCalls(SlotInfo, TheFnVI);

1367

1370

1371 return true;

1372}

1373

1376 VTableSlotInfo &SlotInfo,

1378 std::set &DevirtTargets) {

1379

1380

1381 auto TheFn = TargetsForSlot[0];

1382 for (auto &&Target : TargetsForSlot)

1383 if (TheFn != Target)

1384 return false;

1385

1386

1387 auto Size = TheFn.getSummaryList().size();

1389 return false;

1390

1391

1392

1393 if (FunctionsToSkip.match(TheFn.name()))

1394 return false;

1395

1396

1397

1398 for (const auto &S : TheFn.getSummaryList())

1400 return false;

1401

1402

1404 DevirtTargets.insert(TheFn);

1405

1406 auto &S = TheFn.getSummaryList()[0];

1407 bool IsExported = AddCalls(SlotInfo, TheFn);

1408 if (IsExported)

1409 ExportedGUIDs.insert(TheFn.getGUID());

1410

1411

1412

1415 if (IsExported)

1416

1417

1418

1420 TheFn.name(), ExportSummary.getModuleHash(S->modulePath()));

1421 else {

1422 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);

1424 }

1425 } else

1427

1428

1429

1430

1432

1433 return true;

1434}

1435

1436void DevirtModule::tryICallBranchFunnel(

1439 Triple T(M.getTargetTriple());

1441 return;

1442

1444 return;

1445

1446 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;

1447 if (!HasNonDevirt)

1448 for (auto &P : SlotInfo.ConstCSInfo)

1449 if (P.second.AllCallSitesDevirted) {

1450 HasNonDevirt = true;

1451 break;

1452 }

1453

1454 if (!HasNonDevirt)

1455 return;

1456

1460 if (isa(Slot.TypeID)) {

1462 M.getDataLayout().getProgramAddressSpace(),

1463 getGlobalName(Slot, {}, "branch_funnel"), &M);

1465 } else {

1467 M.getDataLayout().getProgramAddressSpace(),

1468 "branch_funnel", &M);

1469 }

1470 JT->addParamAttr(0, Attribute::Nest);

1471

1472 std::vector<Value *> JTArgs;

1473 JTArgs.push_back(JT->arg_begin());

1474 for (auto &T : TargetsForSlot) {

1475 JTArgs.push_back(getMemberAddr(T.TM));

1476 JTArgs.push_back(T.Fn);

1477 }

1478

1481 &M, llvm::Intrinsic::icall_branch_funnel, {});

1482

1486

1487 bool IsExported = false;

1488 applyICallBranchFunnel(SlotInfo, JT, IsExported);

1489 if (IsExported)

1491}

1492

1493void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,

1494 Constant *JT, bool &IsExported) {

1496 if (CSInfo.isExported())

1497 IsExported = true;

1498 if (CSInfo.AllCallSitesDevirted)

1499 return;

1500

1501 std::map<CallBase *, CallBase *> CallBases;

1502 for (auto &&VCallSite : CSInfo.CallSites) {

1503 CallBase &CB = VCallSite.CB;

1504

1505 if (CallBases.find(&CB) != CallBases.end()) {

1506

1507

1508

1509

1510

1511 continue;

1512 }

1513

1514

1516 if (!FSAttr.isValid() ||

1518 continue;

1519

1520 NumBranchFunnel++;

1521 if (RemarksEnabled)

1522 VCallSite.emitRemark("branch-funnel",

1523 JT->stripPointerCasts()->getName(), OREGetter);

1524

1525

1526

1527 std::vector<Type *> NewArgs;

1528 NewArgs.push_back(Int8PtrTy);

1534 std::vector<Value *> Args;

1535 Args.push_back(VCallSite.VTable);

1537

1539 if (isa(CB))

1540 NewCS = IRB.CreateCall(NewFT, JT, Args);

1541 else

1542 NewCS =

1543 IRB.CreateInvoke(NewFT, JT, cast(CB).getNormalDest(),

1544 cast(CB).getUnwindDest(), Args);

1546

1548 std::vector NewArgAttrs;

1551 M.getContext(), Attribute::Nest)}));

1552 for (unsigned I = 0; I + 2 < Attrs.getNumAttrSets(); ++I)

1553 NewArgAttrs.push_back(Attrs.getParamAttrs(I));

1556 Attrs.getRetAttrs(), NewArgAttrs));

1557

1558 CallBases[&CB] = NewCS;

1559

1560

1561 if (VCallSite.NumUnsafeUses)

1562 --*VCallSite.NumUnsafeUses;

1563 }

1564

1565

1566

1567

1568

1569 for (auto &[Old, New] : CallBases) {

1571 Old->eraseFromParent();

1572 }

1573 };

1574 Apply(SlotInfo.CSInfo);

1575 for (auto &P : SlotInfo.ConstCSInfo)

1576 Apply(P.second);

1577}

1578

1579bool DevirtModule::tryEvaluateFunctionsWithArgs(

1582

1583

1585

1586

1587

1588 auto Fn = dyn_cast(Target.Fn);

1589 if (!Fn)

1590 return false;

1591

1593 return false;

1594

1595 Evaluator Eval(M.getDataLayout(), nullptr);

1599 for (unsigned I = 0; I != Args.size(); ++I) {

1600 auto *ArgTy =

1602 if (!ArgTy)

1603 return false;

1604 EvalArgs.push_back(ConstantInt::get(ArgTy, Args[I]));

1605 }

1606

1608 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||

1609 !isa(RetVal))

1610 return false;

1611 Target.RetVal = cast(RetVal)->getZExtValue();

1612 }

1613 return true;

1614}

1615

1616void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,

1618 for (auto Call : CSInfo.CallSites) {

1619 if (!OptimizedCalls.insert(&Call.CB).second)

1620 continue;

1621 NumUniformRetVal++;

1622 Call.replaceAndErase(

1623 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,

1624 ConstantInt::get(cast(Call.CB.getType()), TheRetVal));

1625 }

1626 CSInfo.markDevirt();

1627}

1628

1629bool DevirtModule::tryUniformRetValOpt(

1632

1633

1634 uint64_t TheRetVal = TargetsForSlot[0].RetVal;

1636 if (Target.RetVal != TheRetVal)

1637 return false;

1638

1639 if (CSInfo.isExported()) {

1641 Res->Info = TheRetVal;

1642 }

1643

1644 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), TheRetVal);

1646 for (auto &&Target : TargetsForSlot)

1647 Target.WasDevirt = true;

1648 return true;

1649}

1650

1651std::string DevirtModule::getGlobalName(VTableSlot Slot,

1654 std::string FullName = "__typeid_";

1656 OS << cast(Slot.TypeID)->getString() << '_' << Slot.ByteOffset;

1658 OS << '_' << Arg;

1660 return FullName;

1661}

1662

1663bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {

1664 Triple T(M.getTargetTriple());

1665 return T.isX86() && T.getObjectFormat() == Triple::ELF;

1666}

1667

1668void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,

1671 getGlobalName(Slot, Args, Name), C, &M);

1673}

1674

1675void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,

1678 if (shouldExportConstantsAsAbsoluteSymbols()) {

1679 exportGlobal(

1680 Slot, Args, Name,

1682 return;

1683 }

1684

1685 Storage = Const;

1686}

1687

1691 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);

1692 auto *GV = dyn_cast(C);

1693 if (GV)

1695 return C;

1696}

1697

1701 if (!shouldExportConstantsAsAbsoluteSymbols())

1702 return ConstantInt::get(IntTy, Storage);

1703

1705 auto *GV = cast(C->stripPointerCasts());

1707

1708

1709

1710 if (GV->hasMetadata(LLVMContext::MD_absolute_symbol))

1711 return C;

1712

1716 GV->setMetadata(LLVMContext::MD_absolute_symbol,

1718 };

1719 unsigned AbsWidth = IntTy->getBitWidth();

1720 if (AbsWidth == IntPtrTy->getBitWidth())

1721 SetAbsRange(~0ull, ~0ull);

1722 else

1723 SetAbsRange(0, 1ull << AbsWidth);

1724 return C;

1725}

1726

1727void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,

1728 bool IsOne,

1729 Constant *UniqueMemberAddr) {

1730 for (auto &&Call : CSInfo.CallSites) {

1731 if (!OptimizedCalls.insert(&Call.CB).second)

1732 continue;

1736 B.CreateBitCast(UniqueMemberAddr, Call.VTable->getType()));

1737 Cmp = B.CreateZExt(Cmp, Call.CB.getType());

1738 NumUniqueRetVal++;

1739 Call.replaceAndErase("unique-ret-val", FnName, RemarksEnabled, OREGetter,

1740 Cmp);

1741 }

1742 CSInfo.markDevirt();

1743}

1744

1747 ConstantInt::get(Int64Ty, M->Offset));

1748}

1749

1750bool DevirtModule::tryUniqueRetValOpt(

1754

1755 auto tryUniqueRetValOptFor = [&](bool IsOne) {

1758 if (Target.RetVal == (IsOne ? 1 : 0)) {

1759 if (UniqueMember)

1760 return false;

1761 UniqueMember = Target.TM;

1762 }

1763 }

1764

1765

1766

1767 assert(UniqueMember);

1768

1769 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);

1770 if (CSInfo.isExported()) {

1772 Res->Info = IsOne;

1773

1774 exportGlobal(Slot, Args, "unique_member", UniqueMemberAddr);

1775 }

1776

1777

1778 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), IsOne,

1779 UniqueMemberAddr);

1780

1781

1783 for (auto &&Target : TargetsForSlot)

1784 Target.WasDevirt = true;

1785

1786 return true;

1787 };

1788

1790 if (tryUniqueRetValOptFor(true))

1791 return true;

1792 if (tryUniqueRetValOptFor(false))

1793 return true;

1794 }

1795 return false;

1796}

1797

1798void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName,

1800 for (auto Call : CSInfo.CallSites) {

1801 if (!OptimizedCalls.insert(&Call.CB).second)

1802 continue;

1803 auto *RetType = cast(Call.CB.getType());

1806 if (RetType->getBitWidth() == 1) {

1808 Value *BitsAndBit = B.CreateAnd(Bits, Bit);

1809 auto IsBitSet = B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));

1810 NumVirtConstProp1Bit++;

1811 Call.replaceAndErase("virtual-const-prop-1-bit", FnName, RemarksEnabled,

1812 OREGetter, IsBitSet);

1813 } else {

1814 Value *Val = B.CreateLoad(RetType, Addr);

1815 NumVirtConstProp++;

1816 Call.replaceAndErase("virtual-const-prop", FnName, RemarksEnabled,

1817 OREGetter, Val);

1818 }

1819 }

1820 CSInfo.markDevirt();

1821}

1822

1823bool DevirtModule::tryVirtualConstProp(

1826

1827

1828

1829 auto Fn = dyn_cast(TargetsForSlot[0].Fn);

1830 if (!Fn)

1831 return false;

1832

1833 auto RetType = dyn_cast(Fn->getReturnType());

1834 if (!RetType)

1835 return false;

1836 unsigned BitWidth = RetType->getBitWidth();

1838 return false;

1839

1840

1841

1842

1843

1844

1845

1846

1847

1848

1849

1851

1852

1853

1854 auto Fn = dyn_cast(Target.Fn);

1855 if (!Fn)

1856 return false;

1857

1860 .doesNotAccessMemory() ||

1863 return false;

1864 }

1865

1866 for (auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {

1867 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))

1868 continue;

1869

1871 if (Res)

1872 ResByArg = &Res->ResByArg[CSByConstantArg.first];

1873

1874 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))

1875 continue;

1876

1877 if (tryUniqueRetValOpt(BitWidth, TargetsForSlot, CSByConstantArg.second,

1878 ResByArg, Slot, CSByConstantArg.first))

1879 continue;

1880

1881

1882

1887

1888

1889

1890 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;

1891 for (auto &&Target : TargetsForSlot) {

1892 TotalPaddingBefore += std::max<int64_t>(

1893 (AllocBefore + 7) / 8 - Target.allocatedBeforeBytes() - 1, 0);

1894 TotalPaddingAfter += std::max<int64_t>(

1895 (AllocAfter + 7) / 8 - Target.allocatedAfterBytes() - 1, 0);

1896 }

1897

1898

1899

1900 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)

1901 continue;

1902

1903

1904

1905 int64_t OffsetByte;

1907 if (TotalPaddingBefore <= TotalPaddingAfter)

1909 OffsetBit);

1910 else

1912 OffsetBit);

1913

1915 for (auto &&Target : TargetsForSlot)

1916 Target.WasDevirt = true;

1917

1918

1919 if (CSByConstantArg.second.isExported()) {

1921 exportConstant(Slot, CSByConstantArg.first, "byte", OffsetByte,

1922 ResByArg->Byte);

1923 exportConstant(Slot, CSByConstantArg.first, "bit", 1ULL << OffsetBit,

1924 ResByArg->Bit);

1925 }

1926

1927

1928 Constant *ByteConst = ConstantInt::get(Int32Ty, OffsetByte);

1929 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);

1930 applyVirtualConstProp(CSByConstantArg.second,

1931 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);

1932 }

1933 return true;

1934}

1935

1936void DevirtModule::rebuildGlobal(VTableBits &B) {

1937 if (B.Before.Bytes.empty() && B.After.Bytes.empty())

1938 return;

1939

1940

1941

1942 Align Alignment = M.getDataLayout().getValueOrABITypeAlignment(

1943 B.GV->getAlign(), B.GV->getValueType());

1944 B.Before.Bytes.resize(alignTo(B.Before.Bytes.size(), Alignment));

1945

1946

1947 for (size_t I = 0, Size = B.Before.Bytes.size(); I != Size / 2; ++I)

1949

1950

1951

1954 B.GV->getInitializer(),

1956 auto NewGV =

1957 new GlobalVariable(M, NewInit->getType(), B.GV->isConstant(),

1959 NewGV->setSection(B.GV->getSection());

1960 NewGV->setComdat(B.GV->getComdat());

1961 NewGV->setAlignment(B.GV->getAlign());

1962

1963

1964

1965 NewGV->copyMetadata(B.GV, B.Before.Bytes.size());

1966

1967

1968

1970 B.GV->getInitializer()->getType(), 0, B.GV->getLinkage(), "",

1972 NewInit->getType(), NewGV,

1974 ConstantInt::get(Int32Ty, 1)}),

1975 &M);

1976 Alias->setVisibility(B.GV->getVisibility());

1977 Alias->takeName(B.GV);

1978

1979 B.GV->replaceAllUsesWith(Alias);

1980 B.GV->eraseFromParent();

1981}

1982

1983bool DevirtModule::areRemarksEnabled() {

1984 const auto &FL = M.getFunctionList();

1985 for (const Function &Fn : FL) {

1987 continue;

1989 return DI.isEnabled();

1990 }

1991 return false;

1992}

1993

1994void DevirtModule::scanTypeTestUsers(

1996 DenseMap<Metadata *, std::set> &TypeIdMap) {

1997

1998

1999

2000

2001

2003 auto *CI = dyn_cast(U.getUser());

2004 if (!CI)

2005 continue;

2006

2007

2010 auto &DT = LookupDomTree(*CI->getFunction());

2012

2014 cast(CI->getArgOperand(1))->getMetadata();

2015

2016 if (!Assumes.empty()) {

2017 Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();

2019 CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CB, nullptr);

2020 }

2021

2022 auto RemoveTypeTestAssumes = [&]() {

2023

2024 for (auto *Assume : Assumes)

2025 Assume->eraseFromParent();

2026

2027

2028 if (CI->use_empty())

2029 CI->eraseFromParent();

2030 };

2031

2032

2033

2034

2035

2036

2037

2038

2039

2040

2041

2042

2043

2044 if (!TypeIdMap.count(TypeId))

2045 RemoveTypeTestAssumes();

2046

2047

2048

2049

2050

2051

2052

2053

2054

2055

2056 else if (ImportSummary && isa(TypeId)) {

2058 ImportSummary->getTypeIdSummary(cast(TypeId)->getString());

2059 if (!TidSummary)

2060 RemoveTypeTestAssumes();

2061 else

2062

2063

2065 }

2066 }

2067}

2068

2069void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {

2072

2074 auto *CI = dyn_cast(U.getUser());

2075 if (!CI)

2076 continue;

2077

2078 Value *Ptr = CI->getArgOperand(0);

2080 Value *TypeIdValue = CI->getArgOperand(2);

2081 Metadata *TypeId = cast(TypeIdValue)->getMetadata();

2082

2086 bool HasNonCallUses = false;

2087 auto &DT = LookupDomTree(*CI->getFunction());

2089 HasNonCallUses, CI, DT);

2090

2091

2092

2093

2094

2095

2096

2098 (LoadedPtrs.size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);

2099

2100 Value *LoadedValue = nullptr;

2102 Intrinsic::type_checked_load_relative) {

2104 LoadedValue = LoadB.CreateLoad(Int32Ty, GEP);

2105 LoadedValue = LoadB.CreateSExt(LoadedValue, IntPtrTy);

2106 GEP = LoadB.CreatePtrToInt(GEP, IntPtrTy);

2107 LoadedValue = LoadB.CreateAdd(GEP, LoadedValue);

2108 LoadedValue = LoadB.CreateIntToPtr(LoadedValue, Int8PtrTy);

2109 } else {

2111 LoadedValue = LoadB.CreateLoad(Int8PtrTy, GEP);

2112 }

2113

2114 for (Instruction *LoadedPtr : LoadedPtrs) {

2116 LoadedPtr->eraseFromParent();

2117 }

2118

2119

2120 IRBuilder<> CallB((Preds.size() == 1 && !HasNonCallUses) ? Preds[0] : CI);

2121 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {Ptr, TypeIdValue});

2122

2125 Pred->eraseFromParent();

2126 }

2127

2128

2129

2130

2131

2132 if (!CI->use_empty()) {

2135 Pair = B.CreateInsertValue(Pair, LoadedValue, {0});

2136 Pair = B.CreateInsertValue(Pair, TypeTestCall, {1});

2137 CI->replaceAllUsesWith(Pair);

2138 }

2139

2140

2141 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];

2142 NumUnsafeUses = DevirtCalls.size();

2143

2144

2145

2146

2147 if (HasNonCallUses)

2148 ++NumUnsafeUses;

2150 CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CB,

2151 &NumUnsafeUses);

2152 }

2153

2154 CI->eraseFromParent();

2155 }

2156}

2157

2158void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {

2159 auto *TypeId = dyn_cast(Slot.TypeID);

2160 if (!TypeId)

2161 return;

2164 if (!TidSummary)

2165 return;

2166 auto ResI = TidSummary->WPDRes.find(Slot.ByteOffset);

2167 if (ResI == TidSummary->WPDRes.end())

2168 return;

2170

2173

2174

2176 cast(M.getOrInsertFunction(Res.SingleImplName,

2178 .getCallee());

2179

2180

2181 bool IsExported = false;

2182 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);

2183 assert(!IsExported);

2184 }

2185

2186 for (auto &CSByConstantArg : SlotInfo.ConstCSInfo) {

2187 auto I = Res.ResByArg.find(CSByConstantArg.first);

2189 continue;

2190 auto &ResByArg = I->second;

2191

2192

2193

2194

2195 switch (ResByArg.TheKind) {

2197 applyUniformRetValOpt(CSByConstantArg.second, "", ResByArg.Info);

2198 break;

2200 Constant *UniqueMemberAddr =

2201 importGlobal(Slot, CSByConstantArg.first, "unique_member");

2202 applyUniqueRetValOpt(CSByConstantArg.second, "", ResByArg.Info,

2203 UniqueMemberAddr);

2204 break;

2205 }

2207 Constant *Byte = importConstant(Slot, CSByConstantArg.first, "byte",

2208 Int32Ty, ResByArg.Byte);

2209 Constant *Bit = importConstant(Slot, CSByConstantArg.first, "bit", Int8Ty,

2210 ResByArg.Bit);

2211 applyVirtualConstProp(CSByConstantArg.second, "", Byte, Bit);

2212 break;

2213 }

2214 default:

2215 break;

2216 }

2217 }

2218

2220

2221

2223 M.getOrInsertFunction(getGlobalName(Slot, {}, "branch_funnel"),

2225 .getCallee());

2226 bool IsExported = false;

2227 applyICallBranchFunnel(SlotInfo, JT, IsExported);

2228 assert(!IsExported);

2229 }

2230}

2231

2232void DevirtModule::removeRedundantTypeTests() {

2234 for (auto &&U : NumUnsafeUsesForTypeTest) {

2235 if (U.second == 0) {

2236 U.first->replaceAllUsesWith(True);

2237 U.first->eraseFromParent();

2238 }

2239 }

2240}

2241

2243DevirtModule::lookUpFunctionValueInfo(Function *TheFn,

2245 assert((ExportSummary != nullptr) &&

2246 "Caller guarantees ExportSummary is not nullptr");

2247

2248 const auto TheFnGUID = TheFn->getGUID();

2250

2252

2253

2254

2255

2256

2257

2258

2259

2260 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {

2261 TheFnVI = ExportSummary->getValueInfo(TheFnGUIDWithExportedName);

2262 }

2263 return TheFnVI;

2264}

2265

2266bool DevirtModule::mustBeUnreachableFunction(

2269 return false;

2270

2271 if (F->isDeclaration()) {

2272

2273

2274 return isa(F->getEntryBlock().getTerminator());

2275 }

2276

2277 return ExportSummary &&

2279 DevirtModule::lookUpFunctionValueInfo(F, ExportSummary));

2280}

2281

2282bool DevirtModule::run() {

2283

2284

2285

2286

2289 return false;

2290

2293 Function *TypeCheckedLoadFunc =

2296 &M, Intrinsic::type_checked_load_relative);

2299

2300

2301

2302

2303 if (!ExportSummary &&

2304 (!TypeTestFunc || TypeTestFunc->use_empty() || !AssumeFunc ||

2306 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty()) &&

2307 (!TypeCheckedLoadRelativeFunc ||

2308 TypeCheckedLoadRelativeFunc->use_empty()))

2309 return false;

2310

2311

2312 std::vector Bits;

2314 buildTypeIdentifierMap(Bits, TypeIdMap);

2315

2316 if (TypeTestFunc && AssumeFunc)

2317 scanTypeTestUsers(TypeTestFunc, TypeIdMap);

2318

2319 if (TypeCheckedLoadFunc)

2320 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);

2321

2322 if (TypeCheckedLoadRelativeFunc)

2323 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);

2324

2325 if (ImportSummary) {

2326 for (auto &S : CallSlots)

2327 importResolution(S.first, S.second);

2328

2329 removeRedundantTypeTests();

2330

2331

2332

2333

2335 GV.eraseMetadata(LLVMContext::MD_vcall_visibility);

2336

2337

2338

2339 return true;

2340 }

2341

2342 if (TypeIdMap.empty())

2343 return true;

2344

2345

2346 if (ExportSummary) {

2348 for (auto &P : TypeIdMap) {

2349 if (auto *TypeId = dyn_cast(P.first))

2351 TypeId);

2352 }

2353

2354 for (auto &P : *ExportSummary) {

2355 for (auto &S : P.second.SummaryList) {

2356 auto *FS = dyn_cast(S.get());

2357 if (!FS)

2358 continue;

2359

2361 for (Metadata *MD : MetadataByGUID[VF.GUID]) {

2362 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);

2363 }

2364 }

2366 for (Metadata *MD : MetadataByGUID[VF.GUID]) {

2367 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);

2368 }

2369 }

2371 FS->type_test_assume_const_vcalls()) {

2372 for (Metadata *MD : MetadataByGUID[VC.VFunc.GUID]) {

2373 CallSlots[{MD, VC.VFunc.Offset}]

2374 .ConstCSInfo[VC.Args]

2375 .addSummaryTypeTestAssumeUser(FS);

2376 }

2377 }

2379 FS->type_checked_load_const_vcalls()) {

2380 for (Metadata *MD : MetadataByGUID[VC.VFunc.GUID]) {

2381 CallSlots[{MD, VC.VFunc.Offset}]

2382 .ConstCSInfo[VC.Args]

2383 .addSummaryTypeCheckedLoadUser(FS);

2384 }

2385 }

2386 }

2387 }

2388 }

2389

2390

2391 bool DidVirtualConstProp = false;

2392 std::map<std::string, GlobalValue *> DevirtTargets;

2393 for (auto &S : CallSlots) {

2394

2395

2396

2397 std::vector TargetsForSlot;

2399 const std::set &TypeMemberInfos = TypeIdMap[S.first.TypeID];

2400 if (ExportSummary && isa(S.first.TypeID) &&

2401 TypeMemberInfos.size())

2402

2403

2404

2405

2406

2407

2408 Res = &ExportSummary

2409 ->getOrInsertTypeIdSummary(

2410 cast(S.first.TypeID)->getString())

2411 .WPDRes[S.first.ByteOffset];

2412 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,

2413 S.first.ByteOffset, ExportSummary)) {

2414

2415 if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res)) {

2416 DidVirtualConstProp |=

2417 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);

2418

2419 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);

2420 }

2421

2422

2424 for (const auto &T : TargetsForSlot)

2425 if (T.WasDevirt)

2426 DevirtTargets[std::string(T.Fn->getName())] = T.Fn;

2427 }

2428

2429

2430

2431

2432

2433 if (ExportSummary && isa(S.first.TypeID)) {

2436 for (auto *FS : S.second.CSInfo.SummaryTypeCheckedLoadUsers)

2437 FS->addTypeTest(GUID);

2438 for (auto &CCS : S.second.ConstCSInfo)

2439 for (auto *FS : CCS.second.SummaryTypeCheckedLoadUsers)

2440 FS->addTypeTest(GUID);

2441 }

2442 }

2443

2444 if (RemarksEnabled) {

2445

2446 for (const auto &DT : DevirtTargets) {

2448 auto F = dyn_cast(GV);

2449 if (F) {

2450 auto A = dyn_cast(GV);

2451 assert(A && isa(A->getAliasee()));

2452 F = dyn_cast(A->getAliasee());

2454 }

2455

2456 using namespace ore;

2458 << "devirtualized "

2459 << NV("FunctionName", DT.first));

2460 }

2461 }

2462

2463 NumDevirtTargets += DevirtTargets.size();

2464

2465 removeRedundantTypeTests();

2466

2467

2468

2469 if (DidVirtualConstProp)

2471 rebuildGlobal(B);

2472

2473

2474

2475

2477 GV.eraseMetadata(LLVMContext::MD_vcall_visibility);

2478

2479 for (auto *CI : CallsWithPtrAuthBundleRemoved)

2480 CI->eraseFromParent();

2481

2482 return true;

2483}

2484

2485void DevirtIndex::run() {

2486 if (ExportSummary.typeIdCompatibleVtableMap().empty())

2487 return;

2488

2490 for (const auto &P : ExportSummary.typeIdCompatibleVtableMap()) {

2492

2493

2494

2495

2496

2497

2498 ExportSummary.getOrInsertTypeIdSummary(P.first);

2499 }

2500

2501

2502 for (auto &P : ExportSummary) {

2503 for (auto &S : P.second.SummaryList) {

2504 auto *FS = dyn_cast(S.get());

2505 if (!FS)

2506 continue;

2507

2510 CallSlots[{Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);

2511 }

2512 }

2515 CallSlots[{Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);

2516 }

2517 }

2519 FS->type_test_assume_const_vcalls()) {

2521 CallSlots[{Name, VC.VFunc.Offset}]

2522 .ConstCSInfo[VC.Args]

2523 .addSummaryTypeTestAssumeUser(FS);

2524 }

2525 }

2527 FS->type_checked_load_const_vcalls()) {

2529 CallSlots[{Name, VC.VFunc.Offset}]

2530 .ConstCSInfo[VC.Args]

2531 .addSummaryTypeCheckedLoadUser(FS);

2532 }

2533 }

2534 }

2535 }

2536

2537 std::set DevirtTargets;

2538

2539 for (auto &S : CallSlots) {

2540

2541

2542

2543 std::vector TargetsForSlot;

2544 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);

2546

2547

2549 &ExportSummary.getTypeIdSummary(S.first.TypeID)

2550 ->WPDRes[S.first.ByteOffset];

2551 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,

2552 S.first.ByteOffset)) {

2553

2554 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,

2555 DevirtTargets))

2556 continue;

2557 }

2558 }

2559

2560

2561

2563 for (const auto &DT : DevirtTargets)

2564 errs() << "Devirtualized call to " << DT << "\n";

2565

2566 NumDevirtTargets += DevirtTargets.size();

2567}

This is the interface for LLVM's primary stateless and local alias analysis.

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)

Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...

#define clEnumValN(ENUMVAL, FLAGNAME, DESC)

This file contains the declarations for the subclasses of Constant, which represent the different fla...

This file defines DenseMapInfo traits for DenseMap.

This file defines the DenseMap class.

This file defines the DenseSet and SmallDenseSet classes.

Provides passes for computing function attributes based on interprocedural analyses.

static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE, bool Skip)

Module.h This file contains the declarations for the Module class.

static cl::opt< std::string > ClReadSummary("lowertypetests-read-summary", cl::desc("Read summary from given YAML file before running pass"), cl::Hidden)

static cl::opt< PassSummaryAction > ClSummaryAction("lowertypetests-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)

static cl::opt< std::string > ClWriteSummary("lowertypetests-write-summary", cl::desc("Write summary to given YAML file after running pass"), cl::Hidden)

This file implements a map that provides insertion order iteration.

static bool mustBeUnreachableFunction(const Function &F)

uint64_t IntrinsicInst * II

FunctionAnalysisManager FAM

const SmallVectorImpl< MachineOperand > & Cond

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

This file defines the SmallVector class.

This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...

#define STATISTIC(VARNAME, DESC)

static cl::opt< bool > DisableWholeProgramVisibility("disable-whole-program-visibility", cl::Hidden, cl::desc("Disable whole program visibility (overrides enabling options)"))

Provide a way to force disable whole program for debugging or workarounds, when enabled via the linke...

WPDCheckMode

Mechanism to add runtime checking of devirtualization decisions, optionally trapping or falling back ...

static cl::opt< PassSummaryAction > ClSummaryAction("wholeprogramdevirt-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)

static cl::opt< bool > WholeProgramVisibility("whole-program-visibility", cl::Hidden, cl::desc("Enable whole program visibility"))

Provide a way to force enable whole program visibility in tests.

static bool typeIDVisibleToRegularObj(StringRef TypeID, function_ref< bool(StringRef)> IsVisibleToRegularObj)

static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary)

static cl::list< std::string > SkipFunctionNames("wholeprogramdevirt-skip", cl::desc("Prevent function(s) from being devirtualized"), cl::Hidden, cl::CommaSeparated)

Provide way to prevent certain function from being devirtualized.

static cl::opt< std::string > ClWriteSummary("wholeprogramdevirt-write-summary", cl::desc("Write summary to given bitcode or YAML file after running pass. " "Output file format is deduced from extension: *.bc means writing " "bitcode, otherwise YAML"), cl::Hidden)

static cl::opt< unsigned > ClThreshold("wholeprogramdevirt-branch-funnel-threshold", cl::Hidden, cl::init(10), cl::desc("Maximum number of call targets per " "call site to enable branch funnels"))

static cl::opt< WPDCheckMode > DevirtCheckMode("wholeprogramdevirt-check", cl::Hidden, cl::desc("Type of checking for incorrect devirtualizations"), cl::values(clEnumValN(WPDCheckMode::None, "none", "No checking"), clEnumValN(WPDCheckMode::Trap, "trap", "Trap when incorrect"), clEnumValN(WPDCheckMode::Fallback, "fallback", "Fallback to indirect when incorrect")))

static cl::opt< bool > WholeProgramDevirtKeepUnreachableFunction("wholeprogramdevirt-keep-unreachable-function", cl::desc("Regard unreachable functions as possible devirtualize targets."), cl::Hidden, cl::init(true))

With Clang, a pure virtual class's deleting destructor is emitted as a llvm.trap intrinsic followed b...

static cl::opt< std::string > ClReadSummary("wholeprogramdevirt-read-summary", cl::desc("Read summary from given bitcode or YAML file before running pass"), cl::Hidden)

static bool skipUpdateDueToValidation(GlobalVariable &GV, function_ref< bool(StringRef)> IsVisibleToRegularObj)

static bool AddCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee)

static cl::opt< unsigned > WholeProgramDevirtCutoff("wholeprogramdevirt-cutoff", cl::desc("Max number of devirtualizations for devirt module pass"), cl::init(0))

If explicitly specified, the devirt module pass will stop transformation once the total number of dev...

static cl::opt< bool > PrintSummaryDevirt("wholeprogramdevirt-print-index-based", cl::Hidden, cl::desc("Print index-based devirtualization messages"))

A manager for alias analyses.

A container for analyses that lazily runs them and caches their results.

PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)

Get the result of an analysis pass for a given IR unit.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

size_t size() const

size - Get the array size.

ArrayRef< T > slice(size_t N, size_t M) const

slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.

static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)

Create an AttributeList with the specified parameters in it.

static AttributeSet get(LLVMContext &C, const AttrBuilder &B)

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.

static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)

Creates a new BasicBlock.

static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)

Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...

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

CallingConv::ID getCallingConv() const

Value * getCalledOperand() const

void setAttributes(AttributeList A)

Set the attributes for this call.

FunctionType * getFunctionType() const

iterator_range< User::op_iterator > args()

Iteration adapter for range-for loops.

void setCalledOperand(Value *V)

static CallBase * removeOperandBundle(CallBase *CB, uint32_t ID, InsertPosition InsertPt=nullptr)

Create a clone of CB with operand bundle ID removed.

AttributeList getAttributes() const

Return the attributes for this call.

Function * getCaller()

Helper to get the caller (the parent function).

This class represents a function call, abstracting a target machine's calling convention.

static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)

void setSelectionKind(SelectionKind Val)

static Constant * get(LLVMContext &Context, ArrayRef< ElementTy > Elts)

get() constructor - Return a constant with array type with an element count and element type matching...

static Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)

static Constant * getInBoundsGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList)

Create an "inbounds" getelementptr.

static Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)

static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReducedTy=nullptr)

Getelementptr form.

static ConstantInt * getTrue(LLVMContext &Context)

static Constant * getAnon(ArrayRef< Constant * > V, bool Packed=false)

Return an anonymous struct that has the specified elements.

This is an important base class in LLVM.

const Constant * stripPointerCasts() const

static Constant * getNullValue(Type *Ty)

Constructor to create a '0' constant of arbitrary type.

Implements a dense probed hash-table based set.

Analysis pass which computes a DominatorTree.

Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.

Subclass of Error for the sole purpose of identifying the success path in the type system.

Lightweight error class with error context and mandatory checking.

This class evaluates LLVM IR, producing the Constant representing each SSA instruction.

Helper for check-and-exit error handling.

Tagged union holding either a T or a Error.

Function summary information to aid decisions and implementation of importing.

Type * getParamType(unsigned i) const

Parameter type accessors.

ArrayRef< Type * > params() const

Type * getReturnType() const

static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)

This static method is the primary way of constructing a FunctionType.

static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)

FunctionType * getFunctionType() const

Returns the FunctionType for me.

const BasicBlock & front() const

Attribute getFnAttribute(Attribute::AttrKind Kind) const

Return the attribute for the given attribute kind.

Intrinsic::ID getIntrinsicID() const LLVM_READONLY

getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...

Type * getReturnType() const

Returns the type of the ret val.

This class implements a glob pattern matcher similar to the one found in bash, but with some key diff...

static Expected< GlobPattern > create(StringRef Pat, std::optional< size_t > MaxSubPatterns={})

static GlobalAlias * create(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, Constant *Aliasee, Module *Parent)

If a parent module is specified, the alias is automatically inserted into the end of the specified mo...

bool hasMetadata() const

Return true if this value has any metadata attached to it.

void setMetadata(unsigned KindID, MDNode *Node)

Set a particular kind of metadata attachment.

VCallVisibility getVCallVisibility() const

bool eraseMetadata(unsigned KindID)

Erase all metadata attachments with the given kind.

@ VCallVisibilityLinkageUnit

MDNode * getMetadata(unsigned KindID) const

Get the current metadata attachments for the given kind, if any.

void setVCallVisibilityMetadata(VCallVisibility Visibility)

static bool isLocalLinkage(LinkageTypes Linkage)

bool isDeclaration() const

Return true if the primary definition of this global value is outside of the current translation unit...

static bool isAvailableExternallyLinkage(LinkageTypes Linkage)

static GUID getGUID(StringRef GlobalName)

Return a 64-bit global unique ID constructed from global value name (i.e.

GUID getGUID() const

Return a 64-bit global unique ID constructed from global value name (i.e.

@ HiddenVisibility

The GV is hidden.

void setVisibility(VisibilityTypes V)

@ PrivateLinkage

Like Internal, but omit from symbol table.

@ InternalLinkage

Rename collisions when linking (static functions).

@ ExternalLinkage

Externally visible function.

Global variable summary information to aid decisions and implementation of importing.

const Constant * getInitializer() const

getInitializer - Return the initializer for this global variable.

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...

const DebugLoc & getDebugLoc() const

Return the debug location for this node as a DebugLoc.

InstListType::iterator eraseFromParent()

This method unlinks 'this' from the containing basic block and deletes it.

void setMetadata(unsigned KindID, MDNode *Node)

Set the metadata of the specified kind to the specified node.

Class to represent integer types.

unsigned getBitWidth() const

Get the number of bits in this IntegerType.

MDNode * createLikelyBranchWeights()

Return metadata containing two branch weights, with significant bias towards true destination.

MDNode * createUnlikelyBranchWeights()

Return metadata containing two branch weights, with significant bias towards false destination.

static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)

This class implements a map that also provides access to all stored values in a deterministic order.

static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)

Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...

Class to hold module path string table and global value map, and encapsulate methods for operating on...

const TypeIdSummary * getTypeIdSummary(StringRef TypeId) const

This returns either a pointer to the type id summary (if present in the summary map) or null (if not ...

ValueInfo getValueInfo(const GlobalValueSummaryMapTy::value_type &R) const

Return a ValueInfo for the index value_type (convenient when iterating index).

const ModuleHash & getModuleHash(const StringRef ModPath) const

Get the module SHA1 hash recorded for the given module path.

static constexpr const char * getRegularLTOModuleName()

bool partiallySplitLTOUnits() const

static std::string getGlobalNameForLocal(StringRef Name, ModuleHash ModHash)

Convenience method for creating a promoted global name for the given value name of a local,...

A Module instance is used to store all the information related to an LLVM module.

MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...

static PoisonValue * get(Type *T)

Static factory methods - Return an 'poison' object of the specified type.

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses none()

Convenience factory function for the empty preserved set.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)

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 push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - Represent a constant reference to a string, i.e.

bool contains(StringRef Other) const

Return true if the given string is a substring of *this, and false otherwise.

Target - Wrapper for Target specific information.

Triple - Helper class for working with autoconf configuration names.

The instances of the Type class are immutable: once they are created, they are never changed.

TypeID

Definitions of all of the base types for the Type system.

static Type * getVoidTy(LLVMContext &C)

A Use represents the edge between a Value definition and its users.

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

void setName(const Twine &Name)

Change the name of the value.

void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

bool eraseMetadata(unsigned KindID)

Erase all metadata attachments with the given kind.

iterator_range< use_iterator > uses()

StringRef getName() const

Return a constant reference to the value's name.

std::pair< iterator, bool > insert(const ValueT &V)

size_type count(const_arg_type_t< ValueT > V) const

Return 1 if the specified key is in the set, 0 otherwise.

An efficient, type-erasing, non-owning reference to a callable.

const ParentTy * getParent() const

self_iterator getIterator()

A raw_ostream that writes to a file descriptor.

A raw_ostream that writes to an std::string.

constexpr char Args[]

Key for Kernel::Metadata::mArgs.

constexpr char Attrs[]

Key for Kernel::Metadata::mAttrs.

@ C

The default llvm calling convention, compatible with C.

Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})

Look up the Function declaration of the intrinsic id in the Module M.

Function * getDeclarationIfExists(Module *M, ID id, ArrayRef< Type * > Tys, FunctionType *FT=nullptr)

This version supports overloaded intrinsics.

bool match(Val *V, const Pattern &P)

ValuesClass values(OptsTy... Options)

Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...

initializer< Ty > init(const Ty &Val)

PointerTypeMap run(const Module &M)

Compute the PointerTypeMap for the module M.

@ Assume

Do not drop type tests (default).

DiagnosticInfoOptimizationBase::Argument NV

@ OF_TextWithCRLF

The file should be opened in text mode and use a carriage linefeed '\r '.

uint64_t findLowestOffset(ArrayRef< VirtualCallTarget > Targets, bool IsAfter, uint64_t Size)

void setAfterReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocAfter, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)

void setBeforeReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocBefore, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)

This is an optimization pass for GlobalISel generic memory operations.

auto drop_begin(T &&RangeOrContainer, size_t N=1)

Return a range covering RangeOrContainer with the first N elements excluded.

MemoryEffects computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR)

Returns the memory access properties of this copy of the function.

@ Export

Export information to summary.

@ Import

Import information from summary.

void append_range(Container &C, Range &&R)

Wrapper function to append range R to container C.

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

Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)

Create formatted StringError object.

bool hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO)

int countr_zero(T Val)

Count number of 0's from the least significant bit to the most stopping at the first 1.

void writeIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out, const ModuleToSummariesForIndexTy *ModuleToSummariesForIndex=nullptr, const GVSummaryPtrSet *DecSummaries=nullptr)

Write the specified module summary index to the given raw output stream, where it will be written in ...

Expected< std::unique_ptr< ModuleSummaryIndex > > getModuleSummaryIndex(MemoryBufferRef Buffer)

Parse the specified bitcode buffer, returning the module summary index.

void updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO)

void getVisibleToRegularObjVtableGUIDs(ModuleSummaryIndex &Index, DenseSet< GlobalValue::GUID > &VisibleToRegularObjSymbols, function_ref< bool(StringRef)> IsVisibleToRegularObj)

Based on typeID string, get all associated vtable GUIDS that are visible to regular objects.

decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)

void findDevirtualizableCallsForTypeCheckedLoad(SmallVectorImpl< DevirtCallSite > &DevirtCalls, SmallVectorImpl< Instruction * > &LoadedPtrs, SmallVectorImpl< Instruction * > &Preds, bool &HasNonCallUses, const CallInst *CI, DominatorTree &DT)

Given a call to the intrinsic @llvm.type.checked.load, find all devirtualizable call sites based on t...

CallBase & versionCallSite(CallBase &CB, Value *Callee, MDNode *BranchWeights)

Predicate and clone the given call site.

bool AreStatisticsEnabled()

Check if statistics are enabled.

void updateIndexWPDForExports(ModuleSummaryIndex &Summary, function_ref< bool(StringRef, ValueInfo)> isExported, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap)

Call after cross-module importing to update the recorded single impl devirt target names for any loca...

raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

void runWholeProgramDevirtOnIndex(ModuleSummaryIndex &Summary, std::set< GlobalValue::GUID > &ExportedGUIDs, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap)

Perform index-based whole program devirtualization on the Summary index.

uint64_t alignTo(uint64_t Size, Align A)

Returns a multiple of A needed to store Size bytes.

Expected< T > errorOrToExpected(ErrorOr< T > &&EO)

Convert an ErrorOr to an Expected.

constexpr unsigned BitWidth

Error errorCodeToError(std::error_code EC)

Helper for converting an std::error_code to a Error.

Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)

Split the containing block at the specified instruction - everything before SplitBefore stays in the ...

std::vector< TypeIdOffsetVtableInfo > TypeIdCompatibleVtableInfo

List of vtable definitions decorated by a particular type identifier, and their corresponding offsets...

void consumeError(Error Err)

Consume a Error without doing anything.

void findDevirtualizableCallsForTypeTest(SmallVectorImpl< DevirtCallSite > &DevirtCalls, SmallVectorImpl< CallInst * > &Assumes, const CallInst *CI, DominatorTree &DT)

Given a call to the intrinsic @llvm.type.test, find all devirtualizable call sites based on the call ...

void updateVCallVisibilityInModule(Module &M, bool WholeProgramVisibilityEnabledInLTO, const DenseSet< GlobalValue::GUID > &DynamicExportSymbols, bool ValidateAllVtablesHaveTypeInfos, function_ref< bool(StringRef)> IsVisibleToRegularObj)

If whole program visibility asserted, then upgrade all public vcall visibility metadata on vtable def...

std::pair< Function *, Constant * > getFunctionAtVTableOffset(GlobalVariable *GV, uint64_t Offset, Module &M)

Given a vtable and a specified offset, returns the function and the trivial pointer at the specified ...

void updateVCallVisibilityInIndex(ModuleSummaryIndex &Index, bool WholeProgramVisibilityEnabledInLTO, const DenseSet< GlobalValue::GUID > &DynamicExportSymbols, const DenseSet< GlobalValue::GUID > &VisibleToRegularObjSymbols)

If whole program visibility asserted, then upgrade all public vcall visibility metadata on vtable def...

void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)

Implement std::swap in terms of BitVector swap.

This struct is a compact representation of a valid (non-zero power of two) alignment.

Class to accumulate and hold information about a callee.

static unsigned getHashValue(const VTableSlotSummary &I)

static bool isEqual(const VTableSlotSummary &LHS, const VTableSlotSummary &RHS)

static VTableSlotSummary getTombstoneKey()

static VTableSlotSummary getEmptyKey()

static VTableSlot getTombstoneKey()

static VTableSlot getEmptyKey()

static bool isEqual(const VTableSlot &LHS, const VTableSlot &RHS)

static unsigned getHashValue(const VTableSlot &I)

An information struct used to provide DenseMap with the various necessary components for a given valu...

A call site that could be devirtualized.

A specification for a virtual function call with all constant integer arguments.

An "identifier" for a virtual function.

The following data structures summarize type metadata information.

std::map< uint64_t, WholeProgramDevirtResolution > WPDRes

Mapping from byte offset to whole-program devirt resolution for that (typeid, byte offset) pair.

@ Unsat

Unsatisfiable type (i.e. no global has this type metadata)

enum llvm::TypeTestResolution::Kind TheKind

Struct that holds a reference to a particular GUID in a global value summary.

ArrayRef< std::unique_ptr< GlobalValueSummary > > getSummaryList() const

PreservedAnalyses run(Module &M, ModuleAnalysisManager &)

@ UniformRetVal

Uniform return value optimization.

@ VirtualConstProp

Virtual constant propagation.

@ UniqueRetVal

Unique return value optimization.

uint64_t Info

Additional information for the resolution:

enum llvm::WholeProgramDevirtResolution::ByArg::Kind TheKind

enum llvm::WholeProgramDevirtResolution::Kind TheKind

std::map< std::vector< uint64_t >, ByArg > ResByArg

Resolutions for calls with all constant integer arguments (excluding the first argument,...

std::string SingleImplName

@ SingleImpl

Single implementation devirtualization.

@ BranchFunnel

When retpoline mitigation is enabled, use a branch funnel that is defined in the merged module.

VirtualCallTarget(GlobalValue *Fn, const TypeMemberInfo *TM)