124#define DEBUG_TYPE "wholeprogramdevirt"
126STATISTIC(NumDevirtTargets,
"Number of whole program devirtualization targets");
127STATISTIC(NumSingleImpl,
"Number of single implementation devirtualizations");
129STATISTIC(NumUniformRetVal,
"Number of uniform return value optimizations");
130STATISTIC(NumUniqueRetVal,
"Number of unique return value optimizations");
132 "Number of 1 bit virtual constant propagations");
133STATISTIC(NumVirtConstProp,
"Number of virtual constant propagations");
135 "Controls how many calls should be devirtualized.");
140 "wholeprogramdevirt-summary-action",
141 cl::desc(
"What to do with the summary when running this pass"),
144 "Import typeid resolutions from summary and globals"),
146 "Export typeid resolutions to summary and globals")),
150 "wholeprogramdevirt-read-summary",
152 "Read summary from given bitcode or YAML file before running pass"),
156 "wholeprogramdevirt-write-summary",
157 cl::desc(
"Write summary to given bitcode or YAML file after running pass. "
158 "Output file format is deduced from extension: *.bc means writing "
159 "bitcode, otherwise YAML"),
165 "devirtualize-speculatively",
166 cl::desc(
"Enable speculative devirtualization optimization"),
172 cl::desc(
"Maximum number of call targets per "
173 "call site to enable branch funnels"));
177 cl::desc(
"Print index-based devirtualization messages"));
185 cl::desc(
"Enable whole program visibility"));
190 "disable-whole-program-visibility",
cl::Hidden,
191 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
196 cl::desc(
"Prevent function(s) from being devirtualized"),
219 "wholeprogramdevirt-keep-unreachable-function",
220 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
231 cl::desc(
"Type of checking for incorrect devirtualizations"),
235 "Fallback to indirect when incorrect")));
239 std::vector<GlobPattern> Patterns;
240 template <
class T>
void init(
const T &StringList) {
241 for (
const auto &S : StringList)
243 Patterns.push_back(std::move(*Pat));
245 bool match(StringRef S) {
246 for (
const GlobPattern &
P : Patterns)
259 bool IsAfter, uint64_t
Size) {
261 uint64_t MinByte = 0;
264 MinByte = std::max(MinByte,
Target.minAfterBytes());
266 MinByte = std::max(MinByte,
Target.minBeforeBytes());
289 std::vector<ArrayRef<uint8_t>> Used;
292 :
Target.TM->Bits->Before.BytesUsed;
293 uint64_t
Offset = IsAfter ? MinByte -
Target.minAfterBytes()
294 : MinByte -
Target.minBeforeBytes();
304 for (
unsigned I = 0;; ++
I) {
306 for (
auto &&
B : Used)
309 if (BitsUsed != 0xff)
315 for (
unsigned I = 0;; ++
I) {
316 for (
auto &&
B : Used) {
318 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
334 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
336 OffsetByte = -(AllocBefore / 8 + 1);
338 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
339 OffsetBit = AllocBefore % 8;
343 Target.setBeforeBit(AllocBefore);
351 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
353 OffsetByte = AllocAfter / 8;
355 OffsetByte = (AllocAfter + 7) / 8;
356 OffsetBit = AllocAfter % 8;
360 Target.setAfterBit(AllocAfter);
389 const VTableSlot &RHS) {
390 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
401 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
425 if (!Summary->isLive())
428 if (!FS->fflags().MustBeUnreachable)
443struct VirtualCallSite {
450 unsigned *NumUnsafeUses =
nullptr;
453 emitRemark(
const StringRef OptName,
const StringRef TargetName,
454 function_ref<OptimizationRemarkEmitter &(
Function &)> OREGetter) {
460 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE, OptName, DLoc,
Block)
461 <<
NV(
"Optimization", OptName)
462 <<
": devirtualized a call to "
463 <<
NV(
"FunctionName", TargetName));
466 void replaceAndErase(
467 const StringRef OptName,
const StringRef TargetName,
bool RemarksEnabled,
468 function_ref<OptimizationRemarkEmitter &(
Function &)> OREGetter,
475 II->getUnwindDest()->removePredecessor(
II->getParent());
492 std::vector<VirtualCallSite> CallSites;
501 bool AllCallSitesDevirted =
true;
510 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
514 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
516 bool isExported()
const {
517 return !SummaryTypeCheckedLoadUsers.empty() ||
518 !SummaryTypeTestAssumeUsers.empty();
521 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
522 SummaryTypeCheckedLoadUsers.push_back(FS);
523 AllCallSitesDevirted =
false;
526 void addSummaryTypeTestAssumeUser(FunctionSummary *FS) {
527 SummaryTypeTestAssumeUsers.push_back(FS);
528 AllCallSitesDevirted =
false;
531 void markDevirt() { AllCallSitesDevirted =
true; }
535struct VTableSlotInfo {
542 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
544 void addCallSite(
Value *VTable, CallBase &CB,
unsigned *NumUnsafeUses);
550CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) {
551 std::vector<uint64_t>
Args;
553 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
557 if (!CI || CI->getBitWidth() > 64)
559 Args.push_back(CI->getZExtValue());
561 return ConstCSInfo[
Args];
564void VTableSlotInfo::addCallSite(
Value *VTable, CallBase &CB,
565 unsigned *NumUnsafeUses) {
566 auto &CSI = findCallSiteInfo(CB);
567 CSI.AllCallSitesDevirted =
false;
568 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
576 ModuleSummaryIndex *
const ExportSummary;
577 const ModuleSummaryIndex *
const ImportSummary;
579 IntegerType *
const Int8Ty;
581 IntegerType *
const Int32Ty;
582 IntegerType *
const Int64Ty;
589 const bool RemarksEnabled;
590 std::function<OptimizationRemarkEmitter &(
Function &)> OREGetter;
591 MapVector<VTableSlot, VTableSlotInfo> CallSlots;
596 SmallPtrSet<CallBase *, 8> OptimizedCalls;
610 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
611 PatternList FunctionsToSkip;
613 const bool DevirtSpeculatively;
615 ModuleSummaryIndex *ExportSummary,
616 const ModuleSummaryIndex *ImportSummary,
617 bool DevirtSpeculatively)
620 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
627 RemarksEnabled(areRemarksEnabled()),
628 OREGetter([&](
Function &
F) -> OptimizationRemarkEmitter & {
631 DevirtSpeculatively(DevirtSpeculatively) {
632 assert(!(ExportSummary && ImportSummary));
636 bool areRemarksEnabled();
639 scanTypeTestUsers(
Function *TypeTestFunc,
640 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
641 void scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc);
643 void buildTypeIdentifierMap(
644 std::vector<VTableBits> &Bits,
645 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
648 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
649 const std::set<TypeMemberInfo> &TypeMemberInfos,
651 ModuleSummaryIndex *ExportSummary);
653 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
655 bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
657 VTableSlotInfo &SlotInfo,
658 WholeProgramDevirtResolution *Res);
660 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Function &JT,
663 VTableSlotInfo &SlotInfo,
664 WholeProgramDevirtResolution *Res, VTableSlot Slot);
666 bool tryEvaluateFunctionsWithArgs(
668 ArrayRef<uint64_t> Args);
670 void applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
674 WholeProgramDevirtResolution::ByArg *Res);
678 std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
681 bool shouldExportConstantsAsAbsoluteSymbols();
686 void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
688 void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
689 uint32_t Const, uint32_t &Storage);
693 Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
695 Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
696 StringRef Name, IntegerType *IntTy,
699 Constant *getMemberAddr(
const TypeMemberInfo *M);
701 void applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
bool IsOne,
702 Constant *UniqueMemberAddr);
703 bool tryUniqueRetValOpt(
unsigned BitWidth,
706 WholeProgramDevirtResolution::ByArg *Res,
707 VTableSlot Slot, ArrayRef<uint64_t> Args);
709 void applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
710 Constant *Byte, Constant *Bit);
712 VTableSlotInfo &SlotInfo,
713 WholeProgramDevirtResolution *Res, VTableSlot Slot);
715 void rebuildGlobal(VTableBits &
B);
718 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
722 void removeRedundantTypeTests();
729 static ValueInfo lookUpFunctionValueInfo(
Function *TheFn,
730 ModuleSummaryIndex *ExportSummary);
741 ModuleSummaryIndex *ExportSummary);
746 bool DevirtSpeculatively);
750 ModuleSummaryIndex &ExportSummary;
753 std::set<GlobalValue::GUID> &ExportedGUIDs;
757 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
762 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr;
764 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
766 PatternList FunctionsToSkip;
769 ModuleSummaryIndex &ExportSummary,
770 std::set<GlobalValue::GUID> &ExportedGUIDs,
771 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
772 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr)
773 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
774 LocalWPDTargetsMap(LocalWPDTargetsMap),
775 ExternallyVisibleSymbolNamesPtr(ExternallyVisibleSymbolNamesPtr) {
779 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
784 VTableSlotSummary &SlotSummary,
785 VTableSlotInfo &SlotInfo,
786 WholeProgramDevirtResolution *Res,
787 std::set<ValueInfo> &DevirtTargets);
801 std::optional<ModuleSummaryIndex> Index;
805 "ExportSummary is expected to be empty in non-LTO mode");
808 ExportSummary = Index.has_value() ? &Index.value() :
nullptr;
829 if (
TypeID.ends_with(
".virtual"))
835 if (!
TypeID.consume_front(
"_ZTS"))
843 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
844 return IsVisibleToRegularObj(TypeInfo);
853 for (
auto *
Type : Types)
856 IsVisibleToRegularObj);
865 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
867 bool ValidateAllVtablesHaveTypeInfos,
885 !(ValidateAllVtablesHaveTypeInfos &&
892 bool WholeProgramVisibilityEnabledInLTO) {
896 if (!PublicTypeTestFunc)
904 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
906 CI->replaceAllUsesWith(NewCI);
907 CI->eraseFromParent();
915 CI->replaceAllUsesWith(True);
916 CI->eraseFromParent();
927 for (
const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
930 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
943 for (
auto &
P : Index) {
946 if (DynamicExportSymbols.
count(
P.first))
952 if (VisibleToRegularObjSymbols.
count(
P.first))
954 for (
auto &S :
P.second.getSummaryList()) {
966 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
968 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap,
969 ExternallyVisibleSymbolNamesPtr)
976 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
978 for (
auto &
T : LocalWPDTargetsMap) {
981 assert(VI.getSummaryList().size() == 1 &&
982 "Devirt of local target has more than one copy");
983 auto &S = VI.getSummaryList()[0];
984 if (!IsExported(S->modulePath(), VI))
988 for (
auto &SlotSummary :
T.second) {
989 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
991 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
992 assert(WPDRes != TIdSum->WPDRes.end());
993 if (ExternallyVisibleSymbolNamesPtr)
994 ExternallyVisibleSymbolNamesPtr->
insert(WPDRes->second.SingleImplName);
996 WPDRes->second.SingleImplName,
997 Summary.getModuleHash(S->modulePath()));
1007 const auto &ModPaths = Summary->modulePaths();
1012 "combined summary should contain Regular LTO module");
1017 bool DevirtSpeculatively) {
1018 std::unique_ptr<ModuleSummaryIndex>
Summary =
1019 std::make_unique<ModuleSummaryIndex>(
false);
1024 ExitOnError ExitOnErr(
"-wholeprogramdevirt-read-summary: " +
ClReadSummary +
1026 auto ReadSummaryFile =
1028 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1030 Summary = std::move(*SummaryOrErr);
1035 yaml::Input
In(ReadSummaryFile->getBuffer());
1042 DevirtModule(M,
MAM,
1047 DevirtSpeculatively)
1051 ExitOnError ExitOnErr(
1061 yaml::Output
Out(OS);
1069void DevirtModule::buildTypeIdentifierMap(
1070 std::vector<VTableBits> &Bits,
1071 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1072 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1073 Bits.reserve(
M.global_size());
1075 for (GlobalVariable &GV :
M.globals()) {
1083 Bits.emplace_back();
1084 Bits.back().GV = &GV;
1085 Bits.back().ObjectSize =
1087 BitsPtr = &
Bits.back();
1090 for (MDNode *
Type : Types) {
1103bool DevirtModule::tryFindVirtualCallTargets(
1104 std::vector<VirtualCallTarget> &TargetsForSlot,
1105 const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset,
1106 ModuleSummaryIndex *ExportSummary) {
1108 if (!TM.Bits->GV->isConstant())
1113 if (!DevirtSpeculatively && TM.Bits->GV->getVCallVisibility() ==
1125 if (FunctionsToSkip.match(Fn->
getName()))
1130 if (Fn->
getName() ==
"__cxa_pure_virtual")
1149 if (!GA->isInterposable() && !GA->getAliaseeObject()->isInterposable())
1151 TargetsForSlot.push_back({GV, &TM});
1155 return !TargetsForSlot.empty();
1158bool DevirtIndex::tryFindVirtualCallTargets(
1159 std::vector<ValueInfo> &TargetsForSlot,
1161 for (
const TypeIdOffsetVtableInfo &
P : TIdInfo) {
1172 if (
P.VTableVI.hasLocal() &&
P.VTableVI.getSummaryList().size() > 1)
1174 const GlobalVarSummary *
VS =
nullptr;
1175 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1177 if (!CurVS->vTableFuncs().empty() ||
1200 for (
auto VTP :
VS->vTableFuncs()) {
1201 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1207 TargetsForSlot.push_back(VTP.FuncVI);
1212 return !TargetsForSlot.empty();
1215void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1216 Constant *TheFn,
bool &IsExported) {
1222 for (
auto &&VCallSite : CSInfo.CallSites) {
1223 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1231 VCallSite.emitRemark(
"single-impl",
1234 auto &CB = VCallSite.CB;
1247 MDBuilder(
M.getContext()).createUnlikelyBranchWeights());
1248 Builder.SetInsertPoint(ThenTerm);
1251 auto *CallTrap = Builder.CreateCall(TrapFn);
1260 MDNode *Weights = MDBuilder(
M.getContext()).createLikelyBranchWeights();
1269 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1270 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1292 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1297 if (VCallSite.NumUnsafeUses)
1298 --*VCallSite.NumUnsafeUses;
1300 if (CSInfo.isExported())
1302 CSInfo.markDevirt();
1304 Apply(SlotInfo.CSInfo);
1305 for (
auto &
P : SlotInfo.ConstCSInfo)
1311 if (Callee.getSummaryList().empty())
1318 bool IsExported =
false;
1319 auto &S = Callee.getSummaryList()[0];
1321 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1322 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1323 FS->addCall({Callee, CI});
1324 IsExported |= S->modulePath() != FS->modulePath();
1326 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1327 FS->addCall({Callee, CI});
1328 IsExported |= S->modulePath() != FS->modulePath();
1331 AddCalls(SlotInfo.CSInfo);
1332 for (
auto &
P : SlotInfo.ConstCSInfo)
1337bool DevirtModule::trySingleImplDevirt(
1338 ModuleSummaryIndex *ExportSummary,
1340 WholeProgramDevirtResolution *Res) {
1343 auto *TheFn = TargetsForSlot[0].Fn;
1344 for (
auto &&Target : TargetsForSlot)
1350 TargetsForSlot[0].WasDevirt =
true;
1352 bool IsExported =
false;
1353 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1360 if (TheFn->hasLocalLinkage()) {
1361 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1366 if (Comdat *
C = TheFn->getComdat()) {
1367 if (
C->getName() == TheFn->
getName()) {
1368 Comdat *NewC =
M.getOrInsertComdat(NewName);
1370 for (GlobalObject &GO :
M.global_objects())
1371 if (GO.getComdat() ==
C)
1380 if (ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFn->getGUID()))
1392 VTableSlotSummary &SlotSummary,
1393 VTableSlotInfo &SlotInfo,
1394 WholeProgramDevirtResolution *Res,
1395 std::set<ValueInfo> &DevirtTargets) {
1398 auto TheFn = TargetsForSlot[0];
1399 for (
auto &&Target : TargetsForSlot)
1400 if (TheFn != Target)
1404 auto Size = TheFn.getSummaryList().size();
1410 if (FunctionsToSkip.match(TheFn.name()))
1415 if (TheFn.hasLocal() &&
Size > 1)
1420 DevirtTargets.insert(TheFn);
1422 auto &S = TheFn.getSummaryList()[0];
1423 bool IsExported =
addCalls(SlotInfo, TheFn);
1425 ExportedGUIDs.insert(TheFn.getGUID());
1435 if (ExternallyVisibleSymbolNamesPtr)
1436 ExternallyVisibleSymbolNamesPtr->insert(TheFn.name());
1438 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1440 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1454void DevirtModule::tryICallBranchFunnel(
1456 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1457 Triple
T(
M.getTargetTriple());
1464 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1466 for (
auto &
P : SlotInfo.ConstCSInfo)
1467 if (!
P.second.AllCallSitesDevirted) {
1468 HasNonDevirt =
true;
1486 for (
auto &
T : TargetsForSlot) {
1487 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1496 M.getDataLayout().getProgramAddressSpace(),
1497 getGlobalName(Slot, {},
"branch_funnel"), &
M);
1501 M.getDataLayout().getProgramAddressSpace(),
1502 "branch_funnel", &M);
1506 std::vector<Value *> JTArgs;
1508 for (
auto &
T : TargetsForSlot) {
1509 JTArgs.push_back(getMemberAddr(
T.TM));
1510 JTArgs.push_back(
T.Fn);
1515 &M, llvm::Intrinsic::icall_branch_funnel, {});
1521 bool IsExported =
false;
1522 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1532void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1534 DenseMap<Function *, double> FunctionEntryCounts;
1536 if (CSInfo.isExported())
1538 if (CSInfo.AllCallSitesDevirted)
1541 std::map<CallBase *, CallBase *> CallBases;
1542 for (
auto &&VCallSite : CSInfo.CallSites) {
1543 CallBase &CB = VCallSite.CB;
1545 if (CallBases.find(&CB) != CallBases.end()) {
1562 VCallSite.emitRemark(
"branch-funnel", JT.
getName(), OREGetter);
1566 std::vector<Type *> NewArgs;
1567 NewArgs.push_back(Int8PtrTy);
1569 FunctionType *NewFT =
1573 std::vector<Value *>
Args;
1574 Args.push_back(VCallSite.VTable);
1577 CallBase *NewCS =
nullptr;
1583 auto EC = BFI.getBlockFreq(&
F.getEntryBlock());
1584 auto CC =
F.getEntryCount();
1585 double CallCount = 0.0;
1586 if (
EC.getFrequency() != 0 && CC && *CC != 0) {
1588 static_cast<double>(
1589 BFI.getBlockFreq(CB.
getParent()).getFrequency()) /
1591 CallCount = CallFreq * *CC;
1593 FunctionEntryCounts[&JT] += CallCount;
1596 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1604 std::vector<AttributeSet> NewArgAttrs;
1607 M.getContext(), Attribute::Nest)}));
1608 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1609 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1611 AttributeList::get(
M.getContext(),
Attrs.getFnAttrs(),
1612 Attrs.getRetAttrs(), NewArgAttrs));
1614 CallBases[&CB] = NewCS;
1617 if (VCallSite.NumUnsafeUses)
1618 --*VCallSite.NumUnsafeUses;
1625 for (
auto &[Old, New] : CallBases) {
1626 Old->replaceAllUsesWith(New);
1627 Old->eraseFromParent();
1630 Apply(SlotInfo.CSInfo);
1631 for (
auto &
P : SlotInfo.ConstCSInfo)
1633 for (
auto &[
F,
C] : FunctionEntryCounts) {
1635 "Unexpected entry count for funnel that was freshly synthesized");
1636 F->setEntryCount(
static_cast<uint64_t>(std::round(
C)));
1640bool DevirtModule::tryEvaluateFunctionsWithArgs(
1642 ArrayRef<uint64_t> Args) {
1656 Evaluator Eval(
M.getDataLayout(),
nullptr);
1660 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1665 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1669 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1677void DevirtModule::applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1679 for (
auto Call : CSInfo.CallSites) {
1683 Call.replaceAndErase(
1684 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1687 CSInfo.markDevirt();
1690bool DevirtModule::tryUniformRetValOpt(
1692 WholeProgramDevirtResolution::ByArg *Res) {
1695 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1697 if (
Target.RetVal != TheRetVal)
1700 if (CSInfo.isExported()) {
1702 Res->
Info = TheRetVal;
1705 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1707 for (
auto &&Target : TargetsForSlot)
1712std::string DevirtModule::getGlobalName(VTableSlot Slot,
1713 ArrayRef<uint64_t> Args,
1715 std::string FullName =
"__typeid_";
1716 raw_string_ostream OS(FullName);
1717 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1724bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1725 Triple
T(
M.getTargetTriple());
1729void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1730 StringRef Name, Constant *
C) {
1732 getGlobalName(Slot, Args, Name),
C, &M);
1736void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1737 StringRef Name, uint32_t Const,
1738 uint32_t &Storage) {
1739 if (shouldExportConstantsAsAbsoluteSymbols()) {
1749Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1751 GlobalVariable *GV =
1752 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1757Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1758 StringRef Name, IntegerType *IntTy,
1760 if (!shouldExportConstantsAsAbsoluteSymbols())
1761 return ConstantInt::get(IntTy, Storage);
1763 Constant *
C = importGlobal(Slot, Args, Name);
1769 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1779 if (AbsWidth ==
IntPtrTy->getBitWidth()) {
1783 SetAbsRange(0, 1ull << AbsWidth);
1788void DevirtModule::applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1790 Constant *UniqueMemberAddr) {
1791 for (
auto &&
Call : CSInfo.CallSites) {
1797 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->
getType()));
1800 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1803 CSInfo.markDevirt();
1808 ConstantInt::get(Int64Ty,
M->Offset));
1811bool DevirtModule::tryUniqueRetValOpt(
1813 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1814 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1816 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1819 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1822 UniqueMember =
Target.TM;
1830 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1831 if (CSInfo.isExported()) {
1835 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1839 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1844 for (
auto &&Target : TargetsForSlot)
1851 if (tryUniqueRetValOptFor(
true))
1853 if (tryUniqueRetValOptFor(
false))
1859void DevirtModule::applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
1860 Constant *Byte, Constant *Bit) {
1861 for (
auto Call : CSInfo.CallSites) {
1866 Value *Addr =
B.CreatePtrAdd(
Call.VTable, Byte);
1867 if (RetType->getBitWidth() == 1) {
1869 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1870 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1871 NumVirtConstProp1Bit++;
1872 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1873 OREGetter, IsBitSet);
1875 Value *Val =
B.CreateLoad(RetType, Addr);
1877 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1881 CSInfo.markDevirt();
1884bool DevirtModule::tryVirtualConstProp(
1886 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1897 unsigned BitWidth = RetType->getBitWidth();
1909 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1942 GlobalVariable *GV =
Target.TM->Bits->GV;
1943 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1945 if (TypeAlignment > TableAlignment)
1949 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1950 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1953 WholeProgramDevirtResolution::ByArg *ResByArg =
nullptr;
1955 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1957 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1960 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1961 ResByArg, Slot, CSByConstantArg.first))
1976 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1977 for (
auto &&Target : TargetsForSlot) {
1978 TotalPaddingBefore += std::max<int64_t>(
1979 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1980 TotalPaddingAfter += std::max<int64_t>(
1981 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1986 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1993 if (TotalPaddingBefore <= TotalPaddingAfter)
2009 for (
auto &&Target : TargetsForSlot)
2013 if (CSByConstantArg.second.isExported()) {
2015 ResByArg->
Byte = OffsetByte;
2016 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
2022 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
2023 applyVirtualConstProp(CSByConstantArg.second,
2024 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
2030 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
2036 B.GV->getAlign(),
B.GV->getValueType());
2037 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
2040 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
2047 B.GV->getInitializer(),
2050 new GlobalVariable(M, NewInit->getType(),
B.GV->isConstant(),
2052 NewGV->setSection(
B.GV->getSection());
2053 NewGV->setComdat(
B.GV->getComdat());
2054 NewGV->setAlignment(
B.GV->getAlign());
2058 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
2063 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2065 NewInit->getType(), NewGV,
2067 ConstantInt::get(Int32Ty, 1)}),
2069 Alias->setVisibility(
B.GV->getVisibility());
2070 Alias->takeName(
B.GV);
2072 B.GV->replaceAllUsesWith(Alias);
2073 B.GV->eraseFromParent();
2076bool DevirtModule::areRemarksEnabled() {
2077 const auto &FL =
M.getFunctionList();
2082 return DI.isEnabled();
2087void DevirtModule::scanTypeTestUsers(
2089 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2103 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2109 if (!Assumes.
empty()) {
2110 Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();
2111 for (DevirtCallSite
Call : DevirtCalls)
2112 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
nullptr);
2115 auto RemoveTypeTestAssumes = [&]() {
2117 for (
auto *Assume : Assumes)
2118 Assume->eraseFromParent();
2121 if (CI->use_empty())
2122 CI->eraseFromParent();
2137 if (!TypeIdMap.count(TypeId))
2138 RemoveTypeTestAssumes();
2150 const TypeIdSummary *TidSummary =
2153 RemoveTypeTestAssumes();
2162void DevirtModule::scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc) {
2171 Value *Ptr = CI->getArgOperand(0);
2173 Value *TypeIdValue = CI->getArgOperand(2);
2179 bool HasNonCallUses =
false;
2180 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2182 HasNonCallUses, CI, DT);
2191 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2193 Value *LoadedValue =
nullptr;
2195 Intrinsic::type_checked_load_relative) {
2197 &M, Intrinsic::load_relative, {Int32Ty});
2198 LoadedValue = LoadB.CreateCall(LoadRelFunc, {Ptr,
Offset});
2201 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2204 for (Instruction *LoadedPtr : LoadedPtrs) {
2205 LoadedPtr->replaceAllUsesWith(LoadedValue);
2206 LoadedPtr->eraseFromParent();
2210 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2211 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {Ptr, TypeIdValue});
2213 for (Instruction *Pred : Preds) {
2214 Pred->replaceAllUsesWith(TypeTestCall);
2215 Pred->eraseFromParent();
2222 if (!CI->use_empty()) {
2225 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2226 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2231 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2232 NumUnsafeUses = DevirtCalls.
size();
2239 for (DevirtCallSite
Call : DevirtCalls) {
2240 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
2244 CI->eraseFromParent();
2248void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2252 const TypeIdSummary *TidSummary =
2256 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2257 if (ResI == TidSummary->
WPDRes.end())
2259 const WholeProgramDevirtResolution &Res = ResI->second;
2265 Value *SingleImplVal =
2270 if (!
A->isInterposable() && !
A->getAliaseeObject()->isInterposable())
2271 SingleImplVal =
A->getAliaseeObject();
2275 bool IsExported =
false;
2276 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2280 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2281 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2284 auto &ResByArg =
I->second;
2291 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2295 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2296 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2302 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2304 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2316 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2319 bool IsExported =
false;
2320 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2325void DevirtModule::removeRedundantTypeTests() {
2327 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2328 if (
U.second == 0) {
2329 U.first->replaceAllUsesWith(True);
2330 U.first->eraseFromParent();
2336DevirtModule::lookUpFunctionValueInfo(
Function *TheFn,
2337 ModuleSummaryIndex *ExportSummary) {
2338 assert((ExportSummary !=
nullptr) &&
2339 "Caller guarantees ExportSummary is not nullptr");
2341 const auto TheFnGUID = TheFn->
getGUID();
2342 const auto TheFnGUIDWithExportedName =
2345 ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFnGUID);
2354 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2355 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2360bool DevirtModule::mustBeUnreachableFunction(
2361 Function *
const F, ModuleSummaryIndex *ExportSummary) {
2365 if (!
F->isDeclaration()) {
2371 return ExportSummary &&
2373 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2376bool DevirtModule::run() {
2385 Function *PublicTypeTestFunc =
nullptr;
2388 if (DevirtSpeculatively)
2389 PublicTypeTestFunc =
2396 &M, Intrinsic::type_checked_load_relative);
2403 if (!ExportSummary &&
2404 (((!PublicTypeTestFunc || PublicTypeTestFunc->
use_empty()) &&
2405 (!TypeTestFunc || TypeTestFunc->
use_empty())) ||
2406 !AssumeFunc || AssumeFunc->
use_empty()) &&
2407 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2408 (!TypeCheckedLoadRelativeFunc ||
2409 TypeCheckedLoadRelativeFunc->
use_empty()))
2413 std::vector<VTableBits>
Bits;
2414 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2415 buildTypeIdentifierMap(Bits, TypeIdMap);
2417 if (PublicTypeTestFunc && AssumeFunc)
2418 scanTypeTestUsers(PublicTypeTestFunc, TypeIdMap);
2420 if (TypeTestFunc && AssumeFunc)
2421 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2423 if (TypeCheckedLoadFunc)
2424 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2426 if (TypeCheckedLoadRelativeFunc)
2427 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2429 if (ImportSummary) {
2430 for (
auto &S : CallSlots)
2431 importResolution(S.first, S.second);
2433 removeRedundantTypeTests();
2438 for (GlobalVariable &GV :
M.globals())
2446 if (TypeIdMap.
empty())
2450 if (ExportSummary) {
2451 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2452 for (
auto &
P : TypeIdMap) {
2455 TypeId->getString())]
2459 for (
auto &
P : *ExportSummary) {
2460 for (
auto &S :
P.second.getSummaryList()) {
2465 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2466 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2467 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2470 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2471 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2472 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2475 for (
const FunctionSummary::ConstVCall &VC :
2476 FS->type_test_assume_const_vcalls()) {
2477 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2478 CallSlots[{MD,
VC.VFunc.Offset}]
2479 .ConstCSInfo[
VC.Args]
2480 .addSummaryTypeTestAssumeUser(FS);
2483 for (
const FunctionSummary::ConstVCall &VC :
2484 FS->type_checked_load_const_vcalls()) {
2485 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2486 CallSlots[{MD,
VC.VFunc.Offset}]
2487 .ConstCSInfo[
VC.Args]
2488 .addSummaryTypeCheckedLoadUser(FS);
2496 bool DidVirtualConstProp =
false;
2497 std::map<std::string, GlobalValue *> DevirtTargets;
2498 for (
auto &S : CallSlots) {
2502 std::vector<VirtualCallTarget> TargetsForSlot;
2503 WholeProgramDevirtResolution *Res =
nullptr;
2504 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2506 TypeMemberInfos.size())
2513 Res = &ExportSummary
2514 ->getOrInsertTypeIdSummary(
2516 .WPDRes[S.first.ByteOffset];
2517 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2518 S.first.ByteOffset, ExportSummary)) {
2519 bool SingleImplDevirt =
2520 trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res);
2524 if (!SingleImplDevirt && !DevirtSpeculatively) {
2525 DidVirtualConstProp |=
2526 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2528 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2533 for (
const auto &
T : TargetsForSlot)
2535 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2545 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2546 if (!CSI.AllCallSitesDevirted)
2547 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2548 FS->addTypeTest(GUID);
2550 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2551 for (
auto &CCS : S.second.ConstCSInfo)
2552 AddTypeTestsForTypeCheckedLoads(CCS.second);
2556 if (RemarksEnabled) {
2558 for (
const auto &DT : DevirtTargets) {
2559 GlobalValue *GV = DT.second;
2568 using namespace ore;
2569 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE,
"Devirtualized",
F)
2570 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2574 NumDevirtTargets += DevirtTargets.size();
2576 removeRedundantTypeTests();
2580 if (DidVirtualConstProp)
2587 for (GlobalVariable &GV :
M.globals())
2590 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2591 CI->eraseFromParent();
2596void DevirtIndex::run() {
2597 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2602 assert(!ExportSummary.withInternalizeAndPromote() &&
2603 "Expect index-based WPD to run before internalization and promotion");
2605 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2606 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2615 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2619 for (
auto &
P : ExportSummary) {
2620 for (
auto &S :
P.second.getSummaryList()) {
2625 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2626 for (StringRef Name : NameByGUID[VF.GUID]) {
2627 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2630 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2631 for (StringRef Name : NameByGUID[VF.GUID]) {
2632 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2635 for (
const FunctionSummary::ConstVCall &VC :
2636 FS->type_test_assume_const_vcalls()) {
2637 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2638 CallSlots[{
Name,
VC.VFunc.Offset}]
2639 .ConstCSInfo[
VC.Args]
2640 .addSummaryTypeTestAssumeUser(FS);
2643 for (
const FunctionSummary::ConstVCall &VC :
2644 FS->type_checked_load_const_vcalls()) {
2645 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2646 CallSlots[{
Name,
VC.VFunc.Offset}]
2647 .ConstCSInfo[
VC.Args]
2648 .addSummaryTypeCheckedLoadUser(FS);
2654 std::set<ValueInfo> DevirtTargets;
2656 for (
auto &S : CallSlots) {
2660 std::vector<ValueInfo> TargetsForSlot;
2661 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2665 WholeProgramDevirtResolution *Res =
2666 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2667 ->WPDRes[S.first.ByteOffset];
2668 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2669 S.first.ByteOffset)) {
2671 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2680 for (
const auto &DT : DevirtTargets)
2681 errs() <<
"Devirtualized call to " << DT <<
"\n";
2683 NumDevirtTargets += DevirtTargets.size();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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...
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
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.
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)
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.
const SmallVectorImpl< MachineOperand > & Cond
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
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)
WPDCheckMode
Mechanism to add runtime checking of devirtualization decisions, optionally trapping or falling back ...
static bool typeIDVisibleToRegularObj(StringRef TypeID, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary)
static bool addCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee)
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 bool skipUpdateDueToValidation(GlobalVariable &GV, function_ref< bool(StringRef)> IsVisibleToRegularObj)
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).
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 * getInBoundsGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList)
Create an "inbounds" getelementptr.
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_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 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.
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)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
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.
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.
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.
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)
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.
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.
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"))
@ Export
Export information to summary.
@ Import
Import information from summary.
static cl::opt< std::string > ClReadSummary("wholeprogramdevirt-read-summary", cl::desc("Read summary from given bitcode or YAML file before running pass"), cl::Hidden)
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.
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...
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)
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)
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.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
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< 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)
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.
static cl::opt< bool > ClDevirtualizeSpeculatively("devirtualize-speculatively", cl::desc("Enable speculative devirtualization optimization"), cl::init(false))
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