124#define DEBUG_TYPE "wholeprogramdevirt"
126STATISTIC(NumDevirtTargets,
"Number of whole program devirtualization targets");
127STATISTIC(NumSingleImpl,
"Number of single implementation devirtualizations");
129STATISTIC(NumUniformRetVal,
"Number of uniform return value optimizations");
130STATISTIC(NumUniqueRetVal,
"Number of unique return value optimizations");
132 "Number of 1 bit virtual constant propagations");
133STATISTIC(NumVirtConstProp,
"Number of virtual constant propagations");
135 "Controls how many calls should be devirtualized.");
140 "wholeprogramdevirt-summary-action",
141 cl::desc(
"What to do with the summary when running this pass"),
144 "Import typeid resolutions from summary and globals"),
146 "Export typeid resolutions to summary and globals")),
150 "wholeprogramdevirt-read-summary",
152 "Read summary from given bitcode or YAML file before running pass"),
156 "wholeprogramdevirt-write-summary",
157 cl::desc(
"Write summary to given bitcode or YAML file after running pass. "
158 "Output file format is deduced from extension: *.bc means writing "
159 "bitcode, otherwise YAML"),
165 "devirtualize-speculatively",
166 cl::desc(
"Enable speculative devirtualization optimization"),
172 cl::desc(
"Maximum number of call targets per "
173 "call site to enable branch funnels"));
177 cl::desc(
"Print index-based devirtualization messages"));
185 cl::desc(
"Enable whole program visibility"));
190 "disable-whole-program-visibility",
cl::Hidden,
191 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
196 cl::desc(
"Prevent function(s) from being devirtualized"),
221 "wholeprogramdevirt-keep-unreachable-function",
222 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
233 cl::desc(
"Type of checking for incorrect devirtualizations"),
237 "Fallback to indirect when incorrect")));
241 std::vector<GlobPattern> Patterns;
242 template <
class T>
void init(
const T &StringList) {
243 for (
const auto &S : StringList)
245 Patterns.push_back(std::move(*Pat));
247 bool match(StringRef S) {
248 for (
const GlobPattern &
P : Patterns)
266 MinByte = std::max(MinByte,
Target.minAfterBytes());
268 MinByte = std::max(MinByte,
Target.minBeforeBytes());
291 std::vector<ArrayRef<uint8_t>> Used;
294 :
Target.TM->Bits->Before.BytesUsed;
296 : MinByte -
Target.minBeforeBytes();
306 for (
unsigned I = 0;; ++
I) {
308 for (
auto &&
B : Used)
311 if (BitsUsed != 0xff)
317 for (
unsigned I = 0;; ++
I) {
318 for (
auto &&
B : Used) {
320 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
338 OffsetByte = -(AllocBefore / 8 + 1);
340 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
341 OffsetBit = AllocBefore % 8;
345 Target.setBeforeBit(AllocBefore);
355 OffsetByte = AllocAfter / 8;
357 OffsetByte = (AllocAfter + 7) / 8;
358 OffsetBit = AllocAfter % 8;
362 Target.setAfterBit(AllocAfter);
399 const VTableSlot &RHS) {
400 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
419 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
443 if (!Summary->isLive())
446 if (!FS->fflags().MustBeUnreachable)
461struct VirtualCallSite {
468 unsigned *NumUnsafeUses =
nullptr;
471 emitRemark(
const StringRef OptName,
const StringRef TargetName,
472 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter) {
478 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE, OptName, DLoc,
Block)
479 <<
NV(
"Optimization", OptName)
480 <<
": devirtualized a call to "
481 <<
NV(
"FunctionName", TargetName));
484 void replaceAndErase(
485 const StringRef OptName,
const StringRef TargetName,
bool RemarksEnabled,
486 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter,
493 II->getUnwindDest()->removePredecessor(
II->getParent());
510 std::vector<VirtualCallSite> CallSites;
519 bool AllCallSitesDevirted =
true;
528 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
532 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
534 bool isExported()
const {
535 return !SummaryTypeCheckedLoadUsers.empty() ||
536 !SummaryTypeTestAssumeUsers.empty();
539 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
540 SummaryTypeCheckedLoadUsers.push_back(FS);
541 AllCallSitesDevirted =
false;
544 void addSummaryTypeTestAssumeUser(FunctionSummary *FS) {
545 SummaryTypeTestAssumeUsers.push_back(FS);
546 AllCallSitesDevirted =
false;
549 void markDevirt() { AllCallSitesDevirted =
true; }
553struct VTableSlotInfo {
560 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
562 void addCallSite(
Value *VTable, CallBase &CB,
unsigned *NumUnsafeUses);
568CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) {
569 std::vector<uint64_t>
Args;
571 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
575 if (!CI || CI->getBitWidth() > 64)
577 Args.push_back(CI->getZExtValue());
579 return ConstCSInfo[
Args];
582void VTableSlotInfo::addCallSite(
Value *VTable, CallBase &CB,
583 unsigned *NumUnsafeUses) {
584 auto &CSI = findCallSiteInfo(CB);
585 CSI.AllCallSitesDevirted =
false;
586 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
594 ModuleSummaryIndex *
const ExportSummary;
595 const ModuleSummaryIndex *
const ImportSummary;
597 IntegerType *
const Int8Ty;
600 IntegerType *
const Int64Ty;
601 IntegerType *
const IntPtrTy;
607 const bool RemarksEnabled;
608 std::function<OptimizationRemarkEmitter &(
Function &)> OREGetter;
609 MapVector<VTableSlot, VTableSlotInfo> CallSlots;
614 SmallPtrSet<CallBase *, 8> OptimizedCalls;
628 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
629 PatternList FunctionsToSkip;
631 const bool DevirtSpeculatively;
633 ModuleSummaryIndex *ExportSummary,
634 const ModuleSummaryIndex *ImportSummary,
635 bool DevirtSpeculatively)
638 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
643 IntPtrTy(
M.getDataLayout().getIntPtrType(
M.
getContext(), 0)),
645 RemarksEnabled(areRemarksEnabled()),
646 OREGetter([&](
Function &
F) -> OptimizationRemarkEmitter & {
649 DevirtSpeculatively(DevirtSpeculatively) {
650 assert(!(ExportSummary && ImportSummary));
654 bool areRemarksEnabled();
657 scanTypeTestUsers(Function *TypeTestFunc,
658 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
659 void scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc);
661 void buildTypeIdentifierMap(
662 std::vector<VTableBits> &Bits,
663 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
666 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
667 const std::set<TypeMemberInfo> &TypeMemberInfos,
669 ModuleSummaryIndex *ExportSummary);
671 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
673 bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
675 VTableSlotInfo &SlotInfo,
676 WholeProgramDevirtResolution *Res);
678 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Function &JT,
681 VTableSlotInfo &SlotInfo,
682 WholeProgramDevirtResolution *Res, VTableSlot Slot);
684 bool tryEvaluateFunctionsWithArgs(
686 ArrayRef<uint64_t> Args);
688 void applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
692 WholeProgramDevirtResolution::ByArg *Res);
696 std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
699 bool shouldExportConstantsAsAbsoluteSymbols();
704 void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
706 void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
707 uint32_t Const, uint32_t &Storage);
711 Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
713 Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
714 StringRef Name, IntegerType *IntTy,
717 Constant *getMemberAddr(
const TypeMemberInfo *M);
719 void applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
bool IsOne,
720 Constant *UniqueMemberAddr);
721 bool tryUniqueRetValOpt(
unsigned BitWidth,
724 WholeProgramDevirtResolution::ByArg *Res,
725 VTableSlot Slot, ArrayRef<uint64_t> Args);
727 void applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
728 Constant *Byte, Constant *Bit);
730 VTableSlotInfo &SlotInfo,
731 WholeProgramDevirtResolution *Res, VTableSlot Slot);
733 void rebuildGlobal(VTableBits &
B);
736 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
740 void removeRedundantTypeTests();
747 static ValueInfo lookUpFunctionValueInfo(Function *TheFn,
748 ModuleSummaryIndex *ExportSummary);
759 ModuleSummaryIndex *ExportSummary);
764 bool DevirtSpeculatively);
768 ModuleSummaryIndex &ExportSummary;
771 std::set<GlobalValue::GUID> &ExportedGUIDs;
775 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
780 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr;
782 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
784 PatternList FunctionsToSkip;
787 ModuleSummaryIndex &ExportSummary,
788 std::set<GlobalValue::GUID> &ExportedGUIDs,
789 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
790 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr)
791 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
792 LocalWPDTargetsMap(LocalWPDTargetsMap),
793 ExternallyVisibleSymbolNamesPtr(ExternallyVisibleSymbolNamesPtr) {
797 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
799 uint64_t ByteOffset);
802 VTableSlotSummary &SlotSummary,
803 VTableSlotInfo &SlotInfo,
804 WholeProgramDevirtResolution *Res,
805 std::set<ValueInfo> &DevirtTargets);
819 std::optional<ModuleSummaryIndex> Index;
823 "ExportSummary is expected to be empty in non-LTO mode");
826 ExportSummary = Index.has_value() ? &Index.value() :
nullptr;
847 if (
TypeID.ends_with(
".virtual"))
853 if (!
TypeID.consume_front(
"_ZTS"))
861 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
862 return IsVisibleToRegularObj(TypeInfo);
871 for (
auto *
Type : Types)
874 IsVisibleToRegularObj);
883 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
885 bool ValidateAllVtablesHaveTypeInfos,
902 !(ValidateAllVtablesHaveTypeInfos &&
909 bool WholeProgramVisibilityEnabledInLTO) {
913 if (!PublicTypeTestFunc)
921 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
923 CI->replaceAllUsesWith(NewCI);
924 CI->eraseFromParent();
932 CI->replaceAllUsesWith(True);
933 CI->eraseFromParent();
944 for (
const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
947 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
960 for (
auto &
P : Index) {
963 if (DynamicExportSymbols.
count(
P.first))
969 if (VisibleToRegularObjSymbols.
count(
P.first))
971 for (
auto &S :
P.second.getSummaryList()) {
983 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
985 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap,
986 ExternallyVisibleSymbolNamesPtr)
993 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
995 for (
auto &
T : LocalWPDTargetsMap) {
998 assert(VI.getSummaryList().size() == 1 &&
999 "Devirt of local target has more than one copy");
1000 auto &S = VI.getSummaryList()[0];
1001 if (!IsExported(S->modulePath(), VI))
1005 for (
auto &SlotSummary :
T.second) {
1006 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
1008 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
1009 assert(WPDRes != TIdSum->WPDRes.end());
1010 if (ExternallyVisibleSymbolNamesPtr)
1011 ExternallyVisibleSymbolNamesPtr->
insert(WPDRes->second.SingleImplName);
1013 WPDRes->second.SingleImplName,
1014 Summary.getModuleHash(S->modulePath()));
1024 const auto &ModPaths = Summary->modulePaths();
1029 "combined summary should contain Regular LTO module");
1034 bool DevirtSpeculatively) {
1035 std::unique_ptr<ModuleSummaryIndex>
Summary =
1036 std::make_unique<ModuleSummaryIndex>(
false);
1041 ExitOnError ExitOnErr(
"-wholeprogramdevirt-read-summary: " +
ClReadSummary +
1043 auto ReadSummaryFile =
1045 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1047 Summary = std::move(*SummaryOrErr);
1052 yaml::Input
In(ReadSummaryFile->getBuffer());
1059 DevirtModule(M,
MAM,
1064 DevirtSpeculatively)
1068 ExitOnError ExitOnErr(
1078 yaml::Output Out(OS);
1086void DevirtModule::buildTypeIdentifierMap(
1087 std::vector<VTableBits> &Bits,
1088 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1089 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1090 Bits.reserve(
M.global_size());
1092 for (GlobalVariable &GV :
M.globals()) {
1100 Bits.emplace_back();
1101 Bits.back().GV = &GV;
1102 Bits.back().ObjectSize =
1104 BitsPtr = &
Bits.back();
1107 for (MDNode *
Type : Types) {
1120bool DevirtModule::tryFindVirtualCallTargets(
1121 std::vector<VirtualCallTarget> &TargetsForSlot,
1122 const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset,
1123 ModuleSummaryIndex *ExportSummary) {
1125 if (!TM.Bits->GV->isConstant())
1130 if (!DevirtSpeculatively && TM.Bits->GV->getVCallVisibility() ==
1142 if (FunctionsToSkip.match(Fn->
getName()))
1147 if (Fn->
getName() ==
"__cxa_pure_virtual")
1165 TargetsForSlot.push_back({GV, &TM});
1169 return !TargetsForSlot.empty();
1172bool DevirtIndex::tryFindVirtualCallTargets(
1173 std::vector<ValueInfo> &TargetsForSlot,
1175 for (
const TypeIdOffsetVtableInfo &
P : TIdInfo) {
1186 if (
P.VTableVI.hasLocal() &&
P.VTableVI.getSummaryList().size() > 1)
1188 const GlobalVarSummary *
VS =
nullptr;
1189 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1191 if (!CurVS->vTableFuncs().empty() ||
1214 for (
auto VTP :
VS->vTableFuncs()) {
1215 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1221 TargetsForSlot.push_back(VTP.FuncVI);
1226 return !TargetsForSlot.empty();
1229void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1230 Constant *TheFn,
bool &IsExported) {
1236 for (
auto &&VCallSite : CSInfo.CallSites) {
1237 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1245 VCallSite.emitRemark(
"single-impl",
1248 auto &CB = VCallSite.CB;
1261 MDBuilder(
M.getContext()).createUnlikelyBranchWeights());
1262 Builder.SetInsertPoint(ThenTerm);
1265 auto *CallTrap = Builder.CreateCall(TrapFn);
1274 MDNode *Weights = MDBuilder(
M.getContext()).createLikelyBranchWeights();
1283 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1284 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1306 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1311 if (VCallSite.NumUnsafeUses)
1312 --*VCallSite.NumUnsafeUses;
1314 if (CSInfo.isExported())
1316 CSInfo.markDevirt();
1318 Apply(SlotInfo.CSInfo);
1319 for (
auto &
P : SlotInfo.ConstCSInfo)
1325 if (Callee.getSummaryList().empty())
1332 bool IsExported =
false;
1333 auto &S = Callee.getSummaryList()[0];
1335 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1336 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1337 FS->addCall({Callee, CI});
1338 IsExported |= S->modulePath() != FS->modulePath();
1340 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1341 FS->addCall({Callee, CI});
1342 IsExported |= S->modulePath() != FS->modulePath();
1345 AddCalls(SlotInfo.CSInfo);
1346 for (
auto &
P : SlotInfo.ConstCSInfo)
1351bool DevirtModule::trySingleImplDevirt(
1352 ModuleSummaryIndex *ExportSummary,
1354 WholeProgramDevirtResolution *Res) {
1357 auto *TheFn = TargetsForSlot[0].Fn;
1358 for (
auto &&Target : TargetsForSlot)
1364 TargetsForSlot[0].WasDevirt =
true;
1366 bool IsExported =
false;
1367 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1374 if (TheFn->hasLocalLinkage()) {
1375 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1380 if (Comdat *
C = TheFn->getComdat()) {
1381 if (
C->getName() == TheFn->
getName()) {
1382 Comdat *NewC =
M.getOrInsertComdat(NewName);
1384 for (GlobalObject &GO :
M.global_objects())
1385 if (GO.getComdat() ==
C)
1394 if (ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFn->getGUID()))
1406 VTableSlotSummary &SlotSummary,
1407 VTableSlotInfo &SlotInfo,
1408 WholeProgramDevirtResolution *Res,
1409 std::set<ValueInfo> &DevirtTargets) {
1412 auto TheFn = TargetsForSlot[0];
1413 for (
auto &&Target : TargetsForSlot)
1414 if (TheFn != Target)
1418 auto Size = TheFn.getSummaryList().size();
1424 if (FunctionsToSkip.match(TheFn.name()))
1429 if (TheFn.hasLocal() &&
Size > 1)
1434 DevirtTargets.insert(TheFn);
1436 auto &S = TheFn.getSummaryList()[0];
1437 bool IsExported =
addCalls(SlotInfo, TheFn);
1439 ExportedGUIDs.insert(TheFn.getGUID());
1449 if (ExternallyVisibleSymbolNamesPtr)
1450 ExternallyVisibleSymbolNamesPtr->insert(TheFn.name());
1452 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1454 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1468void DevirtModule::tryICallBranchFunnel(
1470 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1471 Triple
T(
M.getTargetTriple());
1478 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1480 for (
auto &
P : SlotInfo.ConstCSInfo)
1481 if (!
P.second.AllCallSitesDevirted) {
1482 HasNonDevirt =
true;
1500 for (
auto &
T : TargetsForSlot) {
1501 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1510 M.getDataLayout().getProgramAddressSpace(),
1511 getGlobalName(Slot, {},
"branch_funnel"), &
M);
1515 M.getDataLayout().getProgramAddressSpace(),
1516 "branch_funnel", &M);
1520 std::vector<Value *> JTArgs;
1522 for (
auto &
T : TargetsForSlot) {
1523 JTArgs.push_back(getMemberAddr(
T.TM));
1524 JTArgs.push_back(
T.Fn);
1529 &M, llvm::Intrinsic::icall_branch_funnel, {});
1535 bool IsExported =
false;
1536 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1546void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1547 Function &JT,
bool &IsExported) {
1548 DenseMap<Function *, double> FunctionEntryCounts;
1550 if (CSInfo.isExported())
1552 if (CSInfo.AllCallSitesDevirted)
1555 std::map<CallBase *, CallBase *> CallBases;
1556 for (
auto &&VCallSite : CSInfo.CallSites) {
1557 CallBase &CB = VCallSite.CB;
1559 if (CallBases.find(&CB) != CallBases.end()) {
1576 VCallSite.emitRemark(
"branch-funnel", JT.
getName(), OREGetter);
1580 std::vector<Type *> NewArgs;
1581 NewArgs.push_back(Int8PtrTy);
1583 FunctionType *NewFT =
1587 std::vector<Value *>
Args;
1588 Args.push_back(VCallSite.VTable);
1591 CallBase *NewCS =
nullptr;
1597 auto EC = BFI.getBlockFreq(&
F.getEntryBlock());
1598 auto CC =
F.getEntryCount(
true);
1599 double CallCount = 0.0;
1600 if (
EC.getFrequency() != 0 && CC && CC->getCount() != 0) {
1602 static_cast<double>(
1603 BFI.getBlockFreq(CB.
getParent()).getFrequency()) /
1605 CallCount = CallFreq * CC->getCount();
1607 FunctionEntryCounts[&JT] += CallCount;
1610 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1618 std::vector<AttributeSet> NewArgAttrs;
1621 M.getContext(), Attribute::Nest)}));
1622 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1623 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1625 AttributeList::get(
M.getContext(),
Attrs.getFnAttrs(),
1626 Attrs.getRetAttrs(), NewArgAttrs));
1628 CallBases[&CB] = NewCS;
1631 if (VCallSite.NumUnsafeUses)
1632 --*VCallSite.NumUnsafeUses;
1639 for (
auto &[Old, New] : CallBases) {
1640 Old->replaceAllUsesWith(New);
1641 Old->eraseFromParent();
1644 Apply(SlotInfo.CSInfo);
1645 for (
auto &
P : SlotInfo.ConstCSInfo)
1647 for (
auto &[
F,
C] : FunctionEntryCounts) {
1648 assert(!
F->getEntryCount(
true) &&
1649 "Unexpected entry count for funnel that was freshly synthesized");
1650 F->setEntryCount(
static_cast<uint64_t
>(std::round(
C)));
1654bool DevirtModule::tryEvaluateFunctionsWithArgs(
1656 ArrayRef<uint64_t> Args) {
1670 Evaluator Eval(
M.getDataLayout(),
nullptr);
1674 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1679 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1683 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1691void DevirtModule::applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1692 uint64_t TheRetVal) {
1693 for (
auto Call : CSInfo.CallSites) {
1697 Call.replaceAndErase(
1698 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1701 CSInfo.markDevirt();
1704bool DevirtModule::tryUniformRetValOpt(
1706 WholeProgramDevirtResolution::ByArg *Res) {
1709 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1711 if (
Target.RetVal != TheRetVal)
1714 if (CSInfo.isExported()) {
1716 Res->
Info = TheRetVal;
1719 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1721 for (
auto &&Target : TargetsForSlot)
1726std::string DevirtModule::getGlobalName(VTableSlot Slot,
1727 ArrayRef<uint64_t> Args,
1729 std::string FullName =
"__typeid_";
1730 raw_string_ostream OS(FullName);
1731 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1732 for (uint64_t Arg : Args)
1738bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1739 Triple
T(
M.getTargetTriple());
1743void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1744 StringRef Name, Constant *
C) {
1746 getGlobalName(Slot, Args, Name),
C, &M);
1750void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1751 StringRef Name, uint32_t Const,
1752 uint32_t &Storage) {
1753 if (shouldExportConstantsAsAbsoluteSymbols()) {
1763Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1765 GlobalVariable *GV =
1766 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1771Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1772 StringRef Name, IntegerType *IntTy,
1774 if (!shouldExportConstantsAsAbsoluteSymbols())
1775 return ConstantInt::get(IntTy, Storage);
1777 Constant *
C = importGlobal(Slot, Args, Name);
1783 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1786 auto SetAbsRange = [&](uint64_t Min, uint64_t
Max) {
1797 SetAbsRange(0, 1ull << AbsWidth);
1802void DevirtModule::applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1804 Constant *UniqueMemberAddr) {
1805 for (
auto &&
Call : CSInfo.CallSites) {
1811 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->
getType()));
1814 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1817 CSInfo.markDevirt();
1822 ConstantInt::get(Int64Ty,
M->Offset));
1825bool DevirtModule::tryUniqueRetValOpt(
1827 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1828 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1830 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1833 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1836 UniqueMember =
Target.TM;
1844 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1845 if (CSInfo.isExported()) {
1849 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1853 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1858 for (
auto &&Target : TargetsForSlot)
1865 if (tryUniqueRetValOptFor(
true))
1867 if (tryUniqueRetValOptFor(
false))
1873void DevirtModule::applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
1874 Constant *Byte, Constant *Bit) {
1875 for (
auto Call : CSInfo.CallSites) {
1880 Value *Addr =
B.CreatePtrAdd(
Call.VTable, Byte);
1881 if (RetType->getBitWidth() == 1) {
1883 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1884 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1885 NumVirtConstProp1Bit++;
1886 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1887 OREGetter, IsBitSet);
1889 Value *Val =
B.CreateLoad(RetType, Addr);
1891 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1895 CSInfo.markDevirt();
1898bool DevirtModule::tryVirtualConstProp(
1900 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1911 unsigned BitWidth = RetType->getBitWidth();
1923 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1956 GlobalVariable *GV =
Target.TM->Bits->GV;
1957 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1959 if (TypeAlignment > TableAlignment)
1963 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1964 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1967 WholeProgramDevirtResolution::ByArg *ResByArg =
nullptr;
1969 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1971 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1974 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1975 ResByArg, Slot, CSByConstantArg.first))
1983 uint64_t AllocBefore =
1985 uint64_t AllocAfter =
1990 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1991 for (
auto &&Target : TargetsForSlot) {
1992 TotalPaddingBefore += std::max<int64_t>(
1993 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1994 TotalPaddingAfter += std::max<int64_t>(
1995 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
2000 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
2007 if (TotalPaddingBefore <= TotalPaddingAfter)
2023 for (
auto &&Target : TargetsForSlot)
2027 if (CSByConstantArg.second.isExported()) {
2029 exportConstant(Slot, CSByConstantArg.first,
"byte", OffsetByte,
2031 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
2037 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
2038 applyVirtualConstProp(CSByConstantArg.second,
2039 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
2045 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
2050 Align Alignment =
M.getDataLayout().getValueOrABITypeAlignment(
2051 B.GV->getAlign(),
B.GV->getValueType());
2052 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
2055 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
2062 B.GV->getInitializer(),
2065 new GlobalVariable(M, NewInit->getType(),
B.GV->isConstant(),
2067 NewGV->setSection(
B.GV->getSection());
2068 NewGV->setComdat(
B.GV->getComdat());
2069 NewGV->setAlignment(
B.GV->getAlign());
2073 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
2078 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2080 NewInit->getType(), NewGV,
2082 ConstantInt::get(Int32Ty, 1)}),
2084 Alias->setVisibility(
B.GV->getVisibility());
2085 Alias->takeName(
B.GV);
2087 B.GV->replaceAllUsesWith(Alias);
2088 B.GV->eraseFromParent();
2091bool DevirtModule::areRemarksEnabled() {
2092 const auto &FL =
M.getFunctionList();
2093 for (
const Function &Fn : FL) {
2097 return DI.isEnabled();
2102void DevirtModule::scanTypeTestUsers(
2103 Function *TypeTestFunc,
2104 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2118 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2124 if (!Assumes.
empty()) {
2125 Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();
2126 for (DevirtCallSite
Call : DevirtCalls)
2127 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
nullptr);
2130 auto RemoveTypeTestAssumes = [&]() {
2132 for (
auto *Assume : Assumes)
2133 Assume->eraseFromParent();
2136 if (CI->use_empty())
2137 CI->eraseFromParent();
2152 if (!TypeIdMap.count(TypeId))
2153 RemoveTypeTestAssumes();
2165 const TypeIdSummary *TidSummary =
2168 RemoveTypeTestAssumes();
2177void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {
2186 Value *Ptr = CI->getArgOperand(0);
2188 Value *TypeIdValue = CI->getArgOperand(2);
2194 bool HasNonCallUses =
false;
2195 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2197 HasNonCallUses, CI, DT);
2206 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2208 Value *LoadedValue =
nullptr;
2210 Intrinsic::type_checked_load_relative) {
2212 &M, Intrinsic::load_relative, {
Int32Ty});
2213 LoadedValue = LoadB.CreateCall(LoadRelFunc, {Ptr,
Offset});
2216 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2219 for (Instruction *LoadedPtr : LoadedPtrs) {
2220 LoadedPtr->replaceAllUsesWith(LoadedValue);
2221 LoadedPtr->eraseFromParent();
2225 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2226 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {Ptr, TypeIdValue});
2228 for (Instruction *Pred : Preds) {
2229 Pred->replaceAllUsesWith(TypeTestCall);
2230 Pred->eraseFromParent();
2237 if (!CI->use_empty()) {
2240 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2241 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2246 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2247 NumUnsafeUses = DevirtCalls.
size();
2254 for (DevirtCallSite
Call : DevirtCalls) {
2255 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
2259 CI->eraseFromParent();
2263void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2267 const TypeIdSummary *TidSummary =
2271 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2272 if (ResI == TidSummary->
WPDRes.end())
2274 const WholeProgramDevirtResolution &Res = ResI->second;
2286 bool IsExported =
false;
2287 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2291 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2292 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2295 auto &ResByArg =
I->second;
2302 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2306 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2307 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2312 Constant *
Byte = importConstant(Slot, CSByConstantArg.first,
"byte",
2314 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2316 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2328 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2331 bool IsExported =
false;
2332 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2337void DevirtModule::removeRedundantTypeTests() {
2339 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2340 if (
U.second == 0) {
2341 U.first->replaceAllUsesWith(True);
2342 U.first->eraseFromParent();
2348DevirtModule::lookUpFunctionValueInfo(Function *TheFn,
2349 ModuleSummaryIndex *ExportSummary) {
2350 assert((ExportSummary !=
nullptr) &&
2351 "Caller guarantees ExportSummary is not nullptr");
2353 const auto TheFnGUID = TheFn->
getGUID();
2354 const auto TheFnGUIDWithExportedName =
2357 ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFnGUID);
2366 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2367 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2372bool DevirtModule::mustBeUnreachableFunction(
2373 Function *
const F, ModuleSummaryIndex *ExportSummary) {
2377 if (!
F->isDeclaration()) {
2383 return ExportSummary &&
2385 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2388bool DevirtModule::run() {
2397 Function *PublicTypeTestFunc =
nullptr;
2400 if (DevirtSpeculatively)
2401 PublicTypeTestFunc =
2408 &M, Intrinsic::type_checked_load_relative);
2415 if (!ExportSummary &&
2416 (((!PublicTypeTestFunc || PublicTypeTestFunc->
use_empty()) &&
2417 (!TypeTestFunc || TypeTestFunc->
use_empty())) ||
2418 !AssumeFunc || AssumeFunc->
use_empty()) &&
2419 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2420 (!TypeCheckedLoadRelativeFunc ||
2421 TypeCheckedLoadRelativeFunc->
use_empty()))
2425 std::vector<VTableBits>
Bits;
2426 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2427 buildTypeIdentifierMap(Bits, TypeIdMap);
2429 if (PublicTypeTestFunc && AssumeFunc)
2430 scanTypeTestUsers(PublicTypeTestFunc, TypeIdMap);
2432 if (TypeTestFunc && AssumeFunc)
2433 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2435 if (TypeCheckedLoadFunc)
2436 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2438 if (TypeCheckedLoadRelativeFunc)
2439 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2441 if (ImportSummary) {
2442 for (
auto &S : CallSlots)
2443 importResolution(S.first, S.second);
2445 removeRedundantTypeTests();
2450 for (GlobalVariable &GV :
M.globals())
2458 if (TypeIdMap.
empty())
2462 if (ExportSummary) {
2463 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2464 for (
auto &
P : TypeIdMap) {
2467 TypeId->getString())]
2471 for (
auto &
P : *ExportSummary) {
2472 for (
auto &S :
P.second.getSummaryList()) {
2477 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2478 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2479 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2482 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2483 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2484 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2487 for (
const FunctionSummary::ConstVCall &VC :
2488 FS->type_test_assume_const_vcalls()) {
2489 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2490 CallSlots[{MD,
VC.VFunc.Offset}]
2491 .ConstCSInfo[
VC.Args]
2492 .addSummaryTypeTestAssumeUser(FS);
2495 for (
const FunctionSummary::ConstVCall &VC :
2496 FS->type_checked_load_const_vcalls()) {
2497 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2498 CallSlots[{MD,
VC.VFunc.Offset}]
2499 .ConstCSInfo[
VC.Args]
2500 .addSummaryTypeCheckedLoadUser(FS);
2508 bool DidVirtualConstProp =
false;
2509 std::map<std::string, GlobalValue *> DevirtTargets;
2510 for (
auto &S : CallSlots) {
2514 std::vector<VirtualCallTarget> TargetsForSlot;
2515 WholeProgramDevirtResolution *Res =
nullptr;
2516 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2518 TypeMemberInfos.size())
2525 Res = &ExportSummary
2526 ->getOrInsertTypeIdSummary(
2528 .WPDRes[S.first.ByteOffset];
2529 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2530 S.first.ByteOffset, ExportSummary)) {
2531 bool SingleImplDevirt =
2532 trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res);
2536 if (!SingleImplDevirt && !DevirtSpeculatively) {
2537 DidVirtualConstProp |=
2538 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2540 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2545 for (
const auto &
T : TargetsForSlot)
2547 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2557 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2558 if (!CSI.AllCallSitesDevirted)
2559 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2560 FS->addTypeTest(GUID);
2562 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2563 for (
auto &CCS : S.second.ConstCSInfo)
2564 AddTypeTestsForTypeCheckedLoads(CCS.second);
2568 if (RemarksEnabled) {
2570 for (
const auto &DT : DevirtTargets) {
2571 GlobalValue *GV = DT.second;
2580 using namespace ore;
2581 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE,
"Devirtualized",
F)
2582 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2586 NumDevirtTargets += DevirtTargets.size();
2588 removeRedundantTypeTests();
2592 if (DidVirtualConstProp)
2599 for (GlobalVariable &GV :
M.globals())
2602 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2603 CI->eraseFromParent();
2608void DevirtIndex::run() {
2609 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2614 assert(!ExportSummary.withInternalizeAndPromote() &&
2615 "Expect index-based WPD to run before internalization and promotion");
2617 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2618 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2627 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2631 for (
auto &
P : ExportSummary) {
2632 for (
auto &S :
P.second.getSummaryList()) {
2637 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2638 for (StringRef Name : NameByGUID[VF.GUID]) {
2639 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2642 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2643 for (StringRef Name : NameByGUID[VF.GUID]) {
2644 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2647 for (
const FunctionSummary::ConstVCall &VC :
2648 FS->type_test_assume_const_vcalls()) {
2649 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2650 CallSlots[{
Name,
VC.VFunc.Offset}]
2651 .ConstCSInfo[
VC.Args]
2652 .addSummaryTypeTestAssumeUser(FS);
2655 for (
const FunctionSummary::ConstVCall &VC :
2656 FS->type_checked_load_const_vcalls()) {
2657 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2658 CallSlots[{
Name,
VC.VFunc.Offset}]
2659 .ConstCSInfo[
VC.Args]
2660 .addSummaryTypeCheckedLoadUser(FS);
2666 std::set<ValueInfo> DevirtTargets;
2668 for (
auto &S : CallSlots) {
2672 std::vector<ValueInfo> TargetsForSlot;
2673 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2677 WholeProgramDevirtResolution *Res =
2678 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2679 ->WPDRes[S.first.ByteOffset];
2680 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2681 S.first.ByteOffset)) {
2683 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2692 for (
const auto &DT : DevirtTargets)
2693 errs() <<
"Devirtualized call to " << DT <<
"\n";
2695 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 provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
This file defines DenseMapInfo traits for DenseMap.
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
Provides passes for computing function attributes based on interprocedural analyses.
static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE, bool Skip)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
static cl::opt< PassSummaryAction > ClSummaryAction("lowertypetests-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
static bool mustBeUnreachableFunction(const Function &F)
This is the interface to build a ModuleSummaryIndex for a module.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
This file contains the declarations for profiling metadata utility functions.
const SmallVectorImpl< MachineOperand > & Cond
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
WPDCheckMode
Mechanism to add runtime checking of devirtualization decisions, optionally trapping or falling back ...
static bool typeIDVisibleToRegularObj(StringRef TypeID, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary)
static bool addCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee)
static cl::opt< WPDCheckMode > DevirtCheckMode("wholeprogramdevirt-check", cl::Hidden, cl::desc("Type of checking for incorrect devirtualizations"), cl::values(clEnumValN(WPDCheckMode::None, "none", "No checking"), clEnumValN(WPDCheckMode::Trap, "trap", "Trap when incorrect"), clEnumValN(WPDCheckMode::Fallback, "fallback", "Fallback to indirect when incorrect")))
static cl::opt< bool > WholeProgramDevirtKeepUnreachableFunction("wholeprogramdevirt-keep-unreachable-function", cl::desc("Regard unreachable functions as possible devirtualize targets."), cl::Hidden, cl::init(true))
With Clang, a pure virtual class's deleting destructor is emitted as a llvm.trap intrinsic followed b...
static bool skipUpdateDueToValidation(GlobalVariable &GV, function_ref< bool(StringRef)> IsVisibleToRegularObj)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
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 Constant * getPtrAdd(Constant *Ptr, Constant *Offset, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReduced=nullptr)
Create a getelementptr i8, ptr, offset constant expression.
static LLVM_ABI Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
static Constant * getAnon(ArrayRef< Constant * > V, bool Packed=false)
Return an anonymous struct that has the specified elements.
const Constant * stripPointerCasts() const
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
static bool shouldExecute(CounterInfo &Counter)
Implements a dense probed hash-table based set.
Subclass of Error for the sole purpose of identifying the success path in the type system.
Lightweight error class with error context and mandatory checking.
Tagged union holding either a T or a Error.
Type * getParamType(unsigned i) const
Parameter type accessors.
ArrayRef< Type * > params() const
Type * getReturnType() const
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
FunctionType * getFunctionType() const
Returns the FunctionType for me.
const BasicBlock & front() const
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
adds the attribute to the list of attributes for the given arg.
std::optional< ProfileCount > getEntryCount(bool AllowSynthetic=false) const
Get the entry count for this function.
Type * getReturnType() const
Returns the type of the ret val.
unsigned getInstructionCount() const
Returns the number of non-debug IR instructions in this function.
static LLVM_ABI Expected< GlobPattern > create(StringRef Pat, std::optional< size_t > MaxSubPatterns={})
static LLVM_ABI GlobalAlias * create(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, Constant *Aliasee, Module *Parent)
If a parent module is specified, the alias is automatically inserted into the end of the specified mo...
bool hasMetadata() const
Return true if this value has any metadata attached to it.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
LLVM_ABI VCallVisibility getVCallVisibility() const
LLVM_ABI bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
@ VCallVisibilityLinkageUnit
MDNode * getMetadata(unsigned KindID) const
Get the current metadata attachments for the given kind, if any.
LLVM_ABI void setVCallVisibilityMetadata(VCallVisibility Visibility)
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
static bool isLocalLinkage(LinkageTypes Linkage)
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
static bool isAvailableExternallyLinkage(LinkageTypes Linkage)
GUID getGUID() const
Return a 64-bit global unique ID constructed from global value name (i.e.
@ HiddenVisibility
The GV is hidden.
void setVisibility(VisibilityTypes V)
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
@ ExternalLinkage
Externally visible function.
Type * getValueType() const
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
MaybeAlign getAlign() const
Returns the alignment of the given variable.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
uint64_t getBitMask() const
Return a bitmask with ones set for all of the bits that can be set by an unsigned version of this typ...
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
bool doesNotAccessMemory() const
Whether this function accesses no memory.
Class to hold module path string table and global value map, and encapsulate methods for operating on...
const TypeIdSummary * getTypeIdSummary(StringRef TypeId) const
This returns either a pointer to the type id summary (if present in the summary map) or null (if not ...
ValueInfo getValueInfo(const GlobalValueSummaryMapTy::value_type &R) const
Return a ValueInfo for the index value_type (convenient when iterating index).
const ModuleHash & getModuleHash(const StringRef ModPath) const
Get the module SHA1 hash recorded for the given module path.
static constexpr const char * getRegularLTOModuleName()
bool partiallySplitLTOUnits() const
static std::string getGlobalNameForLocal(StringRef Name, ModuleHash ModHash)
Convenience method for creating a promoted global name for the given value name of a local,...
A Module instance is used to store all the information related to an LLVM module.
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.
Analysis providing profile information.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
Target - Wrapper for Target specific information.
The TimeTraceScope is a helper class to call the begin and end functions of the time trace profiler.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
A Use represents the edge between a Value definition and its users.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
self_iterator getIterator()
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
LLVM_ABI Function * getDeclarationIfExists(const Module *M, ID id)
Look up the Function declaration of the intrinsic id in the Module M and return it if it exists.
bool match(Val *V, const Pattern &P)
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
@ Assume
Do not drop type tests (default).
DiagnosticInfoOptimizationBase::Argument NV
Context & getContext() const
friend class Instruction
Iterator for Instructions in a `BasicBlock.
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
LLVM_ABI uint64_t findLowestOffset(ArrayRef< VirtualCallTarget > Targets, bool IsAfter, uint64_t Size)
LLVM_ABI void setAfterReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocAfter, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)
LLVM_ABI void setBeforeReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocBefore, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
FunctionAddr VTableAddr Value
cl::opt< bool > ProfcheckDisableMetadataFixes
LLVM_ABI void runWholeProgramDevirtOnIndex(ModuleSummaryIndex &Summary, std::set< GlobalValue::GUID > &ExportedGUIDs, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap, DenseSet< StringRef > *ExternallyVisibleSymbolNamesPtr=nullptr)
Perform index-based whole program devirtualization on the Summary index.
LLVM_ABI MemoryEffects computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR)
Returns the memory access properties of this copy of the function.
static cl::opt< bool > DisableWholeProgramVisibility("disable-whole-program-visibility", cl::Hidden, cl::desc("Disable whole program visibility (overrides enabling options)"))
Provide a way to force disable whole program for debugging or workarounds, when enabled via the linke...
static cl::opt< bool > WholeProgramVisibility("whole-program-visibility", cl::Hidden, cl::desc("Enable whole program visibility"))
Provide a way to force enable whole program visibility in tests.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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.
LLVM_ABI ModuleSummaryIndex buildModuleSummaryIndex(const Module &M, std::function< BlockFrequencyInfo *(const Function &F)> GetBFICallback, ProfileSummaryInfo *PSI, std::function< const StackSafetyInfo *(const Function &F)> GetSSICallback=[](const Function &F) -> const StackSafetyInfo *{ return nullptr;})
Direct function to compute a ModuleSummaryIndex from a given module.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
LLVM_ABI bool hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO)
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
LLVM_ABI void writeIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out, const ModuleToSummariesForIndexTy *ModuleToSummariesForIndex=nullptr, const GVSummaryPtrSet *DecSummaries=nullptr)
Write the specified module summary index to the given raw output stream, where it will be written in ...
LLVM_ABI Expected< std::unique_ptr< ModuleSummaryIndex > > getModuleSummaryIndex(MemoryBufferRef Buffer)
Parse the specified bitcode buffer, returning the module summary index.
LLVM_ABI void updateIndexWPDForExports(ModuleSummaryIndex &Summary, function_ref< bool(StringRef, ValueInfo)> isExported, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap, DenseSet< StringRef > *ExternallyVisibleSymbolNamesPtr=nullptr)
Call after cross-module importing to update the recorded single impl devirt target names for any loca...
static cl::opt< std::string > ClWriteSummary("wholeprogramdevirt-write-summary", cl::desc("Write summary to given bitcode or YAML file after running pass. " "Output file format is deduced from extension: *.bc means writing " "bitcode, otherwise YAML"), cl::Hidden)
LLVM_ABI void updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO)
LLVM_ABI void getVisibleToRegularObjVtableGUIDs(ModuleSummaryIndex &Index, DenseSet< GlobalValue::GUID > &VisibleToRegularObjSymbols, function_ref< bool(StringRef)> IsVisibleToRegularObj)
Based on typeID string, get all associated vtable GUIDS that are visible to regular objects.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void findDevirtualizableCallsForTypeCheckedLoad(SmallVectorImpl< DevirtCallSite > &DevirtCalls, SmallVectorImpl< Instruction * > &LoadedPtrs, SmallVectorImpl< Instruction * > &Preds, bool &HasNonCallUses, const CallInst *CI, DominatorTree &DT)
Given a call to the intrinsic @llvm.type.checked.load, find all devirtualizable call sites based on t...
LLVM_ABI CallBase & versionCallSite(CallBase &CB, Value *Callee, MDNode *BranchWeights)
Predicate and clone the given call site.
LLVM_ABI bool AreStatisticsEnabled()
Check if statistics are enabled.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI void setExplicitlyUnknownFunctionEntryCount(Function &F, StringRef PassName)
Analogous to setExplicitlyUnknownBranchWeights, but for functions and their entry counts.
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
static cl::list< std::string > SkipFunctionNames("wholeprogramdevirt-skip", cl::desc("Prevent function(s) from being devirtualized"), cl::Hidden, cl::CommaSeparated)
Provide way to prevent certain function from being devirtualized.
static cl::opt< PassSummaryAction > ClSummaryAction("wholeprogramdevirt-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
static cl::opt< bool > ClDevirtualizeSpeculatively("devirtualize-speculatively", cl::desc("Enable speculative devirtualization optimization"), cl::init(false))
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
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