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");
124 "wholeprogramdevirt-summary-action",
125 cl::desc(
"What to do with the summary when running this pass"),
128 "Import typeid resolutions from summary and globals"),
130 "Export typeid resolutions to summary and globals")),
134 "wholeprogramdevirt-read-summary",
136 "Read summary from given bitcode or YAML file before running pass"),
140 "wholeprogramdevirt-write-summary",
141 cl::desc(
"Write summary to given bitcode or YAML file after running pass. "
142 "Output file format is deduced from extension: *.bc means writing "
143 "bitcode, otherwise YAML"),
149 cl::desc(
"Maximum number of call targets per "
150 "call site to enable branch funnels"));
154 cl::desc(
"Print index-based devirtualization messages"));
162 cl::desc(
"Enable whole program visibility"));
167 "disable-whole-program-visibility",
cl::Hidden,
168 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
173 cl::desc(
"Prevent function(s) from being devirtualized"),
196 "wholeprogramdevirt-keep-unreachable-function",
197 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
204 "wholeprogramdevirt-cutoff",
205 cl::desc(
"Max number of devirtualizations for devirt module pass"),
216 cl::desc(
"Type of checking for incorrect devirtualizations"),
220 "Fallback to indirect when incorrect")));
224 std::vector<GlobPattern> Patterns;
225 template <
class T>
void init(
const T &StringList) {
226 for (
const auto &S : StringList)
228 Patterns.push_back(std::move(*Pat));
230 bool match(StringRef S) {
231 for (
const GlobPattern &
P : Patterns)
249 MinByte = std::max(MinByte,
Target.minAfterBytes());
251 MinByte = std::max(MinByte,
Target.minBeforeBytes());
274 std::vector<ArrayRef<uint8_t>> Used;
277 :
Target.TM->Bits->Before.BytesUsed;
279 : MinByte -
Target.minBeforeBytes();
289 for (
unsigned I = 0;; ++
I) {
291 for (
auto &&
B : Used)
294 if (BitsUsed != 0xff)
300 for (
unsigned I = 0;; ++
I) {
301 for (
auto &&
B : Used) {
303 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
321 OffsetByte = -(AllocBefore / 8 + 1);
323 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
324 OffsetBit = AllocBefore % 8;
328 Target.setBeforeBit(AllocBefore);
338 OffsetByte = AllocAfter / 8;
340 OffsetByte = (AllocAfter + 7) / 8;
341 OffsetBit = AllocAfter % 8;
345 Target.setAfterBit(AllocAfter);
359static unsigned NumDevirtCalls = 0;
387 const VTableSlot &RHS) {
388 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
407 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
433 if (!Summary->isLive())
436 if (!FS->fflags().MustBeUnreachable)
451struct VirtualCallSite {
458 unsigned *NumUnsafeUses =
nullptr;
461 emitRemark(
const StringRef OptName,
const StringRef TargetName,
462 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter) {
468 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE, OptName, DLoc,
Block)
469 <<
NV(
"Optimization", OptName)
470 <<
": devirtualized a call to "
471 <<
NV(
"FunctionName", TargetName));
474 void replaceAndErase(
475 const StringRef OptName,
const StringRef TargetName,
bool RemarksEnabled,
476 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter,
483 II->getUnwindDest()->removePredecessor(
II->getParent());
500 std::vector<VirtualCallSite> CallSites;
509 bool AllCallSitesDevirted =
true;
518 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
522 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
524 bool isExported()
const {
525 return !SummaryTypeCheckedLoadUsers.empty() ||
526 !SummaryTypeTestAssumeUsers.empty();
529 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
530 SummaryTypeCheckedLoadUsers.push_back(FS);
531 AllCallSitesDevirted =
false;
534 void addSummaryTypeTestAssumeUser(FunctionSummary *FS) {
535 SummaryTypeTestAssumeUsers.push_back(FS);
536 AllCallSitesDevirted =
false;
539 void markDevirt() { AllCallSitesDevirted =
true; }
543struct VTableSlotInfo {
550 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
552 void addCallSite(
Value *VTable, CallBase &CB,
unsigned *NumUnsafeUses);
558CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) {
559 std::vector<uint64_t>
Args;
561 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
565 if (!CI || CI->getBitWidth() > 64)
567 Args.push_back(CI->getZExtValue());
569 return ConstCSInfo[
Args];
572void VTableSlotInfo::addCallSite(
Value *VTable, CallBase &CB,
573 unsigned *NumUnsafeUses) {
574 auto &CSI = findCallSiteInfo(CB);
575 CSI.AllCallSitesDevirted =
false;
576 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
584 ModuleSummaryIndex *
const ExportSummary;
585 const ModuleSummaryIndex *
const ImportSummary;
587 IntegerType *
const Int8Ty;
590 IntegerType *
const Int64Ty;
591 IntegerType *
const IntPtrTy;
597 const bool RemarksEnabled;
598 std::function<OptimizationRemarkEmitter &(
Function &)> OREGetter;
599 MapVector<VTableSlot, VTableSlotInfo> CallSlots;
604 SmallPtrSet<CallBase *, 8> OptimizedCalls;
618 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
619 PatternList FunctionsToSkip;
622 ModuleSummaryIndex *ExportSummary,
623 const ModuleSummaryIndex *ImportSummary)
626 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
631 IntPtrTy(
M.getDataLayout().getIntPtrType(
M.
getContext(), 0)),
633 RemarksEnabled(areRemarksEnabled()),
634 OREGetter([&](
Function &
F) -> OptimizationRemarkEmitter & {
637 assert(!(ExportSummary && ImportSummary));
641 bool areRemarksEnabled();
644 scanTypeTestUsers(Function *TypeTestFunc,
645 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
646 void scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc);
648 void buildTypeIdentifierMap(
649 std::vector<VTableBits> &Bits,
650 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
653 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
654 const std::set<TypeMemberInfo> &TypeMemberInfos,
656 ModuleSummaryIndex *ExportSummary);
658 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
660 bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
662 VTableSlotInfo &SlotInfo,
663 WholeProgramDevirtResolution *Res);
665 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Function &JT,
668 VTableSlotInfo &SlotInfo,
669 WholeProgramDevirtResolution *Res, VTableSlot Slot);
671 bool tryEvaluateFunctionsWithArgs(
673 ArrayRef<uint64_t> Args);
675 void applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
679 WholeProgramDevirtResolution::ByArg *Res);
683 std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
686 bool shouldExportConstantsAsAbsoluteSymbols();
691 void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
693 void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
694 uint32_t Const, uint32_t &Storage);
698 Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
700 Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
701 StringRef Name, IntegerType *IntTy,
704 Constant *getMemberAddr(
const TypeMemberInfo *M);
706 void applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
bool IsOne,
707 Constant *UniqueMemberAddr);
708 bool tryUniqueRetValOpt(
unsigned BitWidth,
711 WholeProgramDevirtResolution::ByArg *Res,
712 VTableSlot Slot, ArrayRef<uint64_t> Args);
714 void applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
715 Constant *Byte, Constant *Bit);
717 VTableSlotInfo &SlotInfo,
718 WholeProgramDevirtResolution *Res, VTableSlot Slot);
720 void rebuildGlobal(VTableBits &
B);
723 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
727 void removeRedundantTypeTests();
734 static ValueInfo lookUpFunctionValueInfo(Function *TheFn,
735 ModuleSummaryIndex *ExportSummary);
746 ModuleSummaryIndex *ExportSummary);
754 ModuleSummaryIndex &ExportSummary;
757 std::set<GlobalValue::GUID> &ExportedGUIDs;
761 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
763 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
765 PatternList FunctionsToSkip;
768 ModuleSummaryIndex &ExportSummary,
769 std::set<GlobalValue::GUID> &ExportedGUIDs,
770 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap)
771 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
772 LocalWPDTargetsMap(LocalWPDTargetsMap) {
776 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
778 uint64_t ByteOffset);
781 VTableSlotSummary &SlotSummary,
782 VTableSlotInfo &SlotInfo,
783 WholeProgramDevirtResolution *Res,
784 std::set<ValueInfo> &DevirtTargets);
793 if (!DevirtModule::runForTesting(M,
MAM))
815 if (
TypeID.ends_with(
".virtual"))
821 if (!
TypeID.consume_front(
"_ZTS"))
829 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
830 return IsVisibleToRegularObj(TypeInfo);
839 for (
auto *
Type : Types)
842 IsVisibleToRegularObj);
851 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
853 bool ValidateAllVtablesHaveTypeInfos,
870 !(ValidateAllVtablesHaveTypeInfos &&
877 bool WholeProgramVisibilityEnabledInLTO) {
881 if (!PublicTypeTestFunc)
889 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
891 CI->replaceAllUsesWith(NewCI);
892 CI->eraseFromParent();
898 CI->replaceAllUsesWith(True);
899 CI->eraseFromParent();
910 for (
const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
913 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
926 for (
auto &
P : Index) {
929 if (DynamicExportSymbols.
count(
P.first))
931 for (
auto &S :
P.second.SummaryList) {
940 if (VisibleToRegularObjSymbols.
count(
P.first))
949 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
950 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap).run();
956 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
957 for (
auto &
T : LocalWPDTargetsMap) {
960 assert(VI.getSummaryList().size() == 1 &&
961 "Devirt of local target has more than one copy");
962 auto &S = VI.getSummaryList()[0];
963 if (!IsExported(S->modulePath(), VI))
967 for (
auto &SlotSummary :
T.second) {
968 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
970 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
971 assert(WPDRes != TIdSum->WPDRes.end());
973 WPDRes->second.SingleImplName,
974 Summary.getModuleHash(S->modulePath()));
984 const auto &ModPaths = Summary->modulePaths();
989 "combined summary should contain Regular LTO module");
994 std::unique_ptr<ModuleSummaryIndex>
Summary =
995 std::make_unique<ModuleSummaryIndex>(
false);
1000 ExitOnError ExitOnErr(
"-wholeprogramdevirt-read-summary: " +
ClReadSummary +
1002 auto ReadSummaryFile =
1004 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1006 Summary = std::move(*SummaryOrErr);
1011 yaml::Input
In(ReadSummaryFile->getBuffer());
1018 DevirtModule(M,
MAM,
1026 ExitOnError ExitOnErr(
1036 yaml::Output Out(OS);
1044void DevirtModule::buildTypeIdentifierMap(
1045 std::vector<VTableBits> &Bits,
1046 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1047 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1048 Bits.reserve(
M.global_size());
1050 for (GlobalVariable &GV :
M.globals()) {
1056 VTableBits *&BitsPtr = GVToBits[&GV];
1058 Bits.emplace_back();
1059 Bits.back().GV = &GV;
1060 Bits.back().ObjectSize =
1062 BitsPtr = &
Bits.back();
1065 for (MDNode *
Type : Types) {
1078bool DevirtModule::tryFindVirtualCallTargets(
1079 std::vector<VirtualCallTarget> &TargetsForSlot,
1080 const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset,
1081 ModuleSummaryIndex *ExportSummary) {
1082 for (
const TypeMemberInfo &TM : TypeMemberInfos) {
1083 if (!
TM.Bits->GV->isConstant())
1088 if (
TM.Bits->GV->getVCallVisibility() ==
1100 if (FunctionsToSkip.match(Fn->
getName()))
1105 if (Fn->
getName() ==
"__cxa_pure_virtual")
1117 TargetsForSlot.push_back({GV, &
TM});
1121 return !TargetsForSlot.empty();
1124bool DevirtIndex::tryFindVirtualCallTargets(
1125 std::vector<ValueInfo> &TargetsForSlot,
1127 for (
const TypeIdOffsetVtableInfo &
P : TIdInfo) {
1138 const GlobalVarSummary *
VS =
nullptr;
1139 bool LocalFound =
false;
1140 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1147 if (!CurVS->vTableFuncs().empty() ||
1169 for (
auto VTP :
VS->vTableFuncs()) {
1170 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1176 TargetsForSlot.push_back(VTP.FuncVI);
1181 return !TargetsForSlot.empty();
1184void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1185 Constant *TheFn,
bool &IsExported) {
1191 for (
auto &&VCallSite : CSInfo.CallSites) {
1192 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1201 VCallSite.emitRemark(
"single-impl",
1205 auto &CB = VCallSite.CB;
1218 MDBuilder(
M.getContext()).createUnlikelyBranchWeights());
1219 Builder.SetInsertPoint(ThenTerm);
1222 auto *CallTrap = Builder.CreateCall(TrapFn);
1230 MDNode *Weights = MDBuilder(
M.getContext()).createLikelyBranchWeights();
1239 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1240 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1262 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1267 if (VCallSite.NumUnsafeUses)
1268 --*VCallSite.NumUnsafeUses;
1270 if (CSInfo.isExported())
1272 CSInfo.markDevirt();
1274 Apply(SlotInfo.CSInfo);
1275 for (
auto &
P : SlotInfo.ConstCSInfo)
1281 if (Callee.getSummaryList().empty())
1288 bool IsExported =
false;
1289 auto &S = Callee.getSummaryList()[0];
1292 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1293 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1294 FS->addCall({Callee, CI});
1295 IsExported |= S->modulePath() != FS->modulePath();
1297 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1298 FS->addCall({Callee, CI});
1299 IsExported |= S->modulePath() != FS->modulePath();
1302 AddCalls(SlotInfo.CSInfo);
1303 for (
auto &
P : SlotInfo.ConstCSInfo)
1308bool DevirtModule::trySingleImplDevirt(
1309 ModuleSummaryIndex *ExportSummary,
1311 WholeProgramDevirtResolution *Res) {
1314 auto *TheFn = TargetsForSlot[0].Fn;
1315 for (
auto &&Target : TargetsForSlot)
1321 TargetsForSlot[0].WasDevirt =
true;
1323 bool IsExported =
false;
1324 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1331 if (TheFn->hasLocalLinkage()) {
1332 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1337 if (Comdat *
C = TheFn->getComdat()) {
1338 if (
C->getName() == TheFn->
getName()) {
1339 Comdat *NewC =
M.getOrInsertComdat(NewName);
1341 for (GlobalObject &GO :
M.global_objects())
1342 if (GO.getComdat() ==
C)
1351 if (ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFn->getGUID()))
1363 VTableSlotSummary &SlotSummary,
1364 VTableSlotInfo &SlotInfo,
1365 WholeProgramDevirtResolution *Res,
1366 std::set<ValueInfo> &DevirtTargets) {
1369 auto TheFn = TargetsForSlot[0];
1370 for (
auto &&Target : TargetsForSlot)
1371 if (TheFn != Target)
1375 auto Size = TheFn.getSummaryList().size();
1381 if (FunctionsToSkip.match(TheFn.name()))
1386 for (
const auto &S : TheFn.getSummaryList())
1392 DevirtTargets.insert(TheFn);
1394 auto &S = TheFn.getSummaryList()[0];
1395 bool IsExported =
addCalls(SlotInfo, TheFn);
1397 ExportedGUIDs.insert(TheFn.getGUID());
1408 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1410 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1424void DevirtModule::tryICallBranchFunnel(
1426 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1427 Triple
T(
M.getTargetTriple());
1434 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1436 for (
auto &
P : SlotInfo.ConstCSInfo)
1437 if (!
P.second.AllCallSitesDevirted) {
1438 HasNonDevirt =
true;
1456 for (
auto &
T : TargetsForSlot) {
1457 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1462 FunctionType::get(Type::getVoidTy(
M.getContext()), {Int8PtrTy},
true);
1466 M.getDataLayout().getProgramAddressSpace(),
1467 getGlobalName(Slot, {},
"branch_funnel"), &
M);
1471 M.getDataLayout().getProgramAddressSpace(),
1472 "branch_funnel", &M);
1474 JT->addParamAttr(0, Attribute::Nest);
1476 std::vector<Value *> JTArgs;
1477 JTArgs.push_back(
JT->arg_begin());
1478 for (
auto &
T : TargetsForSlot) {
1479 JTArgs.push_back(getMemberAddr(
T.TM));
1480 JTArgs.push_back(
T.Fn);
1485 &M, llvm::Intrinsic::icall_branch_funnel, {});
1491 bool IsExported =
false;
1492 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1496 if (!
JT->getEntryCount().has_value()) {
1502void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1503 Function &JT,
bool &IsExported) {
1504 DenseMap<Function *, double> FunctionEntryCounts;
1506 if (CSInfo.isExported())
1508 if (CSInfo.AllCallSitesDevirted)
1511 std::map<CallBase *, CallBase *> CallBases;
1512 for (
auto &&VCallSite : CSInfo.CallSites) {
1513 CallBase &CB = VCallSite.CB;
1515 if (CallBases.find(&CB) != CallBases.end()) {
1532 VCallSite.emitRemark(
"branch-funnel",
JT.getName(), OREGetter);
1536 std::vector<Type *> NewArgs;
1537 NewArgs.push_back(Int8PtrTy);
1539 FunctionType *NewFT =
1543 std::vector<Value *>
Args;
1544 Args.push_back(VCallSite.VTable);
1547 CallBase *NewCS =
nullptr;
1553 auto EC =
BFI.getBlockFreq(&
F.getEntryBlock());
1554 auto CC =
F.getEntryCount(
true);
1555 double CallCount = 0.0;
1556 if (
EC.getFrequency() != 0 && CC && CC->getCount() != 0) {
1558 static_cast<double>(
1561 CallCount = CallFreq * CC->getCount();
1563 FunctionEntryCounts[&
JT] += CallCount;
1566 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1574 std::vector<AttributeSet> NewArgAttrs;
1577 M.getContext(), Attribute::Nest)}));
1578 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1579 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1581 AttributeList::get(
M.getContext(),
Attrs.getFnAttrs(),
1582 Attrs.getRetAttrs(), NewArgAttrs));
1584 CallBases[&CB] = NewCS;
1587 if (VCallSite.NumUnsafeUses)
1588 --*VCallSite.NumUnsafeUses;
1595 for (
auto &[Old, New] : CallBases) {
1596 Old->replaceAllUsesWith(New);
1597 Old->eraseFromParent();
1600 Apply(SlotInfo.CSInfo);
1601 for (
auto &
P : SlotInfo.ConstCSInfo)
1603 for (
auto &[
F,
C] : FunctionEntryCounts) {
1604 assert(!
F->getEntryCount(
true) &&
1605 "Unexpected entry count for funnel that was freshly synthesized");
1606 F->setEntryCount(
static_cast<uint64_t
>(std::round(
C)));
1610bool DevirtModule::tryEvaluateFunctionsWithArgs(
1612 ArrayRef<uint64_t> Args) {
1615 for (VirtualCallTarget &Target : TargetsForSlot) {
1626 Evaluator Eval(
M.getDataLayout(),
nullptr);
1630 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1635 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1639 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1647void DevirtModule::applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1648 uint64_t TheRetVal) {
1649 for (
auto Call : CSInfo.CallSites) {
1653 Call.replaceAndErase(
1654 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1657 CSInfo.markDevirt();
1660bool DevirtModule::tryUniformRetValOpt(
1662 WholeProgramDevirtResolution::ByArg *Res) {
1665 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1666 for (
const VirtualCallTarget &Target : TargetsForSlot)
1667 if (
Target.RetVal != TheRetVal)
1670 if (CSInfo.isExported()) {
1672 Res->
Info = TheRetVal;
1675 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1677 for (
auto &&Target : TargetsForSlot)
1682std::string DevirtModule::getGlobalName(VTableSlot Slot,
1683 ArrayRef<uint64_t> Args,
1685 std::string FullName =
"__typeid_";
1686 raw_string_ostream OS(FullName);
1687 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1688 for (uint64_t Arg : Args)
1694bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1695 Triple
T(
M.getTargetTriple());
1699void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1700 StringRef Name, Constant *
C) {
1702 getGlobalName(Slot, Args, Name),
C, &M);
1706void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1707 StringRef Name, uint32_t Const,
1708 uint32_t &Storage) {
1709 if (shouldExportConstantsAsAbsoluteSymbols()) {
1719Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1721 GlobalVariable *GV =
1722 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1727Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1728 StringRef Name, IntegerType *IntTy,
1730 if (!shouldExportConstantsAsAbsoluteSymbols())
1731 return ConstantInt::get(IntTy, Storage);
1733 Constant *
C = importGlobal(Slot, Args, Name);
1739 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1742 auto SetAbsRange = [&](uint64_t Min, uint64_t
Max) {
1750 SetAbsRange(~0ull, ~0ull);
1752 SetAbsRange(0, 1ull << AbsWidth);
1756void DevirtModule::applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1758 Constant *UniqueMemberAddr) {
1759 for (
auto &&
Call : CSInfo.CallSites) {
1764 B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
Call.VTable,
1765 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->
getType()));
1768 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1771 CSInfo.markDevirt();
1774Constant *DevirtModule::getMemberAddr(
const TypeMemberInfo *M) {
1776 ConstantInt::get(Int64Ty,
M->Offset));
1779bool DevirtModule::tryUniqueRetValOpt(
1781 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1782 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1784 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1785 const TypeMemberInfo *UniqueMember =
nullptr;
1786 for (
const VirtualCallTarget &Target : TargetsForSlot) {
1787 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1790 UniqueMember =
Target.TM;
1798 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1799 if (CSInfo.isExported()) {
1803 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1807 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1812 for (
auto &&Target : TargetsForSlot)
1819 if (tryUniqueRetValOptFor(
true))
1821 if (tryUniqueRetValOptFor(
false))
1827void DevirtModule::applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
1828 Constant *Byte, Constant *Bit) {
1829 for (
auto Call : CSInfo.CallSites) {
1834 Value *Addr =
B.CreatePtrAdd(
Call.VTable, Byte);
1835 if (RetType->getBitWidth() == 1) {
1837 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1838 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1839 NumVirtConstProp1Bit++;
1840 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1841 OREGetter, IsBitSet);
1843 Value *Val =
B.CreateLoad(RetType, Addr);
1845 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1849 CSInfo.markDevirt();
1852bool DevirtModule::tryVirtualConstProp(
1854 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1865 unsigned BitWidth = RetType->getBitWidth();
1877 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1889 for (VirtualCallTarget &Target : TargetsForSlot) {
1910 GlobalVariable *GV =
Target.TM->Bits->GV;
1911 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1913 if (TypeAlignment > TableAlignment)
1917 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1918 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1921 WholeProgramDevirtResolution::ByArg *ResByArg =
nullptr;
1923 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1925 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1928 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1929 ResByArg, Slot, CSByConstantArg.first))
1937 uint64_t AllocBefore =
1939 uint64_t AllocAfter =
1944 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1945 for (
auto &&Target : TargetsForSlot) {
1946 TotalPaddingBefore += std::max<int64_t>(
1947 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1948 TotalPaddingAfter += std::max<int64_t>(
1949 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1954 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1961 if (TotalPaddingBefore <= TotalPaddingAfter)
1977 for (
auto &&Target : TargetsForSlot)
1981 if (CSByConstantArg.second.isExported()) {
1983 exportConstant(Slot, CSByConstantArg.first,
"byte", OffsetByte,
1985 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
1991 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
1992 applyVirtualConstProp(CSByConstantArg.second,
1993 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
1998void DevirtModule::rebuildGlobal(VTableBits &
B) {
1999 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
2004 Align Alignment =
M.getDataLayout().getValueOrABITypeAlignment(
2005 B.GV->getAlign(),
B.GV->getValueType());
2006 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
2009 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
2016 B.GV->getInitializer(),
2019 new GlobalVariable(M, NewInit->getType(),
B.GV->isConstant(),
2020 GlobalVariable::PrivateLinkage, NewInit,
"",
B.GV);
2021 NewGV->setSection(
B.GV->getSection());
2022 NewGV->setComdat(
B.GV->getComdat());
2023 NewGV->setAlignment(
B.GV->getAlign());
2027 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
2032 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2034 NewInit->getType(), NewGV,
2036 ConstantInt::get(Int32Ty, 1)}),
2038 Alias->setVisibility(
B.GV->getVisibility());
2039 Alias->takeName(
B.GV);
2041 B.GV->replaceAllUsesWith(Alias);
2042 B.GV->eraseFromParent();
2045bool DevirtModule::areRemarksEnabled() {
2046 const auto &FL =
M.getFunctionList();
2047 for (
const Function &Fn : FL) {
2051 return DI.isEnabled();
2056void DevirtModule::scanTypeTestUsers(
2057 Function *TypeTestFunc,
2058 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2072 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2078 if (!Assumes.
empty()) {
2079 Value *
Ptr = CI->getArgOperand(0)->stripPointerCasts();
2080 for (DevirtCallSite
Call : DevirtCalls)
2081 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
nullptr);
2084 auto RemoveTypeTestAssumes = [&]() {
2086 for (
auto *Assume : Assumes)
2087 Assume->eraseFromParent();
2090 if (CI->use_empty())
2091 CI->eraseFromParent();
2106 if (!TypeIdMap.count(TypeId))
2107 RemoveTypeTestAssumes();
2119 const TypeIdSummary *TidSummary =
2122 RemoveTypeTestAssumes();
2131void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {
2142 Value *TypeIdValue = CI->getArgOperand(2);
2148 bool HasNonCallUses =
false;
2149 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2151 HasNonCallUses, CI, DT);
2160 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2162 Value *LoadedValue =
nullptr;
2164 Intrinsic::type_checked_load_relative) {
2166 &M, Intrinsic::load_relative, {
Int32Ty});
2167 LoadedValue = LoadB.CreateCall(LoadRelFunc, {
Ptr,
Offset});
2170 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2173 for (Instruction *LoadedPtr : LoadedPtrs) {
2174 LoadedPtr->replaceAllUsesWith(LoadedValue);
2175 LoadedPtr->eraseFromParent();
2179 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2180 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {
Ptr, TypeIdValue});
2182 for (Instruction *Pred : Preds) {
2183 Pred->replaceAllUsesWith(TypeTestCall);
2184 Pred->eraseFromParent();
2191 if (!CI->use_empty()) {
2194 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2195 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2200 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2201 NumUnsafeUses = DevirtCalls.
size();
2208 for (DevirtCallSite
Call : DevirtCalls) {
2209 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
2213 CI->eraseFromParent();
2217void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2221 const TypeIdSummary *TidSummary =
2225 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2226 if (ResI == TidSummary->
WPDRes.end())
2228 const WholeProgramDevirtResolution &Res = ResI->second;
2236 Type::getVoidTy(
M.getContext()))
2240 bool IsExported =
false;
2241 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2245 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2246 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2249 auto &ResByArg =
I->second;
2256 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2260 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2261 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2266 Constant *
Byte = importConstant(Slot, CSByConstantArg.first,
"byte",
2268 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2270 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2282 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2283 Type::getVoidTy(
M.getContext()))
2285 bool IsExported =
false;
2286 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2291void DevirtModule::removeRedundantTypeTests() {
2293 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2294 if (
U.second == 0) {
2295 U.first->replaceAllUsesWith(True);
2296 U.first->eraseFromParent();
2302DevirtModule::lookUpFunctionValueInfo(Function *TheFn,
2303 ModuleSummaryIndex *ExportSummary) {
2304 assert((ExportSummary !=
nullptr) &&
2305 "Caller guarantees ExportSummary is not nullptr");
2307 const auto TheFnGUID = TheFn->
getGUID();
2308 const auto TheFnGUIDWithExportedName =
2311 ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFnGUID);
2320 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2321 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2326bool DevirtModule::mustBeUnreachableFunction(
2327 Function *
const F, ModuleSummaryIndex *ExportSummary) {
2331 if (!
F->isDeclaration()) {
2337 return ExportSummary &&
2339 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2342bool DevirtModule::run() {
2356 &M, Intrinsic::type_checked_load_relative);
2363 if (!ExportSummary &&
2364 (!TypeTestFunc || TypeTestFunc->
use_empty() || !AssumeFunc ||
2366 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2367 (!TypeCheckedLoadRelativeFunc ||
2368 TypeCheckedLoadRelativeFunc->
use_empty()))
2372 std::vector<VTableBits>
Bits;
2373 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2374 buildTypeIdentifierMap(Bits, TypeIdMap);
2376 if (TypeTestFunc && AssumeFunc)
2377 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2379 if (TypeCheckedLoadFunc)
2380 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2382 if (TypeCheckedLoadRelativeFunc)
2383 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2385 if (ImportSummary) {
2386 for (
auto &S : CallSlots)
2387 importResolution(S.first, S.second);
2389 removeRedundantTypeTests();
2394 for (GlobalVariable &GV :
M.globals())
2402 if (TypeIdMap.
empty())
2406 if (ExportSummary) {
2407 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2408 for (
auto &
P : TypeIdMap) {
2411 TypeId->getString())]
2415 for (
auto &
P : *ExportSummary) {
2416 for (
auto &S :
P.second.SummaryList) {
2421 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2422 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2423 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2426 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2427 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2428 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2431 for (
const FunctionSummary::ConstVCall &VC :
2432 FS->type_test_assume_const_vcalls()) {
2433 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2434 CallSlots[{MD,
VC.VFunc.Offset}]
2435 .ConstCSInfo[
VC.Args]
2436 .addSummaryTypeTestAssumeUser(FS);
2439 for (
const FunctionSummary::ConstVCall &VC :
2440 FS->type_checked_load_const_vcalls()) {
2441 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2442 CallSlots[{MD,
VC.VFunc.Offset}]
2443 .ConstCSInfo[
VC.Args]
2444 .addSummaryTypeCheckedLoadUser(FS);
2452 bool DidVirtualConstProp =
false;
2453 std::map<std::string, GlobalValue *> DevirtTargets;
2454 for (
auto &S : CallSlots) {
2458 std::vector<VirtualCallTarget> TargetsForSlot;
2459 WholeProgramDevirtResolution *Res =
nullptr;
2460 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2462 TypeMemberInfos.size())
2469 Res = &ExportSummary
2470 ->getOrInsertTypeIdSummary(
2472 .WPDRes[S.first.ByteOffset];
2473 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2474 S.first.ByteOffset, ExportSummary)) {
2476 if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res)) {
2477 DidVirtualConstProp |=
2478 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2480 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2485 for (
const auto &
T : TargetsForSlot)
2487 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2497 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2498 if (!CSI.AllCallSitesDevirted)
2499 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2500 FS->addTypeTest(GUID);
2502 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2503 for (
auto &CCS : S.second.ConstCSInfo)
2504 AddTypeTestsForTypeCheckedLoads(CCS.second);
2508 if (RemarksEnabled) {
2510 for (
const auto &DT : DevirtTargets) {
2511 GlobalValue *GV = DT.second;
2520 using namespace ore;
2521 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE,
"Devirtualized",
F)
2522 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2526 NumDevirtTargets += DevirtTargets.size();
2528 removeRedundantTypeTests();
2532 if (DidVirtualConstProp)
2533 for (VTableBits &
B : Bits)
2539 for (GlobalVariable &GV :
M.globals())
2542 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2543 CI->eraseFromParent();
2548void DevirtIndex::run() {
2549 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2552 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2553 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2562 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2566 for (
auto &
P : ExportSummary) {
2567 for (
auto &S :
P.second.SummaryList) {
2572 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2573 for (StringRef Name : NameByGUID[VF.GUID]) {
2574 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2577 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2578 for (StringRef Name : NameByGUID[VF.GUID]) {
2579 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2582 for (
const FunctionSummary::ConstVCall &VC :
2583 FS->type_test_assume_const_vcalls()) {
2584 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2585 CallSlots[{
Name,
VC.VFunc.Offset}]
2586 .ConstCSInfo[
VC.Args]
2587 .addSummaryTypeTestAssumeUser(FS);
2590 for (
const FunctionSummary::ConstVCall &VC :
2591 FS->type_checked_load_const_vcalls()) {
2592 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2593 CallSlots[{
Name,
VC.VFunc.Offset}]
2594 .ConstCSInfo[
VC.Args]
2595 .addSummaryTypeCheckedLoadUser(FS);
2601 std::set<ValueInfo> DevirtTargets;
2603 for (
auto &S : CallSlots) {
2607 std::vector<ValueInfo> TargetsForSlot;
2608 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2612 WholeProgramDevirtResolution *Res =
2613 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2614 ->WPDRes[S.first.ByteOffset];
2615 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2616 S.first.ByteOffset)) {
2618 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2627 for (
const auto &DT : DevirtTargets)
2628 errs() <<
"Devirtualized call to " << DT <<
"\n";
2630 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
cl::opt< bool > ProfcheckDisableMetadataFixes("profcheck-disable-metadata-fixes", cl::Hidden, cl::init(false), cl::desc("Disable metadata propagation fixes discovered through Issue #147390"))
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static 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...
WPDCheckMode
Mechanism to add runtime checking of devirtualization decisions, optionally trapping or falling back ...
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)
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.
static bool typeIDVisibleToRegularObj(StringRef TypeID, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary)
static cl::list< std::string > SkipFunctionNames("wholeprogramdevirt-skip", cl::desc("Prevent function(s) from being devirtualized"), cl::Hidden, cl::CommaSeparated)
Provide way to prevent certain function from being devirtualized.
static cl::opt< 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)
static bool addCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee)
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"))
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 cl::opt< std::string > ClReadSummary("wholeprogramdevirt-read-summary", cl::desc("Read summary from given bitcode or YAML file before running pass"), cl::Hidden)
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...
static cl::opt< bool > PrintSummaryDevirt("wholeprogramdevirt-print-index-based", cl::Hidden, cl::desc("Print index-based devirtualization messages"))
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.
LLVM_ABI void setExplicitlyUnknownFunctionEntryCount(Function &F)
Analogous to setExplicitlyUnknownBranchWeights, but for functions and their entry counts.
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
@ Export
Export information to summary.
@ Import
Import information from summary.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
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.
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...
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 >
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.
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.
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.
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.
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