112#define DEBUG_TYPE "wholeprogramdevirt"
114STATISTIC(NumDevirtTargets,
"Number of whole program devirtualization targets");
115STATISTIC(NumSingleImpl,
"Number of single implementation devirtualizations");
117STATISTIC(NumUniformRetVal,
"Number of uniform return value optimizations");
118STATISTIC(NumUniqueRetVal,
"Number of unique return value optimizations");
120 "Number of 1 bit virtual constant propagations");
121STATISTIC(NumVirtConstProp,
"Number of virtual constant propagations");
126 "wholeprogramdevirt-summary-action",
127 cl::desc(
"What to do with the summary when running this pass"),
130 "Import typeid resolutions from summary and globals"),
132 "Export typeid resolutions to summary and globals")),
136 "wholeprogramdevirt-read-summary",
138 "Read summary from given bitcode or YAML file before running pass"),
142 "wholeprogramdevirt-write-summary",
143 cl::desc(
"Write summary to given bitcode or YAML file after running pass. "
144 "Output file format is deduced from extension: *.bc means writing "
145 "bitcode, otherwise YAML"),
151 cl::desc(
"Maximum number of call targets per "
152 "call site to enable branch funnels"));
156 cl::desc(
"Print index-based devirtualization messages"));
164 cl::desc(
"Enable whole program visibility"));
169 "disable-whole-program-visibility",
cl::Hidden,
170 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
175 cl::desc(
"Prevent function(s) from being devirtualized"),
200 "wholeprogramdevirt-keep-unreachable-function",
201 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
208 "wholeprogramdevirt-cutoff",
209 cl::desc(
"Max number of devirtualizations for devirt module pass"),
220 cl::desc(
"Type of checking for incorrect devirtualizations"),
224 "Fallback to indirect when incorrect")));
228 std::vector<GlobPattern> Patterns;
229 template <
class T>
void init(
const T &StringList) {
230 for (
const auto &S : StringList)
232 Patterns.push_back(std::move(*Pat));
234 bool match(StringRef S) {
235 for (
const GlobPattern &
P : Patterns)
253 MinByte = std::max(MinByte,
Target.minAfterBytes());
255 MinByte = std::max(MinByte,
Target.minBeforeBytes());
278 std::vector<ArrayRef<uint8_t>> Used;
281 :
Target.TM->Bits->Before.BytesUsed;
283 : MinByte -
Target.minBeforeBytes();
293 for (
unsigned I = 0;; ++
I) {
295 for (
auto &&
B : Used)
298 if (BitsUsed != 0xff)
304 for (
unsigned I = 0;; ++
I) {
305 for (
auto &&
B : Used) {
307 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
325 OffsetByte = -(AllocBefore / 8 + 1);
327 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
328 OffsetBit = AllocBefore % 8;
332 Target.setBeforeBit(AllocBefore);
342 OffsetByte = AllocAfter / 8;
344 OffsetByte = (AllocAfter + 7) / 8;
345 OffsetBit = AllocAfter % 8;
349 Target.setAfterBit(AllocAfter);
363static unsigned NumDevirtCalls = 0;
391 const VTableSlot &RHS) {
392 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
411 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
437 if (!Summary->isLive())
440 if (!FS->fflags().MustBeUnreachable)
455struct VirtualCallSite {
462 unsigned *NumUnsafeUses =
nullptr;
465 emitRemark(
const StringRef OptName,
const StringRef TargetName,
466 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter) {
472 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE, OptName, DLoc,
Block)
473 <<
NV(
"Optimization", OptName)
474 <<
": devirtualized a call to "
475 <<
NV(
"FunctionName", TargetName));
478 void replaceAndErase(
479 const StringRef OptName,
const StringRef TargetName,
bool RemarksEnabled,
480 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter,
487 II->getUnwindDest()->removePredecessor(
II->getParent());
504 std::vector<VirtualCallSite> CallSites;
513 bool AllCallSitesDevirted =
true;
522 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
526 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
528 bool isExported()
const {
529 return !SummaryTypeCheckedLoadUsers.empty() ||
530 !SummaryTypeTestAssumeUsers.empty();
533 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
534 SummaryTypeCheckedLoadUsers.push_back(FS);
535 AllCallSitesDevirted =
false;
538 void addSummaryTypeTestAssumeUser(FunctionSummary *FS) {
539 SummaryTypeTestAssumeUsers.push_back(FS);
540 AllCallSitesDevirted =
false;
543 void markDevirt() { AllCallSitesDevirted =
true; }
547struct VTableSlotInfo {
554 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
556 void addCallSite(
Value *VTable, CallBase &CB,
unsigned *NumUnsafeUses);
562CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) {
563 std::vector<uint64_t>
Args;
565 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
569 if (!CI || CI->getBitWidth() > 64)
571 Args.push_back(CI->getZExtValue());
573 return ConstCSInfo[
Args];
576void VTableSlotInfo::addCallSite(
Value *VTable, CallBase &CB,
577 unsigned *NumUnsafeUses) {
578 auto &CSI = findCallSiteInfo(CB);
579 CSI.AllCallSitesDevirted =
false;
580 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
588 ModuleSummaryIndex *
const ExportSummary;
589 const ModuleSummaryIndex *
const ImportSummary;
591 IntegerType *
const Int8Ty;
594 IntegerType *
const Int64Ty;
595 IntegerType *
const IntPtrTy;
601 const bool RemarksEnabled;
602 std::function<OptimizationRemarkEmitter &(
Function &)> OREGetter;
603 MapVector<VTableSlot, VTableSlotInfo> CallSlots;
608 SmallPtrSet<CallBase *, 8> OptimizedCalls;
622 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
623 PatternList FunctionsToSkip;
626 ModuleSummaryIndex *ExportSummary,
627 const ModuleSummaryIndex *ImportSummary)
630 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
635 IntPtrTy(
M.getDataLayout().getIntPtrType(
M.
getContext(), 0)),
637 RemarksEnabled(areRemarksEnabled()),
638 OREGetter([&](
Function &
F) -> OptimizationRemarkEmitter & {
641 assert(!(ExportSummary && ImportSummary));
645 bool areRemarksEnabled();
648 scanTypeTestUsers(Function *TypeTestFunc,
649 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
650 void scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc);
652 void buildTypeIdentifierMap(
653 std::vector<VTableBits> &Bits,
654 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
657 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
658 const std::set<TypeMemberInfo> &TypeMemberInfos,
660 ModuleSummaryIndex *ExportSummary);
662 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
664 bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
666 VTableSlotInfo &SlotInfo,
667 WholeProgramDevirtResolution *Res);
669 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Function &JT,
672 VTableSlotInfo &SlotInfo,
673 WholeProgramDevirtResolution *Res, VTableSlot Slot);
675 bool tryEvaluateFunctionsWithArgs(
677 ArrayRef<uint64_t> Args);
679 void applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
683 WholeProgramDevirtResolution::ByArg *Res);
687 std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
690 bool shouldExportConstantsAsAbsoluteSymbols();
695 void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
697 void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
698 uint32_t Const, uint32_t &Storage);
702 Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
704 Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
705 StringRef Name, IntegerType *IntTy,
708 Constant *getMemberAddr(
const TypeMemberInfo *M);
710 void applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
bool IsOne,
711 Constant *UniqueMemberAddr);
712 bool tryUniqueRetValOpt(
unsigned BitWidth,
715 WholeProgramDevirtResolution::ByArg *Res,
716 VTableSlot Slot, ArrayRef<uint64_t> Args);
718 void applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
719 Constant *Byte, Constant *Bit);
721 VTableSlotInfo &SlotInfo,
722 WholeProgramDevirtResolution *Res, VTableSlot Slot);
724 void rebuildGlobal(VTableBits &
B);
727 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
731 void removeRedundantTypeTests();
738 static ValueInfo lookUpFunctionValueInfo(Function *TheFn,
739 ModuleSummaryIndex *ExportSummary);
750 ModuleSummaryIndex *ExportSummary);
758 ModuleSummaryIndex &ExportSummary;
761 std::set<GlobalValue::GUID> &ExportedGUIDs;
765 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
767 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
769 PatternList FunctionsToSkip;
772 ModuleSummaryIndex &ExportSummary,
773 std::set<GlobalValue::GUID> &ExportedGUIDs,
774 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap)
775 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
776 LocalWPDTargetsMap(LocalWPDTargetsMap) {
780 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
782 uint64_t ByteOffset);
785 VTableSlotSummary &SlotSummary,
786 VTableSlotInfo &SlotInfo,
787 WholeProgramDevirtResolution *Res,
788 std::set<ValueInfo> &DevirtTargets);
797 if (!DevirtModule::runForTesting(M,
MAM))
819 if (
TypeID.ends_with(
".virtual"))
825 if (!
TypeID.consume_front(
"_ZTS"))
833 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
834 return IsVisibleToRegularObj(TypeInfo);
843 for (
auto *
Type : Types)
846 IsVisibleToRegularObj);
855 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
857 bool ValidateAllVtablesHaveTypeInfos,
874 !(ValidateAllVtablesHaveTypeInfos &&
881 bool WholeProgramVisibilityEnabledInLTO) {
885 if (!PublicTypeTestFunc)
893 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
895 CI->replaceAllUsesWith(NewCI);
896 CI->eraseFromParent();
902 CI->replaceAllUsesWith(True);
903 CI->eraseFromParent();
914 for (
const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
917 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
930 for (
auto &
P : Index) {
933 if (DynamicExportSymbols.
count(
P.first))
935 for (
auto &S :
P.second.SummaryList) {
944 if (VisibleToRegularObjSymbols.
count(
P.first))
953 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
954 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap).run();
960 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
961 for (
auto &
T : LocalWPDTargetsMap) {
964 assert(VI.getSummaryList().size() == 1 &&
965 "Devirt of local target has more than one copy");
966 auto &S = VI.getSummaryList()[0];
967 if (!IsExported(S->modulePath(), VI))
971 for (
auto &SlotSummary :
T.second) {
972 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
974 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
975 assert(WPDRes != TIdSum->WPDRes.end());
977 WPDRes->second.SingleImplName,
978 Summary.getModuleHash(S->modulePath()));
988 const auto &ModPaths = Summary->modulePaths();
993 "combined summary should contain Regular LTO module");
998 std::unique_ptr<ModuleSummaryIndex>
Summary =
999 std::make_unique<ModuleSummaryIndex>(
false);
1004 ExitOnError ExitOnErr(
"-wholeprogramdevirt-read-summary: " +
ClReadSummary +
1006 auto ReadSummaryFile =
1008 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1010 Summary = std::move(*SummaryOrErr);
1015 yaml::Input
In(ReadSummaryFile->getBuffer());
1022 DevirtModule(M,
MAM,
1030 ExitOnError ExitOnErr(
1040 yaml::Output Out(OS);
1048void DevirtModule::buildTypeIdentifierMap(
1049 std::vector<VTableBits> &Bits,
1050 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1051 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1052 Bits.reserve(
M.global_size());
1054 for (GlobalVariable &GV :
M.globals()) {
1060 VTableBits *&BitsPtr = GVToBits[&GV];
1062 Bits.emplace_back();
1063 Bits.back().GV = &GV;
1064 Bits.back().ObjectSize =
1066 BitsPtr = &
Bits.back();
1069 for (MDNode *
Type : Types) {
1082bool DevirtModule::tryFindVirtualCallTargets(
1083 std::vector<VirtualCallTarget> &TargetsForSlot,
1084 const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset,
1085 ModuleSummaryIndex *ExportSummary) {
1086 for (
const TypeMemberInfo &TM : TypeMemberInfos) {
1087 if (!
TM.Bits->GV->isConstant())
1092 if (
TM.Bits->GV->getVCallVisibility() ==
1104 if (FunctionsToSkip.match(Fn->
getName()))
1109 if (Fn->
getName() ==
"__cxa_pure_virtual")
1121 TargetsForSlot.push_back({GV, &
TM});
1125 return !TargetsForSlot.empty();
1128bool DevirtIndex::tryFindVirtualCallTargets(
1129 std::vector<ValueInfo> &TargetsForSlot,
1131 for (
const TypeIdOffsetVtableInfo &
P : TIdInfo) {
1142 const GlobalVarSummary *
VS =
nullptr;
1143 bool LocalFound =
false;
1144 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1151 if (!CurVS->vTableFuncs().empty() ||
1173 for (
auto VTP :
VS->vTableFuncs()) {
1174 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1180 TargetsForSlot.push_back(VTP.FuncVI);
1185 return !TargetsForSlot.empty();
1188void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1189 Constant *TheFn,
bool &IsExported) {
1195 for (
auto &&VCallSite : CSInfo.CallSites) {
1196 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1205 VCallSite.emitRemark(
"single-impl",
1209 auto &CB = VCallSite.CB;
1222 MDBuilder(
M.getContext()).createUnlikelyBranchWeights());
1223 Builder.SetInsertPoint(ThenTerm);
1226 auto *CallTrap = Builder.CreateCall(TrapFn);
1234 MDNode *Weights = MDBuilder(
M.getContext()).createLikelyBranchWeights();
1243 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1244 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1266 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1271 if (VCallSite.NumUnsafeUses)
1272 --*VCallSite.NumUnsafeUses;
1274 if (CSInfo.isExported())
1276 CSInfo.markDevirt();
1278 Apply(SlotInfo.CSInfo);
1279 for (
auto &
P : SlotInfo.ConstCSInfo)
1285 if (Callee.getSummaryList().empty())
1292 bool IsExported =
false;
1293 auto &S = Callee.getSummaryList()[0];
1296 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1297 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1298 FS->addCall({Callee, CI});
1299 IsExported |= S->modulePath() != FS->modulePath();
1301 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1302 FS->addCall({Callee, CI});
1303 IsExported |= S->modulePath() != FS->modulePath();
1306 AddCalls(SlotInfo.CSInfo);
1307 for (
auto &
P : SlotInfo.ConstCSInfo)
1312bool DevirtModule::trySingleImplDevirt(
1313 ModuleSummaryIndex *ExportSummary,
1315 WholeProgramDevirtResolution *Res) {
1318 auto *TheFn = TargetsForSlot[0].Fn;
1319 for (
auto &&Target : TargetsForSlot)
1325 TargetsForSlot[0].WasDevirt =
true;
1327 bool IsExported =
false;
1328 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1335 if (TheFn->hasLocalLinkage()) {
1336 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1341 if (Comdat *
C = TheFn->getComdat()) {
1342 if (
C->getName() == TheFn->
getName()) {
1343 Comdat *NewC =
M.getOrInsertComdat(NewName);
1345 for (GlobalObject &GO :
M.global_objects())
1346 if (GO.getComdat() ==
C)
1355 if (ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFn->getGUID()))
1367 VTableSlotSummary &SlotSummary,
1368 VTableSlotInfo &SlotInfo,
1369 WholeProgramDevirtResolution *Res,
1370 std::set<ValueInfo> &DevirtTargets) {
1373 auto TheFn = TargetsForSlot[0];
1374 for (
auto &&Target : TargetsForSlot)
1375 if (TheFn != Target)
1379 auto Size = TheFn.getSummaryList().size();
1385 if (FunctionsToSkip.match(TheFn.name()))
1390 for (
const auto &S : TheFn.getSummaryList())
1396 DevirtTargets.insert(TheFn);
1398 auto &S = TheFn.getSummaryList()[0];
1399 bool IsExported =
addCalls(SlotInfo, TheFn);
1401 ExportedGUIDs.insert(TheFn.getGUID());
1412 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1414 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1428void DevirtModule::tryICallBranchFunnel(
1430 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1431 Triple
T(
M.getTargetTriple());
1438 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1440 for (
auto &
P : SlotInfo.ConstCSInfo)
1441 if (!
P.second.AllCallSitesDevirted) {
1442 HasNonDevirt =
true;
1460 for (
auto &
T : TargetsForSlot) {
1461 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1466 FunctionType::get(Type::getVoidTy(
M.getContext()), {Int8PtrTy},
true);
1470 M.getDataLayout().getProgramAddressSpace(),
1471 getGlobalName(Slot, {},
"branch_funnel"), &
M);
1475 M.getDataLayout().getProgramAddressSpace(),
1476 "branch_funnel", &M);
1478 JT->addParamAttr(0, Attribute::Nest);
1480 std::vector<Value *> JTArgs;
1481 JTArgs.push_back(
JT->arg_begin());
1482 for (
auto &
T : TargetsForSlot) {
1483 JTArgs.push_back(getMemberAddr(
T.TM));
1484 JTArgs.push_back(
T.Fn);
1489 &M, llvm::Intrinsic::icall_branch_funnel, {});
1495 bool IsExported =
false;
1496 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1500 if (!
JT->getEntryCount().has_value()) {
1506void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1507 Function &JT,
bool &IsExported) {
1508 DenseMap<Function *, double> FunctionEntryCounts;
1510 if (CSInfo.isExported())
1512 if (CSInfo.AllCallSitesDevirted)
1515 std::map<CallBase *, CallBase *> CallBases;
1516 for (
auto &&VCallSite : CSInfo.CallSites) {
1517 CallBase &CB = VCallSite.CB;
1519 if (CallBases.find(&CB) != CallBases.end()) {
1536 VCallSite.emitRemark(
"branch-funnel",
JT.getName(), OREGetter);
1540 std::vector<Type *> NewArgs;
1541 NewArgs.push_back(Int8PtrTy);
1543 FunctionType *NewFT =
1547 std::vector<Value *>
Args;
1548 Args.push_back(VCallSite.VTable);
1551 CallBase *NewCS =
nullptr;
1557 auto EC =
BFI.getBlockFreq(&
F.getEntryBlock());
1558 auto CC =
F.getEntryCount(
true);
1559 double CallCount = 0.0;
1560 if (
EC.getFrequency() != 0 && CC && CC->getCount() != 0) {
1562 static_cast<double>(
1565 CallCount = CallFreq * CC->getCount();
1567 FunctionEntryCounts[&
JT] += CallCount;
1570 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1578 std::vector<AttributeSet> NewArgAttrs;
1581 M.getContext(), Attribute::Nest)}));
1582 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1583 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1585 AttributeList::get(
M.getContext(),
Attrs.getFnAttrs(),
1586 Attrs.getRetAttrs(), NewArgAttrs));
1588 CallBases[&CB] = NewCS;
1591 if (VCallSite.NumUnsafeUses)
1592 --*VCallSite.NumUnsafeUses;
1599 for (
auto &[Old, New] : CallBases) {
1600 Old->replaceAllUsesWith(New);
1601 Old->eraseFromParent();
1604 Apply(SlotInfo.CSInfo);
1605 for (
auto &
P : SlotInfo.ConstCSInfo)
1607 for (
auto &[
F,
C] : FunctionEntryCounts) {
1608 assert(!
F->getEntryCount(
true) &&
1609 "Unexpected entry count for funnel that was freshly synthesized");
1610 F->setEntryCount(
static_cast<uint64_t
>(std::round(
C)));
1614bool DevirtModule::tryEvaluateFunctionsWithArgs(
1616 ArrayRef<uint64_t> Args) {
1619 for (VirtualCallTarget &Target : TargetsForSlot) {
1630 Evaluator Eval(
M.getDataLayout(),
nullptr);
1634 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1639 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1643 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1651void DevirtModule::applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1652 uint64_t TheRetVal) {
1653 for (
auto Call : CSInfo.CallSites) {
1657 Call.replaceAndErase(
1658 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1661 CSInfo.markDevirt();
1664bool DevirtModule::tryUniformRetValOpt(
1666 WholeProgramDevirtResolution::ByArg *Res) {
1669 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1670 for (
const VirtualCallTarget &Target : TargetsForSlot)
1671 if (
Target.RetVal != TheRetVal)
1674 if (CSInfo.isExported()) {
1676 Res->
Info = TheRetVal;
1679 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1681 for (
auto &&Target : TargetsForSlot)
1686std::string DevirtModule::getGlobalName(VTableSlot Slot,
1687 ArrayRef<uint64_t> Args,
1689 std::string FullName =
"__typeid_";
1690 raw_string_ostream OS(FullName);
1691 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1692 for (uint64_t Arg : Args)
1698bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1699 Triple
T(
M.getTargetTriple());
1703void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1704 StringRef Name, Constant *
C) {
1706 getGlobalName(Slot, Args, Name),
C, &M);
1710void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1711 StringRef Name, uint32_t Const,
1712 uint32_t &Storage) {
1713 if (shouldExportConstantsAsAbsoluteSymbols()) {
1723Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1725 GlobalVariable *GV =
1726 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1731Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1732 StringRef Name, IntegerType *IntTy,
1734 if (!shouldExportConstantsAsAbsoluteSymbols())
1735 return ConstantInt::get(IntTy, Storage);
1737 Constant *
C = importGlobal(Slot, Args, Name);
1743 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1746 auto SetAbsRange = [&](uint64_t Min, uint64_t
Max) {
1754 SetAbsRange(~0ull, ~0ull);
1756 SetAbsRange(0, 1ull << AbsWidth);
1760void DevirtModule::applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1762 Constant *UniqueMemberAddr) {
1763 for (
auto &&
Call : CSInfo.CallSites) {
1768 B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
Call.VTable,
1769 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->
getType()));
1772 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1775 CSInfo.markDevirt();
1778Constant *DevirtModule::getMemberAddr(
const TypeMemberInfo *M) {
1780 ConstantInt::get(Int64Ty,
M->Offset));
1783bool DevirtModule::tryUniqueRetValOpt(
1785 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1786 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1788 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1789 const TypeMemberInfo *UniqueMember =
nullptr;
1790 for (
const VirtualCallTarget &Target : TargetsForSlot) {
1791 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1794 UniqueMember =
Target.TM;
1802 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1803 if (CSInfo.isExported()) {
1807 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1811 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1816 for (
auto &&Target : TargetsForSlot)
1823 if (tryUniqueRetValOptFor(
true))
1825 if (tryUniqueRetValOptFor(
false))
1831void DevirtModule::applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
1832 Constant *Byte, Constant *Bit) {
1833 for (
auto Call : CSInfo.CallSites) {
1838 Value *Addr =
B.CreatePtrAdd(
Call.VTable, Byte);
1839 if (RetType->getBitWidth() == 1) {
1841 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1842 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1843 NumVirtConstProp1Bit++;
1844 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1845 OREGetter, IsBitSet);
1847 Value *Val =
B.CreateLoad(RetType, Addr);
1849 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1853 CSInfo.markDevirt();
1856bool DevirtModule::tryVirtualConstProp(
1858 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1869 unsigned BitWidth = RetType->getBitWidth();
1881 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1893 for (VirtualCallTarget &Target : TargetsForSlot) {
1914 GlobalVariable *GV =
Target.TM->Bits->GV;
1915 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1917 if (TypeAlignment > TableAlignment)
1921 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1922 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1925 WholeProgramDevirtResolution::ByArg *ResByArg =
nullptr;
1927 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1929 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1932 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1933 ResByArg, Slot, CSByConstantArg.first))
1941 uint64_t AllocBefore =
1943 uint64_t AllocAfter =
1948 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1949 for (
auto &&Target : TargetsForSlot) {
1950 TotalPaddingBefore += std::max<int64_t>(
1951 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1952 TotalPaddingAfter += std::max<int64_t>(
1953 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1958 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1965 if (TotalPaddingBefore <= TotalPaddingAfter)
1981 for (
auto &&Target : TargetsForSlot)
1985 if (CSByConstantArg.second.isExported()) {
1987 exportConstant(Slot, CSByConstantArg.first,
"byte", OffsetByte,
1989 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
1995 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
1996 applyVirtualConstProp(CSByConstantArg.second,
1997 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
2002void DevirtModule::rebuildGlobal(VTableBits &
B) {
2003 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
2008 Align Alignment =
M.getDataLayout().getValueOrABITypeAlignment(
2009 B.GV->getAlign(),
B.GV->getValueType());
2010 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
2013 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
2020 B.GV->getInitializer(),
2023 new GlobalVariable(M, NewInit->getType(),
B.GV->isConstant(),
2024 GlobalVariable::PrivateLinkage, NewInit,
"",
B.GV);
2025 NewGV->setSection(
B.GV->getSection());
2026 NewGV->setComdat(
B.GV->getComdat());
2027 NewGV->setAlignment(
B.GV->getAlign());
2031 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
2036 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2038 NewInit->getType(), NewGV,
2040 ConstantInt::get(Int32Ty, 1)}),
2042 Alias->setVisibility(
B.GV->getVisibility());
2043 Alias->takeName(
B.GV);
2045 B.GV->replaceAllUsesWith(Alias);
2046 B.GV->eraseFromParent();
2049bool DevirtModule::areRemarksEnabled() {
2050 const auto &FL =
M.getFunctionList();
2051 for (
const Function &Fn : FL) {
2055 return DI.isEnabled();
2060void DevirtModule::scanTypeTestUsers(
2061 Function *TypeTestFunc,
2062 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2076 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2082 if (!Assumes.
empty()) {
2083 Value *
Ptr = CI->getArgOperand(0)->stripPointerCasts();
2084 for (DevirtCallSite
Call : DevirtCalls)
2085 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
nullptr);
2088 auto RemoveTypeTestAssumes = [&]() {
2090 for (
auto *Assume : Assumes)
2091 Assume->eraseFromParent();
2094 if (CI->use_empty())
2095 CI->eraseFromParent();
2110 if (!TypeIdMap.count(TypeId))
2111 RemoveTypeTestAssumes();
2123 const TypeIdSummary *TidSummary =
2126 RemoveTypeTestAssumes();
2135void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {
2146 Value *TypeIdValue = CI->getArgOperand(2);
2152 bool HasNonCallUses =
false;
2153 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2155 HasNonCallUses, CI, DT);
2164 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2166 Value *LoadedValue =
nullptr;
2168 Intrinsic::type_checked_load_relative) {
2170 &M, Intrinsic::load_relative, {
Int32Ty});
2171 LoadedValue = LoadB.CreateCall(LoadRelFunc, {
Ptr,
Offset});
2174 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2177 for (Instruction *LoadedPtr : LoadedPtrs) {
2178 LoadedPtr->replaceAllUsesWith(LoadedValue);
2179 LoadedPtr->eraseFromParent();
2183 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2184 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {
Ptr, TypeIdValue});
2186 for (Instruction *Pred : Preds) {
2187 Pred->replaceAllUsesWith(TypeTestCall);
2188 Pred->eraseFromParent();
2195 if (!CI->use_empty()) {
2198 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2199 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2204 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2205 NumUnsafeUses = DevirtCalls.
size();
2212 for (DevirtCallSite
Call : DevirtCalls) {
2213 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
2217 CI->eraseFromParent();
2221void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2225 const TypeIdSummary *TidSummary =
2229 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2230 if (ResI == TidSummary->
WPDRes.end())
2232 const WholeProgramDevirtResolution &Res = ResI->second;
2240 Type::getVoidTy(
M.getContext()))
2244 bool IsExported =
false;
2245 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2249 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2250 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2253 auto &ResByArg =
I->second;
2260 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2264 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2265 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2270 Constant *
Byte = importConstant(Slot, CSByConstantArg.first,
"byte",
2272 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2274 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2286 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2287 Type::getVoidTy(
M.getContext()))
2289 bool IsExported =
false;
2290 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2295void DevirtModule::removeRedundantTypeTests() {
2297 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2298 if (
U.second == 0) {
2299 U.first->replaceAllUsesWith(True);
2300 U.first->eraseFromParent();
2306DevirtModule::lookUpFunctionValueInfo(Function *TheFn,
2307 ModuleSummaryIndex *ExportSummary) {
2308 assert((ExportSummary !=
nullptr) &&
2309 "Caller guarantees ExportSummary is not nullptr");
2311 const auto TheFnGUID = TheFn->
getGUID();
2312 const auto TheFnGUIDWithExportedName =
2315 ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFnGUID);
2324 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2325 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2330bool DevirtModule::mustBeUnreachableFunction(
2331 Function *
const F, ModuleSummaryIndex *ExportSummary) {
2335 if (!
F->isDeclaration()) {
2341 return ExportSummary &&
2343 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2346bool DevirtModule::run() {
2360 &M, Intrinsic::type_checked_load_relative);
2367 if (!ExportSummary &&
2368 (!TypeTestFunc || TypeTestFunc->
use_empty() || !AssumeFunc ||
2370 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2371 (!TypeCheckedLoadRelativeFunc ||
2372 TypeCheckedLoadRelativeFunc->
use_empty()))
2376 std::vector<VTableBits>
Bits;
2377 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2378 buildTypeIdentifierMap(Bits, TypeIdMap);
2380 if (TypeTestFunc && AssumeFunc)
2381 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2383 if (TypeCheckedLoadFunc)
2384 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2386 if (TypeCheckedLoadRelativeFunc)
2387 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2389 if (ImportSummary) {
2390 for (
auto &S : CallSlots)
2391 importResolution(S.first, S.second);
2393 removeRedundantTypeTests();
2398 for (GlobalVariable &GV :
M.globals())
2406 if (TypeIdMap.
empty())
2410 if (ExportSummary) {
2411 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2412 for (
auto &
P : TypeIdMap) {
2415 TypeId->getString())]
2419 for (
auto &
P : *ExportSummary) {
2420 for (
auto &S :
P.second.SummaryList) {
2425 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2426 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2427 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2430 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2431 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2432 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2435 for (
const FunctionSummary::ConstVCall &VC :
2436 FS->type_test_assume_const_vcalls()) {
2437 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2438 CallSlots[{MD,
VC.VFunc.Offset}]
2439 .ConstCSInfo[
VC.Args]
2440 .addSummaryTypeTestAssumeUser(FS);
2443 for (
const FunctionSummary::ConstVCall &VC :
2444 FS->type_checked_load_const_vcalls()) {
2445 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2446 CallSlots[{MD,
VC.VFunc.Offset}]
2447 .ConstCSInfo[
VC.Args]
2448 .addSummaryTypeCheckedLoadUser(FS);
2456 bool DidVirtualConstProp =
false;
2457 std::map<std::string, GlobalValue *> DevirtTargets;
2458 for (
auto &S : CallSlots) {
2462 std::vector<VirtualCallTarget> TargetsForSlot;
2463 WholeProgramDevirtResolution *Res =
nullptr;
2464 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2466 TypeMemberInfos.size())
2473 Res = &ExportSummary
2474 ->getOrInsertTypeIdSummary(
2476 .WPDRes[S.first.ByteOffset];
2477 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2478 S.first.ByteOffset, ExportSummary)) {
2480 if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res)) {
2481 DidVirtualConstProp |=
2482 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2484 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2489 for (
const auto &
T : TargetsForSlot)
2491 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2501 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2502 if (!CSI.AllCallSitesDevirted)
2503 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2504 FS->addTypeTest(GUID);
2506 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2507 for (
auto &CCS : S.second.ConstCSInfo)
2508 AddTypeTestsForTypeCheckedLoads(CCS.second);
2512 if (RemarksEnabled) {
2514 for (
const auto &DT : DevirtTargets) {
2515 GlobalValue *GV = DT.second;
2524 using namespace ore;
2525 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE,
"Devirtualized",
F)
2526 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2530 NumDevirtTargets += DevirtTargets.size();
2532 removeRedundantTypeTests();
2536 if (DidVirtualConstProp)
2537 for (VTableBits &
B : Bits)
2543 for (GlobalVariable &GV :
M.globals())
2546 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2547 CI->eraseFromParent();
2552void DevirtIndex::run() {
2553 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2556 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2557 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2566 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2570 for (
auto &
P : ExportSummary) {
2571 for (
auto &S :
P.second.SummaryList) {
2576 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2577 for (StringRef Name : NameByGUID[VF.GUID]) {
2578 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2581 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2582 for (StringRef Name : NameByGUID[VF.GUID]) {
2583 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2586 for (
const FunctionSummary::ConstVCall &VC :
2587 FS->type_test_assume_const_vcalls()) {
2588 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2589 CallSlots[{
Name,
VC.VFunc.Offset}]
2590 .ConstCSInfo[
VC.Args]
2591 .addSummaryTypeTestAssumeUser(FS);
2594 for (
const FunctionSummary::ConstVCall &VC :
2595 FS->type_checked_load_const_vcalls()) {
2596 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2597 CallSlots[{
Name,
VC.VFunc.Offset}]
2598 .ConstCSInfo[
VC.Args]
2599 .addSummaryTypeCheckedLoadUser(FS);
2605 std::set<ValueInfo> DevirtTargets;
2607 for (
auto &S : CallSlots) {
2611 std::vector<ValueInfo> TargetsForSlot;
2612 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2616 WholeProgramDevirtResolution *Res =
2617 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2618 ->WPDRes[S.first.ByteOffset];
2619 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2620 S.first.ByteOffset)) {
2622 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2631 for (
const auto &DT : DevirtTargets)
2632 errs() <<
"Devirtualized call to " << DT <<
"\n";
2634 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< std::string > ClReadSummary("lowertypetests-read-summary", cl::desc("Read summary from given YAML file before running pass"), cl::Hidden)
static cl::opt< PassSummaryAction > ClSummaryAction("lowertypetests-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
static cl::opt< std::string > ClWriteSummary("lowertypetests-write-summary", cl::desc("Write summary to given YAML file after running pass"), cl::Hidden)
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
static bool mustBeUnreachableFunction(const Function &F)
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 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.
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)
@ 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.
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.
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