125#define DEBUG_TYPE "wholeprogramdevirt"
127STATISTIC(NumDevirtTargets,
"Number of whole program devirtualization targets");
128STATISTIC(NumSingleImpl,
"Number of single implementation devirtualizations");
130STATISTIC(NumUniformRetVal,
"Number of uniform return value optimizations");
131STATISTIC(NumUniqueRetVal,
"Number of unique return value optimizations");
133 "Number of 1 bit virtual constant propagations");
134STATISTIC(NumVirtConstProp,
"Number of virtual constant propagations");
136 "Controls how many calls should be devirtualized.");
141 "wholeprogramdevirt-summary-action",
142 cl::desc(
"What to do with the summary when running this pass"),
145 "Import typeid resolutions from summary and globals"),
147 "Export typeid resolutions to summary and globals")),
151 "wholeprogramdevirt-read-summary",
153 "Read summary from given bitcode or YAML file before running pass"),
157 "wholeprogramdevirt-write-summary",
158 cl::desc(
"Write summary to given bitcode or YAML file after running pass. "
159 "Output file format is deduced from extension: *.bc means writing "
160 "bitcode, otherwise YAML"),
166 "devirtualize-speculatively",
167 cl::desc(
"Enable speculative devirtualization optimization"),
173 cl::desc(
"Maximum number of call targets per "
174 "call site to enable branch funnels"));
178 cl::desc(
"Print index-based devirtualization messages"));
186 cl::desc(
"Enable whole program visibility"));
191 "disable-whole-program-visibility",
cl::Hidden,
192 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
197 cl::desc(
"Prevent function(s) from being devirtualized"),
220 "wholeprogramdevirt-keep-unreachable-function",
221 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
232 cl::desc(
"Type of checking for incorrect devirtualizations"),
236 "Fallback to indirect when incorrect")));
240 std::vector<GlobPattern> Patterns;
241 template <
class T>
void init(
const T &StringList) {
242 for (
const auto &S : StringList)
244 Patterns.push_back(std::move(*Pat));
246 bool match(StringRef S) {
247 for (
const GlobPattern &
P : Patterns)
260 bool IsAfter, uint64_t
Size) {
262 uint64_t MinByte = 0;
265 MinByte = std::max(MinByte,
Target.minAfterBytes());
267 MinByte = std::max(MinByte,
Target.minBeforeBytes());
290 std::vector<ArrayRef<uint8_t>> Used;
293 :
Target.TM->Bits->Before.BytesUsed;
294 uint64_t
Offset = IsAfter ? MinByte -
Target.minAfterBytes()
295 : MinByte -
Target.minBeforeBytes();
305 for (
unsigned I = 0;; ++
I) {
307 for (
auto &&
B : Used)
310 if (BitsUsed != 0xff)
316 for (
unsigned I = 0;; ++
I) {
317 for (
auto &&
B : Used) {
319 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
335 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
337 OffsetByte = -(AllocBefore / 8 + 1);
339 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
340 OffsetBit = AllocBefore % 8;
344 Target.setBeforeBit(AllocBefore);
352 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
354 OffsetByte = AllocAfter / 8;
356 OffsetByte = (AllocAfter + 7) / 8;
357 OffsetBit = AllocAfter % 8;
361 Target.setAfterBit(AllocAfter);
390 const VTableSlot &RHS) {
391 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
402 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
426 if (!Summary->isLive())
429 if (!FS->fflags().MustBeUnreachable)
444struct VirtualCallSite {
451 unsigned *NumUnsafeUses =
nullptr;
454 emitRemark(
const StringRef OptName,
const StringRef TargetName,
455 function_ref<OptimizationRemarkEmitter &(
Function &)> OREGetter) {
461 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE, OptName, DLoc,
Block)
462 <<
NV(
"Optimization", OptName)
463 <<
": devirtualized a call to "
464 <<
NV(
"FunctionName", TargetName));
467 void replaceAndErase(
468 const StringRef OptName,
const StringRef TargetName,
bool RemarksEnabled,
469 function_ref<OptimizationRemarkEmitter &(
Function &)> OREGetter,
476 II->getUnwindDest()->removePredecessor(
II->getParent());
493 std::vector<VirtualCallSite> CallSites;
502 bool AllCallSitesDevirted =
true;
511 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
515 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
517 bool isExported()
const {
518 return !SummaryTypeCheckedLoadUsers.empty() ||
519 !SummaryTypeTestAssumeUsers.empty();
522 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
523 SummaryTypeCheckedLoadUsers.push_back(FS);
524 AllCallSitesDevirted =
false;
527 void addSummaryTypeTestAssumeUser(FunctionSummary *FS) {
528 SummaryTypeTestAssumeUsers.push_back(FS);
529 AllCallSitesDevirted =
false;
532 void markDevirt() { AllCallSitesDevirted =
true; }
536struct VTableSlotInfo {
543 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
545 void addCallSite(
Value *VTable, CallBase &CB,
unsigned *NumUnsafeUses);
551CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) {
552 std::vector<uint64_t>
Args;
554 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
558 if (!CI || CI->getBitWidth() > 64)
560 Args.push_back(CI->getZExtValue());
562 return ConstCSInfo[
Args];
565void VTableSlotInfo::addCallSite(
Value *VTable, CallBase &CB,
566 unsigned *NumUnsafeUses) {
567 auto &CSI = findCallSiteInfo(CB);
568 CSI.AllCallSitesDevirted =
false;
569 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
577 ModuleSummaryIndex *
const ExportSummary;
578 const ModuleSummaryIndex *
const ImportSummary;
580 IntegerType *
const Int8Ty;
582 IntegerType *
const Int32Ty;
583 IntegerType *
const Int64Ty;
590 const bool RemarksEnabled;
591 std::function<OptimizationRemarkEmitter &(
Function &)> OREGetter;
592 MapVector<VTableSlot, VTableSlotInfo> CallSlots;
597 SmallPtrSet<CallBase *, 8> OptimizedCalls;
611 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
612 PatternList FunctionsToSkip;
614 const bool DevirtSpeculatively;
616 ModuleSummaryIndex *ExportSummary,
617 const ModuleSummaryIndex *ImportSummary,
618 bool DevirtSpeculatively)
621 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
628 RemarksEnabled(areRemarksEnabled()),
629 OREGetter([&](
Function &
F) -> OptimizationRemarkEmitter & {
632 DevirtSpeculatively(DevirtSpeculatively) {
633 assert(!(ExportSummary && ImportSummary));
637 bool areRemarksEnabled();
640 scanTypeTestUsers(
Function *TypeTestFunc,
641 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
642 void scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc);
644 void buildTypeIdentifierMap(
645 std::vector<VTableBits> &Bits,
646 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
649 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
650 const std::set<TypeMemberInfo> &TypeMemberInfos,
652 ModuleSummaryIndex *ExportSummary);
654 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
656 bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
658 VTableSlotInfo &SlotInfo,
659 WholeProgramDevirtResolution *Res);
661 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Function &JT,
664 VTableSlotInfo &SlotInfo,
665 WholeProgramDevirtResolution *Res, VTableSlot Slot);
667 bool tryEvaluateFunctionsWithArgs(
669 ArrayRef<uint64_t> Args);
671 void applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
675 WholeProgramDevirtResolution::ByArg *Res);
679 std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
682 bool shouldExportConstantsAsAbsoluteSymbols();
687 void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
689 void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
690 uint32_t Const, uint32_t &Storage);
694 Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
696 Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
697 StringRef Name, IntegerType *IntTy,
700 Constant *getMemberAddr(
const TypeMemberInfo *M);
702 void applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
bool IsOne,
703 Constant *UniqueMemberAddr);
704 bool tryUniqueRetValOpt(
unsigned BitWidth,
707 WholeProgramDevirtResolution::ByArg *Res,
708 VTableSlot Slot, ArrayRef<uint64_t> Args);
710 void applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
711 Constant *Byte, Constant *Bit);
713 VTableSlotInfo &SlotInfo,
714 WholeProgramDevirtResolution *Res, VTableSlot Slot);
716 void rebuildGlobal(VTableBits &
B);
719 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
723 void removeRedundantTypeTests();
730 static ValueInfo lookUpFunctionValueInfo(
Function *TheFn,
731 ModuleSummaryIndex *ExportSummary);
742 ModuleSummaryIndex *ExportSummary);
747 bool DevirtSpeculatively);
751 ModuleSummaryIndex &ExportSummary;
754 std::set<GlobalValue::GUID> &ExportedGUIDs;
758 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
763 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr;
765 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
767 PatternList FunctionsToSkip;
770 ModuleSummaryIndex &ExportSummary,
771 std::set<GlobalValue::GUID> &ExportedGUIDs,
772 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
773 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr)
774 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
775 LocalWPDTargetsMap(LocalWPDTargetsMap),
776 ExternallyVisibleSymbolNamesPtr(ExternallyVisibleSymbolNamesPtr) {
780 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
785 VTableSlotSummary &SlotSummary,
786 VTableSlotInfo &SlotInfo,
787 WholeProgramDevirtResolution *Res,
788 std::set<ValueInfo> &DevirtTargets);
802 std::optional<ModuleSummaryIndex> Index;
806 "ExportSummary is expected to be empty in non-LTO mode");
809 ExportSummary = Index.has_value() ? &Index.value() :
nullptr;
830 if (
TypeID.ends_with(
".virtual"))
836 if (!
TypeID.consume_front(
"_ZTS"))
844 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
845 return IsVisibleToRegularObj(TypeInfo);
854 for (
auto *
Type : Types)
857 IsVisibleToRegularObj);
866 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
868 bool ValidateAllVtablesHaveTypeInfos,
886 !(ValidateAllVtablesHaveTypeInfos &&
893 bool WholeProgramVisibilityEnabledInLTO) {
897 if (!PublicTypeTestFunc)
905 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
907 CI->replaceAllUsesWith(NewCI);
908 CI->eraseFromParent();
916 CI->replaceAllUsesWith(
True);
917 CI->eraseFromParent();
928 for (
const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
931 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
944 for (
auto &
P : Index) {
947 if (DynamicExportSymbols.
count(
P.first))
953 if (VisibleToRegularObjSymbols.
count(
P.first))
955 for (
auto &S :
P.second.getSummaryList()) {
967 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
969 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap,
970 ExternallyVisibleSymbolNamesPtr)
977 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
979 for (
auto &
T : LocalWPDTargetsMap) {
982 assert(VI.getSummaryList().size() == 1 &&
983 "Devirt of local target has more than one copy");
984 auto &S = VI.getSummaryList()[0];
985 if (!IsExported(S->modulePath(), VI))
989 for (
auto &SlotSummary :
T.second) {
990 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
992 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
993 assert(WPDRes != TIdSum->WPDRes.end());
994 if (ExternallyVisibleSymbolNamesPtr)
995 ExternallyVisibleSymbolNamesPtr->
insert(WPDRes->second.SingleImplName);
997 WPDRes->second.SingleImplName,
998 Summary.getModuleHash(S->modulePath()));
1008 const auto &ModPaths = Summary->modulePaths();
1013 "combined summary should contain Regular LTO module");
1018 bool DevirtSpeculatively) {
1019 std::unique_ptr<ModuleSummaryIndex>
Summary =
1020 std::make_unique<ModuleSummaryIndex>(
false);
1025 ExitOnError ExitOnErr(
"-wholeprogramdevirt-read-summary: " +
ClReadSummary +
1027 auto ReadSummaryFile =
1029 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1031 Summary = std::move(*SummaryOrErr);
1036 yaml::Input
In(ReadSummaryFile->getBuffer());
1043 DevirtModule(M,
MAM,
1048 DevirtSpeculatively)
1052 ExitOnError ExitOnErr(
1062 yaml::Output
Out(OS);
1070void DevirtModule::buildTypeIdentifierMap(
1071 std::vector<VTableBits> &Bits,
1072 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1073 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1074 Bits.reserve(
M.global_size());
1076 for (GlobalVariable &GV :
M.globals()) {
1084 Bits.emplace_back();
1085 Bits.back().GV = &GV;
1086 Bits.back().ObjectSize =
1088 BitsPtr = &
Bits.back();
1091 for (MDNode *
Type : Types) {
1104bool DevirtModule::tryFindVirtualCallTargets(
1105 std::vector<VirtualCallTarget> &TargetsForSlot,
1106 const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset,
1107 ModuleSummaryIndex *ExportSummary) {
1109 if (!TM.Bits->GV->isConstant())
1114 if (!DevirtSpeculatively && TM.Bits->GV->getVCallVisibility() ==
1120 if (TM.Bits->GV->hasLocalLinkage() && TM.Bits->GV->hasZeroLiveUses())
1131 if (FunctionsToSkip.match(Fn->
getName()))
1136 if (Fn->
getName() ==
"__cxa_pure_virtual")
1155 if (!GA->isInterposable() && !GA->getAliaseeObject()->isInterposable())
1157 TargetsForSlot.push_back({GV, &TM});
1161 return !TargetsForSlot.empty();
1164bool DevirtIndex::tryFindVirtualCallTargets(
1165 std::vector<ValueInfo> &TargetsForSlot,
1167 for (
const TypeIdOffsetVtableInfo &
P : TIdInfo) {
1178 if (
P.VTableVI.hasLocal() &&
P.VTableVI.getSummaryList().size() > 1)
1180 const GlobalVarSummary *
VS =
nullptr;
1181 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1183 if (!CurVS->vTableFuncs().empty() ||
1206 for (
auto VTP :
VS->vTableFuncs()) {
1207 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1213 TargetsForSlot.push_back(VTP.FuncVI);
1218 return !TargetsForSlot.empty();
1221void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1222 Constant *TheFn,
bool &IsExported) {
1228 for (
auto &&VCallSite : CSInfo.CallSites) {
1229 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1237 VCallSite.emitRemark(
"single-impl",
1240 auto &CB = VCallSite.CB;
1253 MDBuilder(
M.getContext()).createUnlikelyBranchWeights());
1254 Builder.SetInsertPoint(ThenTerm);
1257 auto *CallTrap = Builder.CreateCall(TrapFn);
1266 MDNode *Weights = MDBuilder(
M.getContext()).createLikelyBranchWeights();
1275 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1276 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1298 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1303 if (VCallSite.NumUnsafeUses)
1304 --*VCallSite.NumUnsafeUses;
1306 if (CSInfo.isExported())
1308 CSInfo.markDevirt();
1310 Apply(SlotInfo.CSInfo);
1311 for (
auto &
P : SlotInfo.ConstCSInfo)
1317 if (Callee.getSummaryList().empty())
1324 bool IsExported =
false;
1325 auto &S = Callee.getSummaryList()[0];
1327 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1328 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1329 FS->addCall({Callee, CI});
1330 IsExported |= S->modulePath() != FS->modulePath();
1332 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1333 FS->addCall({Callee, CI});
1334 IsExported |= S->modulePath() != FS->modulePath();
1337 AddCalls(SlotInfo.CSInfo);
1338 for (
auto &
P : SlotInfo.ConstCSInfo)
1343bool DevirtModule::trySingleImplDevirt(
1344 ModuleSummaryIndex *ExportSummary,
1346 WholeProgramDevirtResolution *Res) {
1349 auto *TheFn = TargetsForSlot[0].Fn;
1350 for (
auto &&Target : TargetsForSlot)
1356 TargetsForSlot[0].WasDevirt =
true;
1358 bool IsExported =
false;
1359 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1366 if (TheFn->hasLocalLinkage()) {
1367 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1372 if (Comdat *
C = TheFn->getComdat()) {
1373 if (
C->getName() == TheFn->
getName()) {
1374 Comdat *NewC =
M.getOrInsertComdat(NewName);
1376 for (GlobalObject &GO :
M.global_objects())
1377 if (GO.getComdat() ==
C)
1386 if (ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFn->getGUID()))
1398 VTableSlotSummary &SlotSummary,
1399 VTableSlotInfo &SlotInfo,
1400 WholeProgramDevirtResolution *Res,
1401 std::set<ValueInfo> &DevirtTargets) {
1404 auto TheFn = TargetsForSlot[0];
1405 for (
auto &&Target : TargetsForSlot)
1406 if (TheFn != Target)
1410 auto Size = TheFn.getSummaryList().size();
1416 if (FunctionsToSkip.match(TheFn.name()))
1421 if (TheFn.hasLocal() &&
Size > 1)
1426 DevirtTargets.insert(TheFn);
1428 auto &S = TheFn.getSummaryList()[0];
1429 bool IsExported =
addCalls(SlotInfo, TheFn);
1431 ExportedGUIDs.insert(TheFn.getGUID());
1441 if (ExternallyVisibleSymbolNamesPtr)
1442 ExternallyVisibleSymbolNamesPtr->insert(TheFn.name());
1444 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1446 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1460void DevirtModule::tryICallBranchFunnel(
1462 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1463 Triple
T(
M.getTargetTriple());
1470 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1472 for (
auto &
P : SlotInfo.ConstCSInfo)
1473 if (!
P.second.AllCallSitesDevirted) {
1474 HasNonDevirt =
true;
1492 for (
auto &
T : TargetsForSlot) {
1493 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1502 M.getDataLayout().getProgramAddressSpace(),
1503 getGlobalName(Slot, {},
"branch_funnel"), &
M);
1507 M.getDataLayout().getProgramAddressSpace(),
1508 "branch_funnel", &M);
1512 std::vector<Value *> JTArgs;
1514 for (
auto &
T : TargetsForSlot) {
1515 JTArgs.push_back(getMemberAddr(
T.TM));
1516 JTArgs.push_back(
T.Fn);
1521 &M, llvm::Intrinsic::icall_branch_funnel, {});
1527 bool IsExported =
false;
1528 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1538void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1540 DenseMap<Function *, double> FunctionEntryCounts;
1542 if (CSInfo.isExported())
1544 if (CSInfo.AllCallSitesDevirted)
1547 std::map<CallBase *, CallBase *> CallBases;
1548 for (
auto &&VCallSite : CSInfo.CallSites) {
1549 CallBase &CB = VCallSite.CB;
1551 if (CallBases.find(&CB) != CallBases.end()) {
1568 VCallSite.emitRemark(
"branch-funnel", JT.
getName(), OREGetter);
1572 std::vector<Type *> NewArgs;
1573 NewArgs.push_back(Int8PtrTy);
1575 FunctionType *NewFT =
1579 std::vector<Value *>
Args;
1580 Args.push_back(VCallSite.VTable);
1583 CallBase *NewCS =
nullptr;
1589 auto EC = BFI.getBlockFreq(&
F.getEntryBlock());
1590 auto CC =
F.getEntryCount();
1591 double CallCount = 0.0;
1592 if (
EC.getFrequency() != 0 && CC && *CC != 0) {
1594 static_cast<double>(
1595 BFI.getBlockFreq(CB.
getParent()).getFrequency()) /
1597 CallCount = CallFreq * *CC;
1599 FunctionEntryCounts[&JT] += CallCount;
1602 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1610 std::vector<AttributeSet> NewArgAttrs;
1613 M.getContext(), Attribute::Nest)}));
1614 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1615 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1617 AttributeList::get(
M.getContext(),
Attrs.getFnAttrs(),
1618 Attrs.getRetAttrs(), NewArgAttrs));
1620 CallBases[&CB] = NewCS;
1623 if (VCallSite.NumUnsafeUses)
1624 --*VCallSite.NumUnsafeUses;
1631 for (
auto &[Old, New] : CallBases) {
1632 Old->replaceAllUsesWith(New);
1633 Old->eraseFromParent();
1636 Apply(SlotInfo.CSInfo);
1637 for (
auto &
P : SlotInfo.ConstCSInfo)
1639 for (
auto &[
F,
C] : FunctionEntryCounts) {
1641 "Unexpected entry count for funnel that was freshly synthesized");
1642 F->setEntryCount(
static_cast<uint64_t>(std::round(
C)));
1646bool DevirtModule::tryEvaluateFunctionsWithArgs(
1648 ArrayRef<uint64_t> Args) {
1662 Evaluator Eval(
M.getDataLayout(),
nullptr);
1666 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1671 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1675 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1683void DevirtModule::applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1685 for (
auto Call : CSInfo.CallSites) {
1689 Call.replaceAndErase(
1690 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1693 CSInfo.markDevirt();
1696bool DevirtModule::tryUniformRetValOpt(
1698 WholeProgramDevirtResolution::ByArg *Res) {
1701 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1703 if (
Target.RetVal != TheRetVal)
1706 if (CSInfo.isExported()) {
1708 Res->
Info = TheRetVal;
1711 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1713 for (
auto &&Target : TargetsForSlot)
1718std::string DevirtModule::getGlobalName(VTableSlot Slot,
1719 ArrayRef<uint64_t> Args,
1721 std::string FullName =
"__typeid_";
1722 raw_string_ostream OS(FullName);
1723 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1730bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1731 Triple
T(
M.getTargetTriple());
1735void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1736 StringRef Name, Constant *
C) {
1738 getGlobalName(Slot, Args, Name),
C, &M);
1742void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1743 StringRef Name, uint32_t Const,
1744 uint32_t &Storage) {
1745 if (shouldExportConstantsAsAbsoluteSymbols()) {
1755Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1757 GlobalVariable *GV =
1758 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1763Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1764 StringRef Name, IntegerType *IntTy,
1766 if (!shouldExportConstantsAsAbsoluteSymbols())
1767 return ConstantInt::get(IntTy, Storage);
1769 Constant *
C = importGlobal(Slot, Args, Name);
1775 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1785 if (AbsWidth ==
IntPtrTy->getBitWidth()) {
1789 SetAbsRange(0, 1ull << AbsWidth);
1794void DevirtModule::applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1796 Constant *UniqueMemberAddr) {
1797 for (
auto &&
Call : CSInfo.CallSites) {
1803 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->
getType()));
1806 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1809 CSInfo.markDevirt();
1814 ConstantInt::get(Int64Ty,
M->Offset));
1817bool DevirtModule::tryUniqueRetValOpt(
1819 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1820 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1822 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1825 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1828 UniqueMember =
Target.TM;
1836 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1837 if (CSInfo.isExported()) {
1841 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1845 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1850 for (
auto &&Target : TargetsForSlot)
1857 if (tryUniqueRetValOptFor(
true))
1859 if (tryUniqueRetValOptFor(
false))
1865void DevirtModule::applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
1866 Constant *Byte, Constant *Bit) {
1867 for (
auto Call : CSInfo.CallSites) {
1872 Value *Addr =
B.CreatePtrAdd(
Call.VTable, Byte);
1873 if (RetType->getBitWidth() == 1) {
1875 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1876 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1877 NumVirtConstProp1Bit++;
1878 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1879 OREGetter, IsBitSet);
1881 Value *Val =
B.CreateLoad(RetType, Addr);
1883 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1887 CSInfo.markDevirt();
1890bool DevirtModule::tryVirtualConstProp(
1892 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1903 unsigned BitWidth = RetType->getBitWidth();
1915 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1948 GlobalVariable *GV =
Target.TM->Bits->GV;
1949 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1951 if (TypeAlignment > TableAlignment)
1955 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1956 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1959 WholeProgramDevirtResolution::ByArg *ResByArg =
nullptr;
1961 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1963 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1966 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1967 ResByArg, Slot, CSByConstantArg.first))
1982 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1983 for (
auto &&Target : TargetsForSlot) {
1984 TotalPaddingBefore += std::max<int64_t>(
1985 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1986 TotalPaddingAfter += std::max<int64_t>(
1987 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1992 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1999 if (TotalPaddingBefore <= TotalPaddingAfter)
2015 for (
auto &&Target : TargetsForSlot)
2019 if (CSByConstantArg.second.isExported()) {
2021 ResByArg->
Byte = OffsetByte;
2022 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
2028 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
2029 applyVirtualConstProp(CSByConstantArg.second,
2030 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
2036 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
2042 B.GV->getAlign(),
B.GV->getValueType());
2043 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
2046 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
2053 B.GV->getInitializer(),
2056 new GlobalVariable(M, NewInit->getType(),
B.GV->isConstant(),
2058 NewGV->setSection(
B.GV->getSection());
2059 NewGV->setComdat(
B.GV->getComdat());
2060 NewGV->setAlignment(
B.GV->getAlign());
2064 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
2069 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2071 M.getDataLayout(), NewInit->getType(), NewGV,
2072 {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 1)},
2075 Alias->setVisibility(
B.GV->getVisibility());
2076 Alias->takeName(
B.GV);
2078 B.GV->replaceAllUsesWith(Alias);
2079 B.GV->eraseFromParent();
2082bool DevirtModule::areRemarksEnabled() {
2083 const auto &FL =
M.getFunctionList();
2088 return DI.isEnabled();
2118 if (
Value *
Merge = GetMergeUser(U, &TypeTest))
2121 while (!Worklist.
empty()) {
2123 if (!VisitedMerges.
insert(V).second)
2128 if (Assume->getArgOperand(0) == V) {
2130 "assume must not be both direct and merged");
2142void DevirtModule::scanTypeTestUsers(
2144 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2147 SmallPtrSet<Value *, 8> VisitedMerges;
2162 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2168 if (!Assumes.
empty()) {
2169 Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();
2170 for (DevirtCallSite
Call : DevirtCalls)
2171 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
nullptr);
2174 auto RemoveTypeTestAssumes = [&]() {
2182 for (
auto *Assume : Assumes)
2183 Assume->eraseFromParent();
2186 if (CI->use_empty())
2187 CI->eraseFromParent();
2202 if (!TypeIdMap.count(TypeId))
2203 RemoveTypeTestAssumes();
2215 const TypeIdSummary *TidSummary =
2218 RemoveTypeTestAssumes();
2227void DevirtModule::scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc) {
2236 Value *Ptr = CI->getArgOperand(0);
2238 Value *TypeIdValue = CI->getArgOperand(2);
2244 bool HasNonCallUses =
false;
2245 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2247 HasNonCallUses, CI, DT);
2256 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2258 Value *LoadedValue =
nullptr;
2260 Intrinsic::type_checked_load_relative) {
2262 &M, Intrinsic::load_relative, {Int32Ty});
2263 LoadedValue = LoadB.CreateCall(LoadRelFunc, {Ptr,
Offset});
2266 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2269 for (Instruction *LoadedPtr : LoadedPtrs) {
2270 LoadedPtr->replaceAllUsesWith(LoadedValue);
2271 LoadedPtr->eraseFromParent();
2275 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2276 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {Ptr, TypeIdValue});
2278 for (Instruction *Pred : Preds) {
2279 Pred->replaceAllUsesWith(TypeTestCall);
2280 Pred->eraseFromParent();
2287 if (!CI->use_empty()) {
2290 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2291 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2296 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2297 NumUnsafeUses = DevirtCalls.
size();
2304 for (DevirtCallSite
Call : DevirtCalls) {
2305 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
2309 CI->eraseFromParent();
2313void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2317 const TypeIdSummary *TidSummary =
2321 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2322 if (ResI == TidSummary->
WPDRes.end())
2324 const WholeProgramDevirtResolution &Res = ResI->second;
2330 Value *SingleImplVal =
2335 if (!
A->isInterposable() && !
A->getAliaseeObject()->isInterposable())
2336 SingleImplVal =
A->getAliaseeObject();
2340 bool IsExported =
false;
2341 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2345 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2346 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2349 auto &ResByArg =
I->second;
2356 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2360 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2361 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2367 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2369 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2381 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2384 bool IsExported =
false;
2385 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2390void DevirtModule::removeRedundantTypeTests() {
2392 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2393 if (
U.second == 0) {
2394 U.first->replaceAllUsesWith(
True);
2395 U.first->eraseFromParent();
2401DevirtModule::lookUpFunctionValueInfo(
Function *TheFn,
2402 ModuleSummaryIndex *ExportSummary) {
2403 assert((ExportSummary !=
nullptr) &&
2404 "Caller guarantees ExportSummary is not nullptr");
2406 const auto TheFnGUID = TheFn->
getGUID();
2407 const auto TheFnGUIDWithExportedName =
2410 ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFnGUID);
2419 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2420 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2425bool DevirtModule::mustBeUnreachableFunction(
2426 Function *
const F, ModuleSummaryIndex *ExportSummary) {
2430 if (!
F->isDeclaration()) {
2436 return ExportSummary &&
2438 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2441bool DevirtModule::run() {
2450 Function *PublicTypeTestFunc =
nullptr;
2453 if (DevirtSpeculatively)
2454 PublicTypeTestFunc =
2461 &M, Intrinsic::type_checked_load_relative);
2468 if (!ExportSummary &&
2469 (((!PublicTypeTestFunc || PublicTypeTestFunc->
use_empty()) &&
2470 (!TypeTestFunc || TypeTestFunc->
use_empty())) ||
2471 !AssumeFunc || AssumeFunc->
use_empty()) &&
2472 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2473 (!TypeCheckedLoadRelativeFunc ||
2474 TypeCheckedLoadRelativeFunc->
use_empty()))
2478 std::vector<VTableBits>
Bits;
2479 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2480 buildTypeIdentifierMap(Bits, TypeIdMap);
2482 if (PublicTypeTestFunc && AssumeFunc)
2483 scanTypeTestUsers(PublicTypeTestFunc, TypeIdMap);
2485 if (TypeTestFunc && AssumeFunc)
2486 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2488 if (TypeCheckedLoadFunc)
2489 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2491 if (TypeCheckedLoadRelativeFunc)
2492 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2494 if (ImportSummary) {
2495 for (
auto &S : CallSlots)
2496 importResolution(S.first, S.second);
2498 removeRedundantTypeTests();
2503 for (GlobalVariable &GV :
M.globals())
2511 if (TypeIdMap.
empty())
2515 if (ExportSummary) {
2516 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2517 for (
auto &
P : TypeIdMap) {
2520 TypeId->getString())]
2524 for (
auto &
P : *ExportSummary) {
2525 for (
auto &S :
P.second.getSummaryList()) {
2530 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2531 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2532 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2535 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2536 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2537 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2540 for (
const FunctionSummary::ConstVCall &VC :
2541 FS->type_test_assume_const_vcalls()) {
2542 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2543 CallSlots[{MD,
VC.VFunc.Offset}]
2544 .ConstCSInfo[
VC.Args]
2545 .addSummaryTypeTestAssumeUser(FS);
2548 for (
const FunctionSummary::ConstVCall &VC :
2549 FS->type_checked_load_const_vcalls()) {
2550 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2551 CallSlots[{MD,
VC.VFunc.Offset}]
2552 .ConstCSInfo[
VC.Args]
2553 .addSummaryTypeCheckedLoadUser(FS);
2561 bool DidVirtualConstProp =
false;
2562 std::map<std::string, GlobalValue *> DevirtTargets;
2563 for (
auto &S : CallSlots) {
2567 std::vector<VirtualCallTarget> TargetsForSlot;
2568 WholeProgramDevirtResolution *Res =
nullptr;
2569 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2571 TypeMemberInfos.size())
2578 Res = &ExportSummary
2579 ->getOrInsertTypeIdSummary(
2581 .WPDRes[S.first.ByteOffset];
2582 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2583 S.first.ByteOffset, ExportSummary)) {
2584 bool SingleImplDevirt =
2585 trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res);
2589 if (!SingleImplDevirt && !DevirtSpeculatively) {
2590 DidVirtualConstProp |=
2591 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2593 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2598 for (
const auto &
T : TargetsForSlot)
2600 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2610 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2611 if (!CSI.AllCallSitesDevirted)
2612 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2613 FS->addTypeTest(GUID);
2615 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2616 for (
auto &CCS : S.second.ConstCSInfo)
2617 AddTypeTestsForTypeCheckedLoads(CCS.second);
2621 if (RemarksEnabled) {
2623 for (
const auto &DT : DevirtTargets) {
2624 GlobalValue *GV = DT.second;
2633 using namespace ore;
2634 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE,
"Devirtualized",
F)
2635 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2639 NumDevirtTargets += DevirtTargets.size();
2641 removeRedundantTypeTests();
2645 if (DidVirtualConstProp)
2652 for (GlobalVariable &GV :
M.globals())
2655 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2656 CI->eraseFromParent();
2661void DevirtIndex::run() {
2662 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2667 assert(!ExportSummary.withInternalizeAndPromote() &&
2668 "Expect index-based WPD to run before internalization and promotion");
2670 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2671 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2680 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2684 for (
auto &
P : ExportSummary) {
2685 for (
auto &S :
P.second.getSummaryList()) {
2690 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2691 for (StringRef Name : NameByGUID[VF.GUID]) {
2692 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2695 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2696 for (StringRef Name : NameByGUID[VF.GUID]) {
2697 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2700 for (
const FunctionSummary::ConstVCall &VC :
2701 FS->type_test_assume_const_vcalls()) {
2702 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2703 CallSlots[{
Name,
VC.VFunc.Offset}]
2704 .ConstCSInfo[
VC.Args]
2705 .addSummaryTypeTestAssumeUser(FS);
2708 for (
const FunctionSummary::ConstVCall &VC :
2709 FS->type_checked_load_const_vcalls()) {
2710 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2711 CallSlots[{
Name,
VC.VFunc.Offset}]
2712 .ConstCSInfo[
VC.Args]
2713 .addSummaryTypeCheckedLoadUser(FS);
2719 std::set<ValueInfo> DevirtTargets;
2721 for (
auto &S : CallSlots) {
2725 std::vector<ValueInfo> TargetsForSlot;
2726 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2730 WholeProgramDevirtResolution *Res =
2731 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2732 ->WPDRes[S.first.ByteOffset];
2733 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2734 S.first.ByteOffset)) {
2736 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2745 for (
const auto &DT : DevirtTargets)
2746 errs() <<
"Devirtualized call to " << DT <<
"\n";
2748 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...
#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 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)
WPDCheckMode
Mechanism to add runtime checking of devirtualization decisions, optionally trapping or falling back ...
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 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).
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.
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.
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.
iterator_range< user_iterator > users()
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)
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.
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