123#define DEBUG_TYPE "wholeprogramdevirt"
125STATISTIC(NumDevirtTargets,
"Number of whole program devirtualization targets");
126STATISTIC(NumSingleImpl,
"Number of single implementation devirtualizations");
128STATISTIC(NumUniformRetVal,
"Number of uniform return value optimizations");
129STATISTIC(NumUniqueRetVal,
"Number of unique return value optimizations");
131 "Number of 1 bit virtual constant propagations");
132STATISTIC(NumVirtConstProp,
"Number of virtual constant propagations");
137 "wholeprogramdevirt-summary-action",
138 cl::desc(
"What to do with the summary when running this pass"),
141 "Import typeid resolutions from summary and globals"),
143 "Export typeid resolutions to summary and globals")),
147 "wholeprogramdevirt-read-summary",
149 "Read summary from given bitcode or YAML file before running pass"),
153 "wholeprogramdevirt-write-summary",
154 cl::desc(
"Write summary to given bitcode or YAML file after running pass. "
155 "Output file format is deduced from extension: *.bc means writing "
156 "bitcode, otherwise YAML"),
162 "devirtualize-speculatively",
163 cl::desc(
"Enable speculative devirtualization optimization"),
169 cl::desc(
"Maximum number of call targets per "
170 "call site to enable branch funnels"));
174 cl::desc(
"Print index-based devirtualization messages"));
182 cl::desc(
"Enable whole program visibility"));
187 "disable-whole-program-visibility",
cl::Hidden,
188 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
193 cl::desc(
"Prevent function(s) from being devirtualized"),
218 "wholeprogramdevirt-keep-unreachable-function",
219 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
226 "wholeprogramdevirt-cutoff",
227 cl::desc(
"Max number of devirtualizations for devirt module pass"),
238 cl::desc(
"Type of checking for incorrect devirtualizations"),
242 "Fallback to indirect when incorrect")));
246 std::vector<GlobPattern> Patterns;
247 template <
class T>
void init(
const T &StringList) {
248 for (
const auto &S : StringList)
250 Patterns.push_back(std::move(*Pat));
252 bool match(StringRef S) {
253 for (
const GlobPattern &
P : Patterns)
271 MinByte = std::max(MinByte,
Target.minAfterBytes());
273 MinByte = std::max(MinByte,
Target.minBeforeBytes());
296 std::vector<ArrayRef<uint8_t>> Used;
299 :
Target.TM->Bits->Before.BytesUsed;
301 : MinByte -
Target.minBeforeBytes();
311 for (
unsigned I = 0;; ++
I) {
313 for (
auto &&
B : Used)
316 if (BitsUsed != 0xff)
322 for (
unsigned I = 0;; ++
I) {
323 for (
auto &&
B : Used) {
325 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
343 OffsetByte = -(AllocBefore / 8 + 1);
345 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
346 OffsetBit = AllocBefore % 8;
350 Target.setBeforeBit(AllocBefore);
360 OffsetByte = AllocAfter / 8;
362 OffsetByte = (AllocAfter + 7) / 8;
363 OffsetBit = AllocAfter % 8;
367 Target.setAfterBit(AllocAfter);
381static unsigned NumDevirtCalls = 0;
407 const VTableSlot &RHS) {
408 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
427 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
451 if (!Summary->isLive())
454 if (!FS->fflags().MustBeUnreachable)
469struct VirtualCallSite {
476 unsigned *NumUnsafeUses =
nullptr;
479 emitRemark(
const StringRef OptName,
const StringRef TargetName,
480 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter) {
486 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE, OptName, DLoc,
Block)
487 <<
NV(
"Optimization", OptName)
488 <<
": devirtualized a call to "
489 <<
NV(
"FunctionName", TargetName));
492 void replaceAndErase(
493 const StringRef OptName,
const StringRef TargetName,
bool RemarksEnabled,
494 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter,
501 II->getUnwindDest()->removePredecessor(
II->getParent());
518 std::vector<VirtualCallSite> CallSites;
527 bool AllCallSitesDevirted =
true;
536 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
540 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
542 bool isExported()
const {
543 return !SummaryTypeCheckedLoadUsers.empty() ||
544 !SummaryTypeTestAssumeUsers.empty();
547 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
548 SummaryTypeCheckedLoadUsers.push_back(FS);
549 AllCallSitesDevirted =
false;
552 void addSummaryTypeTestAssumeUser(FunctionSummary *FS) {
553 SummaryTypeTestAssumeUsers.push_back(FS);
554 AllCallSitesDevirted =
false;
557 void markDevirt() { AllCallSitesDevirted =
true; }
561struct VTableSlotInfo {
568 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
570 void addCallSite(
Value *VTable, CallBase &CB,
unsigned *NumUnsafeUses);
576CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) {
577 std::vector<uint64_t>
Args;
579 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
583 if (!CI || CI->getBitWidth() > 64)
585 Args.push_back(CI->getZExtValue());
587 return ConstCSInfo[
Args];
590void VTableSlotInfo::addCallSite(
Value *VTable, CallBase &CB,
591 unsigned *NumUnsafeUses) {
592 auto &CSI = findCallSiteInfo(CB);
593 CSI.AllCallSitesDevirted =
false;
594 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
602 ModuleSummaryIndex *
const ExportSummary;
603 const ModuleSummaryIndex *
const ImportSummary;
605 IntegerType *
const Int8Ty;
608 IntegerType *
const Int64Ty;
609 IntegerType *
const IntPtrTy;
615 const bool RemarksEnabled;
616 std::function<OptimizationRemarkEmitter &(
Function &)> OREGetter;
617 MapVector<VTableSlot, VTableSlotInfo> CallSlots;
622 SmallPtrSet<CallBase *, 8> OptimizedCalls;
636 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
637 PatternList FunctionsToSkip;
640 ModuleSummaryIndex *ExportSummary,
641 const ModuleSummaryIndex *ImportSummary)
644 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
649 IntPtrTy(
M.getDataLayout().getIntPtrType(
M.
getContext(), 0)),
651 RemarksEnabled(areRemarksEnabled()),
652 OREGetter([&](
Function &
F) -> OptimizationRemarkEmitter & {
655 assert(!(ExportSummary && ImportSummary));
659 bool areRemarksEnabled();
662 scanTypeTestUsers(Function *TypeTestFunc,
663 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
664 void scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc);
666 void buildTypeIdentifierMap(
667 std::vector<VTableBits> &Bits,
668 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
671 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
672 const std::set<TypeMemberInfo> &TypeMemberInfos,
674 ModuleSummaryIndex *ExportSummary);
676 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
678 bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
680 VTableSlotInfo &SlotInfo,
681 WholeProgramDevirtResolution *Res);
683 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Function &JT,
686 VTableSlotInfo &SlotInfo,
687 WholeProgramDevirtResolution *Res, VTableSlot Slot);
689 bool tryEvaluateFunctionsWithArgs(
691 ArrayRef<uint64_t> Args);
693 void applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
697 WholeProgramDevirtResolution::ByArg *Res);
701 std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
704 bool shouldExportConstantsAsAbsoluteSymbols();
709 void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
711 void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
712 uint32_t Const, uint32_t &Storage);
716 Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
718 Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
719 StringRef Name, IntegerType *IntTy,
722 Constant *getMemberAddr(
const TypeMemberInfo *M);
724 void applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
bool IsOne,
725 Constant *UniqueMemberAddr);
726 bool tryUniqueRetValOpt(
unsigned BitWidth,
729 WholeProgramDevirtResolution::ByArg *Res,
730 VTableSlot Slot, ArrayRef<uint64_t> Args);
732 void applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
733 Constant *Byte, Constant *Bit);
735 VTableSlotInfo &SlotInfo,
736 WholeProgramDevirtResolution *Res, VTableSlot Slot);
738 void rebuildGlobal(VTableBits &
B);
741 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
745 void removeRedundantTypeTests();
752 static ValueInfo lookUpFunctionValueInfo(Function *TheFn,
753 ModuleSummaryIndex *ExportSummary);
764 ModuleSummaryIndex *ExportSummary);
772 ModuleSummaryIndex &ExportSummary;
775 std::set<GlobalValue::GUID> &ExportedGUIDs;
779 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
781 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
783 PatternList FunctionsToSkip;
786 ModuleSummaryIndex &ExportSummary,
787 std::set<GlobalValue::GUID> &ExportedGUIDs,
788 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap)
789 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
790 LocalWPDTargetsMap(LocalWPDTargetsMap) {
794 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
796 uint64_t ByteOffset);
799 VTableSlotSummary &SlotSummary,
800 VTableSlotInfo &SlotInfo,
801 WholeProgramDevirtResolution *Res,
802 std::set<ValueInfo> &DevirtTargets);
811 if (!DevirtModule::runForTesting(M,
MAM))
833 if (
TypeID.ends_with(
".virtual"))
839 if (!
TypeID.consume_front(
"_ZTS"))
847 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
848 return IsVisibleToRegularObj(TypeInfo);
857 for (
auto *
Type : Types)
860 IsVisibleToRegularObj);
869 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
871 bool ValidateAllVtablesHaveTypeInfos,
888 !(ValidateAllVtablesHaveTypeInfos &&
895 bool WholeProgramVisibilityEnabledInLTO) {
899 if (!PublicTypeTestFunc)
907 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
909 CI->replaceAllUsesWith(NewCI);
910 CI->eraseFromParent();
918 CI->replaceAllUsesWith(True);
919 CI->eraseFromParent();
930 for (
const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
933 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
946 for (
auto &
P : Index) {
949 if (DynamicExportSymbols.
count(
P.first))
955 if (VisibleToRegularObjSymbols.
count(
P.first))
957 for (
auto &S :
P.second.getSummaryList()) {
969 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
970 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap).run();
976 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
977 for (
auto &
T : LocalWPDTargetsMap) {
980 assert(VI.getSummaryList().size() == 1 &&
981 "Devirt of local target has more than one copy");
982 auto &S = VI.getSummaryList()[0];
983 if (!IsExported(S->modulePath(), VI))
987 for (
auto &SlotSummary :
T.second) {
988 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
990 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
991 assert(WPDRes != TIdSum->WPDRes.end());
993 WPDRes->second.SingleImplName,
994 Summary.getModuleHash(S->modulePath()));
1004 const auto &ModPaths = Summary->modulePaths();
1009 "combined summary should contain Regular LTO module");
1014 std::unique_ptr<ModuleSummaryIndex>
Summary =
1015 std::make_unique<ModuleSummaryIndex>(
false);
1020 ExitOnError ExitOnErr(
"-wholeprogramdevirt-read-summary: " +
ClReadSummary +
1022 auto ReadSummaryFile =
1024 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1026 Summary = std::move(*SummaryOrErr);
1031 yaml::Input
In(ReadSummaryFile->getBuffer());
1038 DevirtModule(M,
MAM,
1046 ExitOnError ExitOnErr(
1056 yaml::Output Out(OS);
1064void DevirtModule::buildTypeIdentifierMap(
1065 std::vector<VTableBits> &Bits,
1066 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1067 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1068 Bits.reserve(
M.global_size());
1070 for (GlobalVariable &GV :
M.globals()) {
1078 Bits.emplace_back();
1079 Bits.back().GV = &GV;
1080 Bits.back().ObjectSize =
1082 BitsPtr = &
Bits.back();
1085 for (MDNode *
Type : Types) {
1098bool DevirtModule::tryFindVirtualCallTargets(
1099 std::vector<VirtualCallTarget> &TargetsForSlot,
1100 const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset,
1101 ModuleSummaryIndex *ExportSummary) {
1103 if (!
TM.Bits->GV->isConstant())
1120 if (FunctionsToSkip.match(Fn->
getName()))
1125 if (Fn->
getName() ==
"__cxa_pure_virtual")
1143 TargetsForSlot.push_back({GV, &
TM});
1147 return !TargetsForSlot.empty();
1150bool DevirtIndex::tryFindVirtualCallTargets(
1151 std::vector<ValueInfo> &TargetsForSlot,
1153 for (
const TypeIdOffsetVtableInfo &
P : TIdInfo) {
1164 if (
P.VTableVI.hasLocal() &&
P.VTableVI.getSummaryList().size() > 1)
1166 const GlobalVarSummary *
VS =
nullptr;
1167 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1169 if (!CurVS->vTableFuncs().empty() ||
1192 for (
auto VTP :
VS->vTableFuncs()) {
1193 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1199 TargetsForSlot.push_back(VTP.FuncVI);
1204 return !TargetsForSlot.empty();
1207void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1208 Constant *TheFn,
bool &IsExported) {
1214 for (
auto &&VCallSite : CSInfo.CallSites) {
1215 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1224 VCallSite.emitRemark(
"single-impl",
1228 auto &CB = VCallSite.CB;
1241 MDBuilder(
M.getContext()).createUnlikelyBranchWeights());
1242 Builder.SetInsertPoint(ThenTerm);
1245 auto *CallTrap = Builder.CreateCall(TrapFn);
1255 MDNode *Weights = MDBuilder(
M.getContext()).createLikelyBranchWeights();
1264 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1265 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1287 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1292 if (VCallSite.NumUnsafeUses)
1293 --*VCallSite.NumUnsafeUses;
1295 if (CSInfo.isExported())
1297 CSInfo.markDevirt();
1299 Apply(SlotInfo.CSInfo);
1300 for (
auto &
P : SlotInfo.ConstCSInfo)
1306 if (Callee.getSummaryList().empty())
1313 bool IsExported =
false;
1314 auto &S = Callee.getSummaryList()[0];
1317 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1318 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1319 FS->addCall({Callee, CI});
1320 IsExported |= S->modulePath() != FS->modulePath();
1322 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1323 FS->addCall({Callee, CI});
1324 IsExported |= S->modulePath() != FS->modulePath();
1327 AddCalls(SlotInfo.CSInfo);
1328 for (
auto &
P : SlotInfo.ConstCSInfo)
1333bool DevirtModule::trySingleImplDevirt(
1334 ModuleSummaryIndex *ExportSummary,
1336 WholeProgramDevirtResolution *Res) {
1339 auto *TheFn = TargetsForSlot[0].Fn;
1340 for (
auto &&Target : TargetsForSlot)
1346 TargetsForSlot[0].WasDevirt =
true;
1348 bool IsExported =
false;
1349 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1356 if (TheFn->hasLocalLinkage()) {
1357 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1362 if (Comdat *
C = TheFn->getComdat()) {
1363 if (
C->getName() == TheFn->
getName()) {
1364 Comdat *NewC =
M.getOrInsertComdat(NewName);
1366 for (GlobalObject &GO :
M.global_objects())
1367 if (GO.getComdat() ==
C)
1376 if (ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFn->getGUID()))
1388 VTableSlotSummary &SlotSummary,
1389 VTableSlotInfo &SlotInfo,
1390 WholeProgramDevirtResolution *Res,
1391 std::set<ValueInfo> &DevirtTargets) {
1394 auto TheFn = TargetsForSlot[0];
1395 for (
auto &&Target : TargetsForSlot)
1396 if (TheFn != Target)
1400 auto Size = TheFn.getSummaryList().size();
1406 if (FunctionsToSkip.match(TheFn.name()))
1411 if (TheFn.hasLocal() &&
Size > 1)
1416 DevirtTargets.insert(TheFn);
1418 auto &S = TheFn.getSummaryList()[0];
1419 bool IsExported =
addCalls(SlotInfo, TheFn);
1421 ExportedGUIDs.insert(TheFn.getGUID());
1432 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1434 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1448void DevirtModule::tryICallBranchFunnel(
1450 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1451 Triple
T(
M.getTargetTriple());
1458 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1460 for (
auto &
P : SlotInfo.ConstCSInfo)
1461 if (!
P.second.AllCallSitesDevirted) {
1462 HasNonDevirt =
true;
1480 for (
auto &
T : TargetsForSlot) {
1481 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1490 M.getDataLayout().getProgramAddressSpace(),
1491 getGlobalName(Slot, {},
"branch_funnel"), &
M);
1495 M.getDataLayout().getProgramAddressSpace(),
1496 "branch_funnel", &M);
1498 JT->addParamAttr(0, Attribute::Nest);
1500 std::vector<Value *> JTArgs;
1501 JTArgs.push_back(
JT->arg_begin());
1502 for (
auto &
T : TargetsForSlot) {
1503 JTArgs.push_back(getMemberAddr(
T.TM));
1504 JTArgs.push_back(
T.Fn);
1509 &M, llvm::Intrinsic::icall_branch_funnel, {});
1515 bool IsExported =
false;
1516 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1520 if (!
JT->getEntryCount().has_value()) {
1526void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1527 Function &JT,
bool &IsExported) {
1528 DenseMap<Function *, double> FunctionEntryCounts;
1530 if (CSInfo.isExported())
1532 if (CSInfo.AllCallSitesDevirted)
1535 std::map<CallBase *, CallBase *> CallBases;
1536 for (
auto &&VCallSite : CSInfo.CallSites) {
1537 CallBase &CB = VCallSite.CB;
1539 if (CallBases.find(&CB) != CallBases.end()) {
1556 VCallSite.emitRemark(
"branch-funnel",
JT.getName(), OREGetter);
1560 std::vector<Type *> NewArgs;
1561 NewArgs.push_back(Int8PtrTy);
1563 FunctionType *NewFT =
1567 std::vector<Value *>
Args;
1568 Args.push_back(VCallSite.VTable);
1571 CallBase *NewCS =
nullptr;
1577 auto EC =
BFI.getBlockFreq(&
F.getEntryBlock());
1578 auto CC =
F.getEntryCount(
true);
1579 double CallCount = 0.0;
1580 if (
EC.getFrequency() != 0 && CC && CC->getCount() != 0) {
1582 static_cast<double>(
1585 CallCount = CallFreq * CC->getCount();
1587 FunctionEntryCounts[&
JT] += CallCount;
1590 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1598 std::vector<AttributeSet> NewArgAttrs;
1601 M.getContext(), Attribute::Nest)}));
1602 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1603 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1605 AttributeList::get(
M.getContext(),
Attrs.getFnAttrs(),
1606 Attrs.getRetAttrs(), NewArgAttrs));
1608 CallBases[&CB] = NewCS;
1611 if (VCallSite.NumUnsafeUses)
1612 --*VCallSite.NumUnsafeUses;
1619 for (
auto &[Old, New] : CallBases) {
1620 Old->replaceAllUsesWith(New);
1621 Old->eraseFromParent();
1624 Apply(SlotInfo.CSInfo);
1625 for (
auto &
P : SlotInfo.ConstCSInfo)
1627 for (
auto &[
F,
C] : FunctionEntryCounts) {
1628 assert(!
F->getEntryCount(
true) &&
1629 "Unexpected entry count for funnel that was freshly synthesized");
1630 F->setEntryCount(
static_cast<uint64_t
>(std::round(
C)));
1634bool DevirtModule::tryEvaluateFunctionsWithArgs(
1636 ArrayRef<uint64_t> Args) {
1650 Evaluator Eval(
M.getDataLayout(),
nullptr);
1654 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1659 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1663 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1671void DevirtModule::applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1672 uint64_t TheRetVal) {
1673 for (
auto Call : CSInfo.CallSites) {
1677 Call.replaceAndErase(
1678 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1681 CSInfo.markDevirt();
1684bool DevirtModule::tryUniformRetValOpt(
1686 WholeProgramDevirtResolution::ByArg *Res) {
1689 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1691 if (
Target.RetVal != TheRetVal)
1694 if (CSInfo.isExported()) {
1696 Res->
Info = TheRetVal;
1699 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1701 for (
auto &&Target : TargetsForSlot)
1706std::string DevirtModule::getGlobalName(VTableSlot Slot,
1707 ArrayRef<uint64_t> Args,
1709 std::string FullName =
"__typeid_";
1710 raw_string_ostream OS(FullName);
1711 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1712 for (uint64_t Arg : Args)
1718bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1719 Triple
T(
M.getTargetTriple());
1723void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1724 StringRef Name, Constant *
C) {
1726 getGlobalName(Slot, Args, Name),
C, &M);
1730void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1731 StringRef Name, uint32_t Const,
1732 uint32_t &Storage) {
1733 if (shouldExportConstantsAsAbsoluteSymbols()) {
1743Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1745 GlobalVariable *GV =
1746 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1751Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1752 StringRef Name, IntegerType *IntTy,
1754 if (!shouldExportConstantsAsAbsoluteSymbols())
1755 return ConstantInt::get(IntTy, Storage);
1757 Constant *
C = importGlobal(Slot, Args, Name);
1763 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1766 auto SetAbsRange = [&](uint64_t Min, uint64_t
Max) {
1774 SetAbsRange(~0ull, ~0ull);
1776 SetAbsRange(0, 1ull << AbsWidth);
1780void DevirtModule::applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1782 Constant *UniqueMemberAddr) {
1783 for (
auto &&
Call : CSInfo.CallSites) {
1789 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->
getType()));
1792 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1795 CSInfo.markDevirt();
1800 ConstantInt::get(Int64Ty,
M->Offset));
1803bool DevirtModule::tryUniqueRetValOpt(
1805 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1806 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1808 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1811 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1814 UniqueMember =
Target.TM;
1822 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1823 if (CSInfo.isExported()) {
1827 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1831 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1836 for (
auto &&Target : TargetsForSlot)
1843 if (tryUniqueRetValOptFor(
true))
1845 if (tryUniqueRetValOptFor(
false))
1851void DevirtModule::applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
1852 Constant *Byte, Constant *Bit) {
1853 for (
auto Call : CSInfo.CallSites) {
1858 Value *Addr =
B.CreatePtrAdd(
Call.VTable, Byte);
1859 if (RetType->getBitWidth() == 1) {
1861 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1862 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1863 NumVirtConstProp1Bit++;
1864 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1865 OREGetter, IsBitSet);
1867 Value *Val =
B.CreateLoad(RetType, Addr);
1869 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1873 CSInfo.markDevirt();
1876bool DevirtModule::tryVirtualConstProp(
1878 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1889 unsigned BitWidth = RetType->getBitWidth();
1901 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1934 GlobalVariable *GV =
Target.TM->Bits->GV;
1935 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1937 if (TypeAlignment > TableAlignment)
1941 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1942 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1945 WholeProgramDevirtResolution::ByArg *ResByArg =
nullptr;
1947 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1949 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1952 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1953 ResByArg, Slot, CSByConstantArg.first))
1961 uint64_t AllocBefore =
1963 uint64_t AllocAfter =
1968 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1969 for (
auto &&Target : TargetsForSlot) {
1970 TotalPaddingBefore += std::max<int64_t>(
1971 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1972 TotalPaddingAfter += std::max<int64_t>(
1973 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1978 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1985 if (TotalPaddingBefore <= TotalPaddingAfter)
2001 for (
auto &&Target : TargetsForSlot)
2005 if (CSByConstantArg.second.isExported()) {
2007 exportConstant(Slot, CSByConstantArg.first,
"byte", OffsetByte,
2009 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
2015 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
2016 applyVirtualConstProp(CSByConstantArg.second,
2017 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
2023 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
2028 Align Alignment =
M.getDataLayout().getValueOrABITypeAlignment(
2029 B.GV->getAlign(),
B.GV->getValueType());
2030 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
2033 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
2040 B.GV->getInitializer(),
2043 new GlobalVariable(M, NewInit->getType(),
B.GV->isConstant(),
2045 NewGV->setSection(
B.GV->getSection());
2046 NewGV->setComdat(
B.GV->getComdat());
2047 NewGV->setAlignment(
B.GV->getAlign());
2051 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
2056 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2058 NewInit->getType(), NewGV,
2060 ConstantInt::get(Int32Ty, 1)}),
2062 Alias->setVisibility(
B.GV->getVisibility());
2063 Alias->takeName(
B.GV);
2065 B.GV->replaceAllUsesWith(Alias);
2066 B.GV->eraseFromParent();
2069bool DevirtModule::areRemarksEnabled() {
2070 const auto &FL =
M.getFunctionList();
2071 for (
const Function &Fn : FL) {
2075 return DI.isEnabled();
2080void DevirtModule::scanTypeTestUsers(
2081 Function *TypeTestFunc,
2082 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2096 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2102 if (!Assumes.
empty()) {
2103 Value *
Ptr = CI->getArgOperand(0)->stripPointerCasts();
2104 for (DevirtCallSite
Call : DevirtCalls)
2105 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
nullptr);
2108 auto RemoveTypeTestAssumes = [&]() {
2110 for (
auto *Assume : Assumes)
2111 Assume->eraseFromParent();
2114 if (CI->use_empty())
2115 CI->eraseFromParent();
2130 if (!TypeIdMap.count(TypeId))
2131 RemoveTypeTestAssumes();
2143 const TypeIdSummary *TidSummary =
2146 RemoveTypeTestAssumes();
2155void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {
2166 Value *TypeIdValue = CI->getArgOperand(2);
2172 bool HasNonCallUses =
false;
2173 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2175 HasNonCallUses, CI, DT);
2184 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2186 Value *LoadedValue =
nullptr;
2188 Intrinsic::type_checked_load_relative) {
2190 &M, Intrinsic::load_relative, {
Int32Ty});
2191 LoadedValue = LoadB.CreateCall(LoadRelFunc, {
Ptr,
Offset});
2194 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2197 for (Instruction *LoadedPtr : LoadedPtrs) {
2198 LoadedPtr->replaceAllUsesWith(LoadedValue);
2199 LoadedPtr->eraseFromParent();
2203 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2204 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {
Ptr, TypeIdValue});
2206 for (Instruction *Pred : Preds) {
2207 Pred->replaceAllUsesWith(TypeTestCall);
2208 Pred->eraseFromParent();
2215 if (!CI->use_empty()) {
2218 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2219 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2224 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2225 NumUnsafeUses = DevirtCalls.
size();
2232 for (DevirtCallSite
Call : DevirtCalls) {
2233 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
2237 CI->eraseFromParent();
2241void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2245 const TypeIdSummary *TidSummary =
2249 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2250 if (ResI == TidSummary->
WPDRes.end())
2252 const WholeProgramDevirtResolution &Res = ResI->second;
2264 bool IsExported =
false;
2265 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2269 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2270 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2273 auto &ResByArg =
I->second;
2280 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2284 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2285 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2290 Constant *
Byte = importConstant(Slot, CSByConstantArg.first,
"byte",
2292 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2294 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2306 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2309 bool IsExported =
false;
2310 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2315void DevirtModule::removeRedundantTypeTests() {
2317 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2318 if (
U.second == 0) {
2319 U.first->replaceAllUsesWith(True);
2320 U.first->eraseFromParent();
2326DevirtModule::lookUpFunctionValueInfo(Function *TheFn,
2327 ModuleSummaryIndex *ExportSummary) {
2328 assert((ExportSummary !=
nullptr) &&
2329 "Caller guarantees ExportSummary is not nullptr");
2331 const auto TheFnGUID = TheFn->
getGUID();
2332 const auto TheFnGUIDWithExportedName =
2335 ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFnGUID);
2344 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2345 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2350bool DevirtModule::mustBeUnreachableFunction(
2351 Function *
const F, ModuleSummaryIndex *ExportSummary) {
2355 if (!
F->isDeclaration()) {
2361 return ExportSummary &&
2363 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2366bool DevirtModule::run() {
2375 Function *PublicTypeTestFunc =
nullptr;
2379 PublicTypeTestFunc =
2386 &M, Intrinsic::type_checked_load_relative);
2393 if (!ExportSummary &&
2394 (((!PublicTypeTestFunc || PublicTypeTestFunc->
use_empty()) &&
2395 (!TypeTestFunc || TypeTestFunc->
use_empty())) ||
2396 !AssumeFunc || AssumeFunc->
use_empty()) &&
2397 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2398 (!TypeCheckedLoadRelativeFunc ||
2399 TypeCheckedLoadRelativeFunc->
use_empty()))
2403 std::vector<VTableBits>
Bits;
2404 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2405 buildTypeIdentifierMap(Bits, TypeIdMap);
2407 if (PublicTypeTestFunc && AssumeFunc)
2408 scanTypeTestUsers(PublicTypeTestFunc, TypeIdMap);
2410 if (TypeTestFunc && AssumeFunc)
2411 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2413 if (TypeCheckedLoadFunc)
2414 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2416 if (TypeCheckedLoadRelativeFunc)
2417 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2419 if (ImportSummary) {
2420 for (
auto &S : CallSlots)
2421 importResolution(S.first, S.second);
2423 removeRedundantTypeTests();
2428 for (GlobalVariable &GV :
M.globals())
2436 if (TypeIdMap.
empty())
2440 if (ExportSummary) {
2441 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2442 for (
auto &
P : TypeIdMap) {
2445 TypeId->getString())]
2449 for (
auto &
P : *ExportSummary) {
2450 for (
auto &S :
P.second.getSummaryList()) {
2455 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2456 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2457 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2460 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2461 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2462 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2465 for (
const FunctionSummary::ConstVCall &VC :
2466 FS->type_test_assume_const_vcalls()) {
2467 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2468 CallSlots[{MD,
VC.VFunc.Offset}]
2469 .ConstCSInfo[
VC.Args]
2470 .addSummaryTypeTestAssumeUser(FS);
2473 for (
const FunctionSummary::ConstVCall &VC :
2474 FS->type_checked_load_const_vcalls()) {
2475 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2476 CallSlots[{MD,
VC.VFunc.Offset}]
2477 .ConstCSInfo[
VC.Args]
2478 .addSummaryTypeCheckedLoadUser(FS);
2486 bool DidVirtualConstProp =
false;
2487 std::map<std::string, GlobalValue *> DevirtTargets;
2488 for (
auto &S : CallSlots) {
2492 std::vector<VirtualCallTarget> TargetsForSlot;
2493 WholeProgramDevirtResolution *Res =
nullptr;
2494 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2496 TypeMemberInfos.size())
2503 Res = &ExportSummary
2504 ->getOrInsertTypeIdSummary(
2506 .WPDRes[S.first.ByteOffset];
2507 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2508 S.first.ByteOffset, ExportSummary)) {
2509 bool SingleImplDevirt =
2510 trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res);
2515 DidVirtualConstProp |=
2516 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2518 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2523 for (
const auto &
T : TargetsForSlot)
2525 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2535 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2536 if (!CSI.AllCallSitesDevirted)
2537 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2538 FS->addTypeTest(GUID);
2540 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2541 for (
auto &CCS : S.second.ConstCSInfo)
2542 AddTypeTestsForTypeCheckedLoads(CCS.second);
2546 if (RemarksEnabled) {
2548 for (
const auto &DT : DevirtTargets) {
2549 GlobalValue *GV = DT.second;
2558 using namespace ore;
2559 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE,
"Devirtualized",
F)
2560 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2564 NumDevirtTargets += DevirtTargets.size();
2566 removeRedundantTypeTests();
2570 if (DidVirtualConstProp)
2577 for (GlobalVariable &GV :
M.globals())
2580 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2581 CI->eraseFromParent();
2586void DevirtIndex::run() {
2587 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2592 assert(!ExportSummary.withInternalizeAndPromote() &&
2593 "Expect index-based WPD to run before internalization and promotion");
2595 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2596 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2605 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2609 for (
auto &
P : ExportSummary) {
2610 for (
auto &S :
P.second.getSummaryList()) {
2615 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2616 for (StringRef Name : NameByGUID[VF.GUID]) {
2617 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2620 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2621 for (StringRef Name : NameByGUID[VF.GUID]) {
2622 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2625 for (
const FunctionSummary::ConstVCall &VC :
2626 FS->type_test_assume_const_vcalls()) {
2627 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2628 CallSlots[{
Name,
VC.VFunc.Offset}]
2629 .ConstCSInfo[
VC.Args]
2630 .addSummaryTypeTestAssumeUser(FS);
2633 for (
const FunctionSummary::ConstVCall &VC :
2634 FS->type_checked_load_const_vcalls()) {
2635 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2636 CallSlots[{
Name,
VC.VFunc.Offset}]
2637 .ConstCSInfo[
VC.Args]
2638 .addSummaryTypeCheckedLoadUser(FS);
2644 std::set<ValueInfo> DevirtTargets;
2646 for (
auto &S : CallSlots) {
2650 std::vector<ValueInfo> TargetsForSlot;
2651 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2655 WholeProgramDevirtResolution *Res =
2656 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2657 ->WPDRes[S.first.ByteOffset];
2658 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2659 S.first.ByteOffset)) {
2661 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2670 for (
const auto &DT : DevirtTargets)
2671 errs() <<
"Devirtualized call to " << DT <<
"\n";
2673 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< 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 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
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)
static cl::opt< unsigned > WholeProgramDevirtCutoff("wholeprogramdevirt-cutoff", cl::desc("Max number of devirtualizations for devirt module pass"), cl::init(0))
If explicitly specified, the devirt module pass will stop transformation once the total number of dev...
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
static 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.
static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)
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 LLVM_ABI Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReducedTy=nullptr)
Getelementptr form.
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
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.
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...
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={})
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...
bool hasMetadata() const
Return true if this value has any metadata attached to it.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
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 current metadata attachments for the given kind, if any.
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)
GUID getGUID() const
Return a 64-bit global unique ID constructed from global value name (i.e.
@ HiddenVisibility
The GV is hidden.
void setVisibility(VisibilityTypes V)
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
@ ExternalLinkage
Externally visible function.
Type * getValueType() const
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.
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.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
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.
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.
StringRef - Represent a constant reference to a string, i.e.
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
Target - Wrapper for Target specific information.
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'.
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 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.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
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.
bool match(Val *V, const Pattern &P)
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
@ Assume
Do not drop type tests (default).
DiagnosticInfoOptimizationBase::Argument NV
Context & getContext() const
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.
FunctionAddr VTableAddr Value
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.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
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.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
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.
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)
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.
LLVM_ABI void updateIndexWPDForExports(ModuleSummaryIndex &Summary, function_ref< bool(StringRef, ValueInfo)> isExported, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap)
Call after cross-module importing to update the recorded single impl devirt target names for any loca...
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.
LLVM_ABI void runWholeProgramDevirtOnIndex(ModuleSummaryIndex &Summary, std::set< GlobalValue::GUID > &ExportedGUIDs, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap)
Perform index-based whole program devirtualization on the Summary index.
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)
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<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.
cl::opt< bool > ProfcheckDisableMetadataFixes("profcheck-disable-metadata-fixes", cl::Hidden, cl::init(false), cl::desc("Disable metadata propagation fixes discovered through Issue #147390"))
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.
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.
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 VTableSlotSummary getTombstoneKey()
static VTableSlotSummary getEmptyKey()
static VTableSlot getTombstoneKey()
static VTableSlot getEmptyKey()
static bool isEqual(const VTableSlot &LHS, const VTableSlot &RHS)
static unsigned getHashValue(const VTableSlot &I)
An information struct used to provide DenseMap with the various necessary components for a given valu...
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