126#define DEBUG_TYPE "wholeprogramdevirt"
128STATISTIC(NumDevirtTargets,
"Number of whole program devirtualization targets");
129STATISTIC(NumSingleImpl,
"Number of single implementation devirtualizations");
131STATISTIC(NumUniformRetVal,
"Number of uniform return value optimizations");
132STATISTIC(NumUniqueRetVal,
"Number of unique return value optimizations");
134 "Number of 1 bit virtual constant propagations");
135STATISTIC(NumVirtConstProp,
"Number of virtual constant propagations");
137 "Controls how many calls should be devirtualized.");
143 cl::desc(
"Print index-based devirtualization messages"));
151 cl::desc(
"Enable whole program visibility"));
156 "disable-whole-program-visibility",
cl::Hidden,
157 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
162 cl::desc(
"Prevent function(s) from being devirtualized"),
185 "wholeprogramdevirt-keep-unreachable-function",
186 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
191 std::vector<GlobPattern> Patterns;
192 template <
class T>
void init(
const T &StringList) {
193 for (
const auto &S : StringList)
195 Patterns.push_back(std::move(*Pat));
197 bool match(StringRef S) {
198 for (
const GlobPattern &
P : Patterns)
211 bool IsAfter, uint64_t
Size) {
213 uint64_t MinByte = 0;
216 MinByte = std::max(MinByte,
Target.minAfterBytes());
218 MinByte = std::max(MinByte,
Target.minBeforeBytes());
241 std::vector<ArrayRef<uint8_t>> Used;
244 :
Target.TM->Bits->Before.BytesUsed;
245 uint64_t
Offset = IsAfter ? MinByte -
Target.minAfterBytes()
246 : MinByte -
Target.minBeforeBytes();
256 for (
unsigned I = 0;; ++
I) {
258 for (
auto &&
B : Used)
261 if (BitsUsed != 0xff)
267 for (
unsigned I = 0;; ++
I) {
268 for (
auto &&
B : Used) {
270 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
286 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
288 OffsetByte = -(AllocBefore / 8 + 1);
290 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
291 OffsetBit = AllocBefore % 8;
295 Target.setBeforeBit(AllocBefore);
303 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
305 OffsetByte = AllocAfter / 8;
307 OffsetByte = (AllocAfter + 7) / 8;
308 OffsetBit = AllocAfter % 8;
312 Target.setAfterBit(AllocAfter);
341 const VTableSlot &RHS) {
342 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
353 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
377 if (!Summary->isLive())
380 if (!FS->fflags().MustBeUnreachable)
395struct VirtualCallSite {
402 unsigned *NumUnsafeUses =
nullptr;
405 emitRemark(
const StringRef OptName,
const StringRef TargetName,
406 function_ref<OptimizationRemarkEmitter &(
Function &)> OREGetter) {
412 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE, OptName, DLoc,
Block)
413 <<
NV(
"Optimization", OptName)
414 <<
": devirtualized a call to "
415 <<
NV(
"FunctionName", TargetName));
418 void replaceAndErase(
419 const StringRef OptName,
const StringRef TargetName,
bool RemarksEnabled,
420 function_ref<OptimizationRemarkEmitter &(
Function &)> OREGetter,
427 II->getUnwindDest()->removePredecessor(
II->getParent());
444 std::vector<VirtualCallSite> CallSites;
453 bool AllCallSitesDevirted =
true;
462 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
466 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
468 bool isExported()
const {
469 return !SummaryTypeCheckedLoadUsers.empty() ||
470 !SummaryTypeTestAssumeUsers.empty();
473 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
474 SummaryTypeCheckedLoadUsers.push_back(FS);
475 AllCallSitesDevirted =
false;
478 void addSummaryTypeTestAssumeUser(FunctionSummary *FS) {
479 SummaryTypeTestAssumeUsers.push_back(FS);
480 AllCallSitesDevirted =
false;
483 void markDevirt() { AllCallSitesDevirted =
true; }
487struct VTableSlotInfo {
494 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
496 void addCallSite(
Value *VTable, CallBase &CB,
unsigned *NumUnsafeUses);
502CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) {
503 std::vector<uint64_t>
Args;
505 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
509 if (!CI || CI->getBitWidth() > 64)
511 Args.push_back(CI->getZExtValue());
513 return ConstCSInfo[
Args];
516void VTableSlotInfo::addCallSite(
Value *VTable, CallBase &CB,
517 unsigned *NumUnsafeUses) {
518 auto &CSI = findCallSiteInfo(CB);
519 CSI.AllCallSitesDevirted =
false;
520 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
524 const IPOOptions &Opts;
529 ModuleSummaryIndex *
const ExportSummary;
530 const ModuleSummaryIndex *
const ImportSummary;
532 IntegerType *
const Int8Ty;
534 IntegerType *
const Int32Ty;
535 IntegerType *
const Int64Ty;
542 const bool RemarksEnabled;
543 std::function<OptimizationRemarkEmitter &(
Function &)> OREGetter;
544 MapVector<VTableSlot, VTableSlotInfo> CallSlots;
549 SmallPtrSet<CallBase *, 8> OptimizedCalls;
563 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
564 PatternList FunctionsToSkip;
566 const bool DevirtSpeculatively;
568 ModuleSummaryIndex *ExportSummary,
569 const ModuleSummaryIndex *ImportSummary,
570 bool DevirtSpeculatively)
573 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
580 RemarksEnabled(areRemarksEnabled()),
581 OREGetter([&](
Function &
F) -> OptimizationRemarkEmitter & {
584 DevirtSpeculatively(DevirtSpeculatively) {
585 assert(!(ExportSummary && ImportSummary));
589 bool areRemarksEnabled();
592 scanTypeTestUsers(
Function *TypeTestFunc,
593 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
594 void scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc);
596 void buildTypeIdentifierMap(
597 std::vector<VTableBits> &Bits,
598 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
601 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
602 const std::set<TypeMemberInfo> &TypeMemberInfos,
604 ModuleSummaryIndex *ExportSummary);
606 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
608 bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
610 VTableSlotInfo &SlotInfo,
611 WholeProgramDevirtResolution *Res);
613 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Function &JT,
616 VTableSlotInfo &SlotInfo,
617 WholeProgramDevirtResolution *Res, VTableSlot Slot);
619 bool tryEvaluateFunctionsWithArgs(
621 ArrayRef<uint64_t> Args);
623 void applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
627 WholeProgramDevirtResolution::ByArg *Res);
631 std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
634 bool shouldExportConstantsAsAbsoluteSymbols();
639 void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
641 void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
642 uint32_t Const, uint32_t &Storage);
646 Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
648 Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
649 StringRef Name, IntegerType *IntTy,
652 Constant *getMemberAddr(
const TypeMemberInfo *M);
654 void applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
bool IsOne,
655 Constant *UniqueMemberAddr);
656 bool tryUniqueRetValOpt(
unsigned BitWidth,
659 WholeProgramDevirtResolution::ByArg *Res,
660 VTableSlot Slot, ArrayRef<uint64_t> Args);
662 void applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
663 Constant *Byte, Constant *Bit);
665 VTableSlotInfo &SlotInfo,
666 WholeProgramDevirtResolution *Res, VTableSlot Slot);
668 void rebuildGlobal(VTableBits &
B);
671 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
675 void removeRedundantTypeTests();
682 static ValueInfo lookUpFunctionValueInfo(
Function *TheFn,
683 ModuleSummaryIndex *ExportSummary);
694 ModuleSummaryIndex *ExportSummary);
702 ModuleSummaryIndex &ExportSummary;
705 std::set<GlobalValue::GUID> &ExportedGUIDs;
709 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
714 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr;
716 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
718 PatternList FunctionsToSkip;
721 ModuleSummaryIndex &ExportSummary,
722 std::set<GlobalValue::GUID> &ExportedGUIDs,
723 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
724 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr)
725 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
726 LocalWPDTargetsMap(LocalWPDTargetsMap),
727 ExternallyVisibleSymbolNamesPtr(ExternallyVisibleSymbolNamesPtr) {
731 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
736 VTableSlotSummary &SlotSummary,
737 VTableSlotInfo &SlotInfo,
738 WholeProgramDevirtResolution *Res,
739 std::set<ValueInfo> &DevirtTargets);
748 if (!DevirtModule::runForTesting(M,
MAM))
753 std::optional<ModuleSummaryIndex> Index;
757 "ExportSummary is expected to be empty in non-LTO mode");
760 ExportSummary = Index.has_value() ? &Index.value() :
nullptr;
781 if (
TypeID.ends_with(
".virtual"))
787 if (!
TypeID.consume_front(
"_ZTS"))
795 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
796 return IsVisibleToRegularObj(TypeInfo);
805 for (
auto *
Type : Types)
808 IsVisibleToRegularObj);
817 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
819 bool ValidateAllVtablesHaveTypeInfos,
837 !(ValidateAllVtablesHaveTypeInfos &&
844 bool WholeProgramVisibilityEnabledInLTO) {
848 if (!PublicTypeTestFunc)
856 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
858 CI->replaceAllUsesWith(NewCI);
859 CI->eraseFromParent();
867 CI->replaceAllUsesWith(
True);
868 CI->eraseFromParent();
879 for (
const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
882 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
895 for (
auto &
P : Index) {
898 if (DynamicExportSymbols.
count(
P.first))
904 if (VisibleToRegularObjSymbols.
count(
P.first))
906 for (
auto &S :
P.second.getSummaryList()) {
918 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
920 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap,
921 ExternallyVisibleSymbolNamesPtr)
928 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
930 for (
auto &
T : LocalWPDTargetsMap) {
933 assert(VI.getSummaryList().size() == 1 &&
934 "Devirt of local target has more than one copy");
935 auto &S = VI.getSummaryList()[0];
936 if (!IsExported(S->modulePath(), VI))
940 for (
auto &SlotSummary :
T.second) {
941 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
943 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
944 assert(WPDRes != TIdSum->WPDRes.end());
945 if (ExternallyVisibleSymbolNamesPtr)
946 ExternallyVisibleSymbolNamesPtr->
insert(WPDRes->second.SingleImplName);
948 WPDRes->second.SingleImplName,
949 Summary.getModuleHash(S->modulePath()));
960 const auto &ModPaths = Summary->modulePaths();
965 "combined summary should contain Regular LTO module");
971 StringRef ReadSummary = Opts.wholeprogramdevirt_read_summary;
972 StringRef WriteSummary = Opts.wholeprogramdevirt_write_summary;
974 std::unique_ptr<ModuleSummaryIndex>
Summary =
975 std::make_unique<ModuleSummaryIndex>(
false);
979 if (!ReadSummary.
empty()) {
980 ExitOnError ExitOnErr(
981 (
"-wholeprogramdevirt-read-summary: " + ReadSummary +
": ").str());
982 auto ReadSummaryFile =
984 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
986 Summary = std::move(*SummaryOrErr);
991 yaml::Input
In(ReadSummaryFile->getBuffer());
1002 Opts.devirtualize_speculatively)
1005 if (!WriteSummary.
empty()) {
1006 ExitOnError ExitOnErr(
1007 (
"-wholeprogramdevirt-write-summary: " + WriteSummary +
": ").str());
1016 yaml::Output
Out(OS);
1024void DevirtModule::buildTypeIdentifierMap(
1025 std::vector<VTableBits> &Bits,
1026 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1027 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1028 Bits.reserve(
M.global_size());
1030 for (GlobalVariable &GV :
M.globals()) {
1038 Bits.emplace_back();
1039 Bits.back().GV = &GV;
1040 Bits.back().ObjectSize =
1042 BitsPtr = &
Bits.back();
1045 for (MDNode *
Type : Types) {
1058bool DevirtModule::tryFindVirtualCallTargets(
1059 std::vector<VirtualCallTarget> &TargetsForSlot,
1060 const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset,
1061 ModuleSummaryIndex *ExportSummary) {
1063 if (!TM.Bits->GV->isConstant())
1068 if (!DevirtSpeculatively && TM.Bits->GV->getVCallVisibility() ==
1074 if (TM.Bits->GV->hasLocalLinkage() && TM.Bits->GV->hasZeroLiveUses())
1085 if (FunctionsToSkip.match(Fn->
getName()))
1090 if (Fn->
getName() ==
"__cxa_pure_virtual")
1109 if (!GA->isInterposable() && !GA->getAliaseeObject()->isInterposable())
1111 TargetsForSlot.push_back({GV, &TM});
1115 return !TargetsForSlot.empty();
1118bool DevirtIndex::tryFindVirtualCallTargets(
1119 std::vector<ValueInfo> &TargetsForSlot,
1121 for (
const TypeIdOffsetVtableInfo &
P : TIdInfo) {
1132 if (
P.VTableVI.hasLocal() &&
P.VTableVI.getSummaryList().size() > 1)
1134 const GlobalVarSummary *
VS =
nullptr;
1135 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1137 if (!CurVS->vTableFuncs().empty() ||
1160 for (
auto VTP :
VS->vTableFuncs()) {
1161 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1167 TargetsForSlot.push_back(VTP.FuncVI);
1172 return !TargetsForSlot.empty();
1175void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1176 Constant *TheFn,
bool &IsExported) {
1182 for (
auto &&VCallSite : CSInfo.CallSites) {
1183 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1191 VCallSite.emitRemark(
"single-impl",
1194 auto &CB = VCallSite.CB;
1207 MDBuilder(
M.getContext()).createUnlikelyBranchWeights());
1208 Builder.SetInsertPoint(ThenTerm);
1211 auto *CallTrap = Builder.CreateCall(TrapFn);
1220 DevirtSpeculatively) {
1221 MDNode *Weights = MDBuilder(
M.getContext()).createLikelyBranchWeights();
1230 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1231 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1253 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1258 if (VCallSite.NumUnsafeUses)
1259 --*VCallSite.NumUnsafeUses;
1261 if (CSInfo.isExported())
1263 CSInfo.markDevirt();
1265 Apply(SlotInfo.CSInfo);
1266 for (
auto &
P : SlotInfo.ConstCSInfo)
1272 if (Callee.getSummaryList().empty())
1279 bool IsExported =
false;
1280 auto &S = Callee.getSummaryList()[0];
1282 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1283 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1284 FS->addCall({Callee, CI});
1285 IsExported |= S->modulePath() != FS->modulePath();
1287 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1288 FS->addCall({Callee, CI});
1289 IsExported |= S->modulePath() != FS->modulePath();
1292 AddCalls(SlotInfo.CSInfo);
1293 for (
auto &
P : SlotInfo.ConstCSInfo)
1298bool DevirtModule::trySingleImplDevirt(
1299 ModuleSummaryIndex *ExportSummary,
1301 WholeProgramDevirtResolution *Res) {
1304 auto *TheFn = TargetsForSlot[0].Fn;
1305 for (
auto &&Target : TargetsForSlot)
1311 TargetsForSlot[0].WasDevirt =
true;
1313 bool IsExported =
false;
1314 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1321 if (TheFn->hasLocalLinkage()) {
1322 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1327 if (Comdat *
C = TheFn->getComdat()) {
1328 if (
C->getName() == TheFn->
getName()) {
1329 Comdat *NewC =
M.getOrInsertComdat(NewName);
1331 for (GlobalObject &GO :
M.global_objects())
1332 if (GO.getComdat() ==
C)
1341 if (ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFn->getGUID()))
1353 VTableSlotSummary &SlotSummary,
1354 VTableSlotInfo &SlotInfo,
1355 WholeProgramDevirtResolution *Res,
1356 std::set<ValueInfo> &DevirtTargets) {
1359 auto TheFn = TargetsForSlot[0];
1360 for (
auto &&Target : TargetsForSlot)
1361 if (TheFn != Target)
1365 auto Size = TheFn.getSummaryList().size();
1371 if (FunctionsToSkip.match(TheFn.name()))
1376 if (TheFn.hasLocal() &&
Size > 1)
1381 DevirtTargets.insert(TheFn);
1383 auto &S = TheFn.getSummaryList()[0];
1384 bool IsExported =
addCalls(SlotInfo, TheFn);
1386 ExportedGUIDs.insert(TheFn.getGUID());
1396 if (ExternallyVisibleSymbolNamesPtr)
1397 ExternallyVisibleSymbolNamesPtr->insert(TheFn.name());
1399 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1401 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1415void DevirtModule::tryICallBranchFunnel(
1417 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1418 Triple
T(
M.getTargetTriple());
1422 if (TargetsForSlot.
size() > Opts.wholeprogramdevirt_branch_funnel_threshold)
1425 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1427 for (
auto &
P : SlotInfo.ConstCSInfo)
1428 if (!
P.second.AllCallSitesDevirted) {
1429 HasNonDevirt =
true;
1447 for (
auto &
T : TargetsForSlot) {
1448 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1457 M.getDataLayout().getProgramAddressSpace(),
1458 getGlobalName(Slot, {},
"branch_funnel"), &
M);
1462 M.getDataLayout().getProgramAddressSpace(),
1463 "branch_funnel", &M);
1467 std::vector<Value *> JTArgs;
1469 for (
auto &
T : TargetsForSlot) {
1470 JTArgs.push_back(getMemberAddr(
T.TM));
1471 JTArgs.push_back(
T.Fn);
1476 &M, llvm::Intrinsic::icall_branch_funnel, {});
1482 bool IsExported =
false;
1483 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1493void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1495 DenseMap<Function *, double> FunctionEntryCounts;
1497 if (CSInfo.isExported())
1499 if (CSInfo.AllCallSitesDevirted)
1502 std::map<CallBase *, CallBase *> CallBases;
1503 for (
auto &&VCallSite : CSInfo.CallSites) {
1504 CallBase &CB = VCallSite.CB;
1506 if (CallBases.find(&CB) != CallBases.end()) {
1523 VCallSite.emitRemark(
"branch-funnel", JT.
getName(), OREGetter);
1527 std::vector<Type *> NewArgs;
1528 NewArgs.push_back(Int8PtrTy);
1530 FunctionType *NewFT =
1534 std::vector<Value *>
Args;
1535 Args.push_back(VCallSite.VTable);
1538 CallBase *NewCS =
nullptr;
1544 auto EC = BFI.getBlockFreq(&
F.getEntryBlock());
1545 auto CC =
F.getEntryCount();
1546 double CallCount = 0.0;
1547 if (
EC.getFrequency() != 0 &&
CC && *
CC != 0) {
1549 static_cast<double>(
1550 BFI.getBlockFreq(CB.
getParent()).getFrequency()) /
1552 CallCount = CallFreq * *
CC;
1554 FunctionEntryCounts[&JT] += CallCount;
1557 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1565 std::vector<AttributeSet> NewArgAttrs;
1568 M.getContext(), Attribute::Nest)}));
1569 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1570 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1572 AttributeList::get(
M.getContext(),
Attrs.getFnAttrs(),
1573 Attrs.getRetAttrs(), NewArgAttrs));
1575 CallBases[&CB] = NewCS;
1578 if (VCallSite.NumUnsafeUses)
1579 --*VCallSite.NumUnsafeUses;
1586 for (
auto &[Old, New] : CallBases) {
1587 Old->replaceAllUsesWith(New);
1588 Old->eraseFromParent();
1591 Apply(SlotInfo.CSInfo);
1592 for (
auto &
P : SlotInfo.ConstCSInfo)
1594 for (
auto &[
F,
C] : FunctionEntryCounts) {
1596 "Unexpected entry count for funnel that was freshly synthesized");
1597 F->setEntryCount(
static_cast<uint64_t>(std::round(
C)));
1601bool DevirtModule::tryEvaluateFunctionsWithArgs(
1603 ArrayRef<uint64_t> Args) {
1617 Evaluator Eval(
M.getDataLayout(),
nullptr);
1621 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1626 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1630 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1638void DevirtModule::applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1640 for (
auto Call : CSInfo.CallSites) {
1644 Call.replaceAndErase(
1645 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1648 CSInfo.markDevirt();
1651bool DevirtModule::tryUniformRetValOpt(
1653 WholeProgramDevirtResolution::ByArg *Res) {
1656 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1658 if (
Target.RetVal != TheRetVal)
1661 if (CSInfo.isExported()) {
1663 Res->
Info = TheRetVal;
1666 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1668 for (
auto &&Target : TargetsForSlot)
1673std::string DevirtModule::getGlobalName(VTableSlot Slot,
1674 ArrayRef<uint64_t> Args,
1676 std::string FullName =
"__typeid_";
1677 raw_string_ostream OS(FullName);
1678 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1685bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1686 Triple
T(
M.getTargetTriple());
1690void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1691 StringRef Name, Constant *
C) {
1693 getGlobalName(Slot, Args, Name),
C, &M);
1697void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1698 StringRef Name, uint32_t Const,
1699 uint32_t &Storage) {
1700 if (shouldExportConstantsAsAbsoluteSymbols()) {
1710Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1712 GlobalVariable *GV =
1713 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1718Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1719 StringRef Name, IntegerType *IntTy,
1721 if (!shouldExportConstantsAsAbsoluteSymbols())
1722 return ConstantInt::get(IntTy, Storage);
1724 Constant *
C = importGlobal(Slot, Args, Name);
1730 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1740 if (AbsWidth ==
IntPtrTy->getBitWidth()) {
1744 SetAbsRange(0, 1ull << AbsWidth);
1749void DevirtModule::applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1751 Constant *UniqueMemberAddr) {
1752 for (
auto &&
Call : CSInfo.CallSites) {
1758 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->
getType()));
1761 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1764 CSInfo.markDevirt();
1769 ConstantInt::get(Int64Ty,
M->Offset));
1772bool DevirtModule::tryUniqueRetValOpt(
1774 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1775 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1777 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1780 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1783 UniqueMember =
Target.TM;
1791 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1792 if (CSInfo.isExported()) {
1796 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1800 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1805 for (
auto &&Target : TargetsForSlot)
1812 if (tryUniqueRetValOptFor(
true))
1814 if (tryUniqueRetValOptFor(
false))
1820void DevirtModule::applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
1821 Constant *Byte, Constant *Bit) {
1822 for (
auto Call : CSInfo.CallSites) {
1827 Value *Addr =
B.CreatePtrAddWithSExtOrTrunc(
Call.VTable, Byte);
1828 if (RetType->getBitWidth() == 1) {
1830 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1831 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1832 NumVirtConstProp1Bit++;
1833 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1834 OREGetter, IsBitSet);
1836 Value *Val =
B.CreateLoad(RetType, Addr);
1838 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1842 CSInfo.markDevirt();
1845bool DevirtModule::tryVirtualConstProp(
1847 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1858 unsigned BitWidth = RetType->getBitWidth();
1870 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1903 GlobalVariable *GV =
Target.TM->Bits->GV;
1904 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1906 if (TypeAlignment > TableAlignment)
1910 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1911 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1914 WholeProgramDevirtResolution::ByArg *ResByArg =
nullptr;
1916 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1918 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1921 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1922 ResByArg, Slot, CSByConstantArg.first))
1937 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1938 for (
auto &&Target : TargetsForSlot) {
1939 TotalPaddingBefore += std::max<int64_t>(
1940 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1941 TotalPaddingAfter += std::max<int64_t>(
1942 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1947 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1954 if (TotalPaddingBefore <= TotalPaddingAfter)
1970 for (
auto &&Target : TargetsForSlot)
1974 if (CSByConstantArg.second.isExported()) {
1976 ResByArg->
Byte = OffsetByte;
1977 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
1983 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
1984 applyVirtualConstProp(CSByConstantArg.second,
1985 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
1991 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
1997 B.GV->getAlign(),
B.GV->getValueType());
1998 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
2001 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
2008 B.GV->getInitializer(),
2011 new GlobalVariable(M, NewInit->getType(),
B.GV->isConstant(),
2013 NewGV->setSection(
B.GV->getSection());
2014 NewGV->setComdat(
B.GV->getComdat());
2015 NewGV->setAlignment(
B.GV->getAlign());
2019 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
2024 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2026 M.getDataLayout(), NewInit->getType(), NewGV,
2027 {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 1)},
2030 Alias->setVisibility(
B.GV->getVisibility());
2031 Alias->takeName(
B.GV);
2033 B.GV->replaceAllUsesWith(Alias);
2034 B.GV->eraseFromParent();
2037bool DevirtModule::areRemarksEnabled() {
2038 const auto &FL =
M.getFunctionList();
2043 return DI.isEnabled();
2073 if (
Value *
Merge = GetMergeUser(U, &TypeTest))
2076 while (!Worklist.
empty()) {
2078 if (!VisitedMerges.
insert(
V).second)
2081 for (
User *U :
V->users()) {
2083 if (Assume->getArgOperand(0) ==
V) {
2085 "assume must not be both direct and merged");
2097void DevirtModule::scanTypeTestUsers(
2099 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2102 SmallPtrSet<Value *, 8> VisitedMerges;
2117 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2123 if (!Assumes.
empty()) {
2124 Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();
2125 for (DevirtCallSite
Call : DevirtCalls)
2126 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
nullptr);
2129 auto RemoveTypeTestAssumes = [&]() {
2137 for (
auto *Assume : Assumes)
2138 Assume->eraseFromParent();
2141 if (CI->use_empty())
2142 CI->eraseFromParent();
2157 if (!TypeIdMap.count(TypeId))
2158 RemoveTypeTestAssumes();
2170 const TypeIdSummary *TidSummary =
2173 RemoveTypeTestAssumes();
2182void DevirtModule::scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc) {
2191 Value *Ptr = CI->getArgOperand(0);
2193 Value *TypeIdValue = CI->getArgOperand(2);
2199 bool HasNonCallUses =
false;
2200 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2202 HasNonCallUses, CI, DT);
2211 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2213 Value *LoadedValue =
nullptr;
2215 Intrinsic::type_checked_load_relative) {
2217 &M, Intrinsic::load_relative, {Int32Ty});
2218 LoadedValue = LoadB.CreateCall(LoadRelFunc, {Ptr,
Offset});
2221 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2224 for (Instruction *LoadedPtr : LoadedPtrs) {
2225 LoadedPtr->replaceAllUsesWith(LoadedValue);
2226 LoadedPtr->eraseFromParent();
2230 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2231 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {Ptr, TypeIdValue});
2233 for (Instruction *
Pred : Preds) {
2234 Pred->replaceAllUsesWith(TypeTestCall);
2235 Pred->eraseFromParent();
2242 if (!CI->use_empty()) {
2245 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2246 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2251 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2252 NumUnsafeUses = DevirtCalls.
size();
2259 for (DevirtCallSite
Call : DevirtCalls) {
2260 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
2264 CI->eraseFromParent();
2268void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2272 const TypeIdSummary *TidSummary =
2276 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2277 if (ResI == TidSummary->
WPDRes.end())
2279 const WholeProgramDevirtResolution &Res = ResI->second;
2285 Value *SingleImplVal =
2290 if (!
A->isInterposable() && !
A->getAliaseeObject()->isInterposable())
2291 SingleImplVal =
A->getAliaseeObject();
2295 bool IsExported =
false;
2296 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2300 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2301 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2304 auto &ResByArg =
I->second;
2311 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2315 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2316 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2322 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2324 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2336 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2339 bool IsExported =
false;
2340 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2345void DevirtModule::removeRedundantTypeTests() {
2347 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2348 if (
U.second == 0) {
2349 U.first->replaceAllUsesWith(
True);
2350 U.first->eraseFromParent();
2356DevirtModule::lookUpFunctionValueInfo(
Function *TheFn,
2357 ModuleSummaryIndex *ExportSummary) {
2358 assert((ExportSummary !=
nullptr) &&
2359 "Caller guarantees ExportSummary is not nullptr");
2361 const auto TheFnGUID = TheFn->
getGUID();
2362 const auto TheFnGUIDWithExportedName =
2365 ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFnGUID);
2374 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2375 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2380bool DevirtModule::mustBeUnreachableFunction(
2381 Function *
const F, ModuleSummaryIndex *ExportSummary) {
2385 if (!
F->isDeclaration()) {
2391 return ExportSummary &&
2393 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2396bool DevirtModule::run() {
2405 Function *PublicTypeTestFunc =
nullptr;
2408 if (DevirtSpeculatively)
2409 PublicTypeTestFunc =
2416 &M, Intrinsic::type_checked_load_relative);
2423 if (!ExportSummary &&
2424 (((!PublicTypeTestFunc || PublicTypeTestFunc->
use_empty()) &&
2425 (!TypeTestFunc || TypeTestFunc->
use_empty())) ||
2426 !AssumeFunc || AssumeFunc->
use_empty()) &&
2427 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2428 (!TypeCheckedLoadRelativeFunc ||
2429 TypeCheckedLoadRelativeFunc->
use_empty()))
2433 std::vector<VTableBits>
Bits;
2434 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2435 buildTypeIdentifierMap(Bits, TypeIdMap);
2437 if (PublicTypeTestFunc && AssumeFunc)
2438 scanTypeTestUsers(PublicTypeTestFunc, TypeIdMap);
2440 if (TypeTestFunc && AssumeFunc)
2441 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2443 if (TypeCheckedLoadFunc)
2444 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2446 if (TypeCheckedLoadRelativeFunc)
2447 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2449 if (ImportSummary) {
2450 for (
auto &S : CallSlots)
2451 importResolution(S.first, S.second);
2453 removeRedundantTypeTests();
2458 for (GlobalVariable &GV :
M.globals())
2466 if (TypeIdMap.
empty())
2470 if (ExportSummary) {
2471 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2472 for (
auto &
P : TypeIdMap) {
2475 TypeId->getString())]
2479 for (
auto &
P : *ExportSummary) {
2480 for (
auto &S :
P.second.getSummaryList()) {
2485 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2486 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2487 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2490 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2491 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2492 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2495 for (
const FunctionSummary::ConstVCall &VC :
2496 FS->type_test_assume_const_vcalls()) {
2497 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2498 CallSlots[{MD,
VC.VFunc.Offset}]
2499 .ConstCSInfo[
VC.Args]
2500 .addSummaryTypeTestAssumeUser(FS);
2503 for (
const FunctionSummary::ConstVCall &VC :
2504 FS->type_checked_load_const_vcalls()) {
2505 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2506 CallSlots[{MD,
VC.VFunc.Offset}]
2507 .ConstCSInfo[
VC.Args]
2508 .addSummaryTypeCheckedLoadUser(FS);
2516 bool DidVirtualConstProp =
false;
2517 std::map<std::string, GlobalValue *> DevirtTargets;
2518 for (
auto &S : CallSlots) {
2522 std::vector<VirtualCallTarget> TargetsForSlot;
2523 WholeProgramDevirtResolution *Res =
nullptr;
2524 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2526 TypeMemberInfos.size())
2533 Res = &ExportSummary
2534 ->getOrInsertTypeIdSummary(
2536 .WPDRes[S.first.ByteOffset];
2537 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2538 S.first.ByteOffset, ExportSummary)) {
2539 bool SingleImplDevirt =
2540 trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res);
2544 if (!SingleImplDevirt && !DevirtSpeculatively) {
2545 DidVirtualConstProp |=
2546 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2548 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2553 for (
const auto &
T : TargetsForSlot)
2555 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2565 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2566 if (!CSI.AllCallSitesDevirted)
2567 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2568 FS->addTypeTest(GUID);
2570 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2571 for (
auto &CCS : S.second.ConstCSInfo)
2572 AddTypeTestsForTypeCheckedLoads(CCS.second);
2576 if (RemarksEnabled) {
2578 for (
const auto &DT : DevirtTargets) {
2579 GlobalValue *GV = DT.second;
2588 using namespace ore;
2589 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE,
"Devirtualized",
F)
2590 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2594 NumDevirtTargets += DevirtTargets.size();
2596 removeRedundantTypeTests();
2600 if (DidVirtualConstProp)
2607 for (GlobalVariable &GV :
M.globals())
2610 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2611 CI->eraseFromParent();
2616void DevirtIndex::run() {
2617 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2622 assert(!ExportSummary.withInternalizeAndPromote() &&
2623 "Expect index-based WPD to run before internalization and promotion");
2625 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2626 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2635 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2639 for (
auto &
P : ExportSummary) {
2640 for (
auto &S :
P.second.getSummaryList()) {
2645 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2646 for (StringRef Name : NameByGUID[VF.GUID]) {
2647 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2650 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2651 for (StringRef Name : NameByGUID[VF.GUID]) {
2652 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2655 for (
const FunctionSummary::ConstVCall &VC :
2656 FS->type_test_assume_const_vcalls()) {
2657 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2658 CallSlots[{
Name,
VC.VFunc.Offset}]
2659 .ConstCSInfo[
VC.Args]
2660 .addSummaryTypeTestAssumeUser(FS);
2663 for (
const FunctionSummary::ConstVCall &VC :
2664 FS->type_checked_load_const_vcalls()) {
2665 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2666 CallSlots[{
Name,
VC.VFunc.Offset}]
2667 .ConstCSInfo[
VC.Args]
2668 .addSummaryTypeCheckedLoadUser(FS);
2674 std::set<ValueInfo> DevirtTargets;
2676 for (
auto &S : CallSlots) {
2680 std::vector<ValueInfo> TargetsForSlot;
2681 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2685 WholeProgramDevirtResolution *Res =
2686 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2687 ->WPDRes[S.first.ByteOffset];
2688 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2689 S.first.ByteOffset)) {
2691 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2700 for (
const auto &DT : DevirtTargets)
2701 errs() <<
"Devirtualized call to " << DT <<
"\n";
2703 NumDevirtTargets += DevirtTargets.size();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This is the interface for LLVM's primary stateless and local alias analysis.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
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.
This header defines various interfaces for pass management in LLVM.
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
static bool mustBeUnreachableFunction(const Function &F)
This is the interface to build a ModuleSummaryIndex for a module.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
This file contains the declarations for profiling metadata utility functions.
SmallVector< MachineOperand, 4 > Cond
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
This file defines the SmallPtrSet class.
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 void findAssumesThroughMergesForTypeTest(SmallVectorImpl< CallInst * > &Assumes, CallInst &TypeTest, SmallPtrSetImpl< Value * > &VisitedMerges)
Find assumes whose conditions depend on this type test through phi or select nodes.
static bool typeIDVisibleToRegularObj(StringRef TypeID, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static bool addCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee)
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 bool skipUpdateDueToValidation(GlobalVariable &GV, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static Error checkCombinedSummaryForTesting(const IPOOptions &Opts, ModuleSummaryIndex *Summary)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
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 LLVM_ABI AttributeSet get(LLVMContext &C, const AttrBuilder &B)
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
bool isValid() const
Return true if the attribute is any kind of attribute.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
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 LLVM_ABI 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.
LLVM_ABI 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 LLVM_ABI Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getPtrAdd(Constant *Ptr, Constant *Offset, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReduced=nullptr)
Create a getelementptr i8, ptr, offset constant expression.
static LLVM_ABI Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static LLVM_SUPPRESS_DEPRECATED_DECLARATIONS_PUSH 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 LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
static Constant * getAnon(ArrayRef< Constant * > V, bool Packed=false)
Return an anonymous struct that has the specified elements.
const Constant * stripPointerCasts() const
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
static bool shouldExecute(CounterInfo &Counter)
Implements a dense probed hash-table based set.
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.
Tagged union holding either a T or a Error.
Type * getParamType(unsigned i) const
Parameter type accessors.
ArrayRef< Type * > params() const
Type * getReturnType() const
static LLVM_ABI 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...
std::optional< uint64_t > getEntryCount() const
Get the entry count for this function.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
adds the attribute to the list of attributes for the given arg.
Type * getReturnType() const
Returns the type of the ret val.
unsigned getInstructionCount() const
Returns the number of non-debug IR instructions in this function.
static GEPNoWrapFlags inBounds()
static LLVM_ABI Expected< GlobPattern > create(StringRef Pat, std::optional< size_t > MaxSubPatterns={}, bool SlashAgnostic=false)
static LLVM_ABI 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...
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
bool hasMetadata() const
Return true if this GlobalObject has any metadata attached to it.
LLVM_ABI VCallVisibility getVCallVisibility() const
LLVM_ABI bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
@ VCallVisibilityLinkageUnit
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this GlobalObject.
LLVM_ABI void setVCallVisibilityMetadata(VCallVisibility Visibility)
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
static bool isLocalLinkage(LinkageTypes Linkage)
LLVM_ABI 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)
LLVM_ABI const GlobalObject * getAliaseeObject() const
LLVM_ABI GUID getGUID() const
Return a 64-bit global unique ID for this value.
@ 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.
Type * getValueType() const
LLVM_ABI bool isInterposable(bool CheckNoIPA=true) const
Return true if this global's definition can be substituted with an arbitrary definition at link time ...
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
MaybeAlign getAlign() const
Returns the alignment of the given variable.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
iterator_range< user_iterator > users()
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
uint64_t getBitMask() const
Return a bitmask with ones set for all of the bits that can be set by an unsigned version of this typ...
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
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,...
bool doesNotAccessMemory() const
Whether this function accesses no memory.
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.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
static LLVM_ABI 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.
Analysis providing profile information.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
constexpr bool empty() const
Check if the string is empty.
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
bool ends_with(StringRef Suffix) const
Check if this string ends with the given Suffix.
Target - Wrapper for Target specific information.
The TimeTraceScope is a helper class to call the begin and end functions of the time trace profiler.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
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.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
LLVM_ABI bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
iterator_range< use_iterator > uses()
LLVM_ABI 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()
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ BasicBlock
Various leaf nodes.
LLVM_ABI Function * getDeclarationIfExists(const Module *M, ID id)
Look up the Function declaration of the intrinsic id in the Module M and return it if it exists.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
DiagnosticInfoOptimizationBase::Argument NV
friend class Instruction
Iterator for Instructions in a `BasicBlock.
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
LLVM_ABI uint64_t findLowestOffset(ArrayRef< VirtualCallTarget > Targets, bool IsAfter, uint64_t Size)
LLVM_ABI void setAfterReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocAfter, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)
LLVM_ABI 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.
LLVM_ABI void runWholeProgramDevirtOnIndex(ModuleSummaryIndex &Summary, std::set< GlobalValue::GUID > &ExportedGUIDs, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap, DenseSet< StringRef > *ExternallyVisibleSymbolNamesPtr=nullptr)
Perform index-based whole program devirtualization on the Summary index.
LLVM_ABI MemoryEffects computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR)
Returns the memory access properties of this copy of the function.
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...
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
PassSummaryAction
What to do with the summary when running passes that operate on it.
@ 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...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
LLVM_ABI ModuleSummaryIndex buildModuleSummaryIndex(const Module &M, std::function< BlockFrequencyInfo *(const Function &F)> GetBFICallback, ProfileSummaryInfo *PSI, std::function< const StackSafetyInfo *(const Function &F)> GetSSICallback=[](const Function &F) -> const StackSafetyInfo *{ return nullptr;})
Direct function to compute a ModuleSummaryIndex from a given module.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI 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.
LLVM_ABI 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 ...
LLVM_ABI Expected< std::unique_ptr< ModuleSummaryIndex > > getModuleSummaryIndex(MemoryBufferRef Buffer)
Parse the specified bitcode buffer, returning the module summary index.
const IPOOptions & getIPOOptions(const LLVMContext &C)
LLVM_ABI void updateIndexWPDForExports(ModuleSummaryIndex &Summary, function_ref< bool(StringRef, ValueInfo)> isExported, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap, DenseSet< StringRef > *ExternallyVisibleSymbolNamesPtr=nullptr)
Call after cross-module importing to update the recorded single impl devirt target names for any loca...
LLVM_ABI void updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO)
LLVM_ABI 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)
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
LLVM_ABI 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...
LLVM_ABI CallBase & versionCallSite(CallBase &CB, Value *Callee, MDNode *BranchWeights)
Predicate and clone the given call site.
LLVM_ABI bool AreStatisticsEnabled()
Check if statistics are enabled.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI void setExplicitlyUnknownFunctionEntryCount(Function &F, StringRef PassName)
Analogous to setExplicitlyUnknownBranchWeights, but for functions and their entry counts.
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
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.
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
LLVM_ABI 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...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
static cl::opt< bool > PrintSummaryDevirt("wholeprogramdevirt-print-index-based", cl::Hidden, cl::desc("Print index-based devirtualization messages"))
void consumeError(Error Err)
Consume a Error without doing anything.
LLVM_ABI 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 ...
LLVM_ABI 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...
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
LLVM_ABI 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 ...
LLVM_ABI 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.
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
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 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...
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
const ModuleSummaryIndex * ImportSummary
ModuleSummaryIndex * ExportSummary
LLVM_ABI 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.
LLVM_ABI VirtualCallTarget(GlobalValue *Fn, const TypeMemberInfo *TM)
const TypeMemberInfo * TM