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;
777 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
779 PatternList FunctionsToSkip;
782 ModuleSummaryIndex &ExportSummary,
783 std::set<GlobalValue::GUID> &ExportedGUIDs,
784 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap)
785 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
786 LocalWPDTargetsMap(LocalWPDTargetsMap) {
790 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
792 uint64_t ByteOffset);
795 VTableSlotSummary &SlotSummary,
796 VTableSlotInfo &SlotInfo,
797 WholeProgramDevirtResolution *Res,
798 std::set<ValueInfo> &DevirtTargets);
812 std::optional<ModuleSummaryIndex> Index;
816 "ExportSummary is expected to be empty in non-LTO mode");
819 ExportSummary = Index.has_value() ? &Index.value() :
nullptr;
840 if (
TypeID.ends_with(
".virtual"))
846 if (!
TypeID.consume_front(
"_ZTS"))
854 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
855 return IsVisibleToRegularObj(TypeInfo);
864 for (
auto *
Type : Types)
867 IsVisibleToRegularObj);
876 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
878 bool ValidateAllVtablesHaveTypeInfos,
895 !(ValidateAllVtablesHaveTypeInfos &&
902 bool WholeProgramVisibilityEnabledInLTO) {
906 if (!PublicTypeTestFunc)
914 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
916 CI->replaceAllUsesWith(NewCI);
917 CI->eraseFromParent();
925 CI->replaceAllUsesWith(True);
926 CI->eraseFromParent();
937 for (
const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
940 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
953 for (
auto &
P : Index) {
956 if (DynamicExportSymbols.
count(
P.first))
962 if (VisibleToRegularObjSymbols.
count(
P.first))
964 for (
auto &S :
P.second.getSummaryList()) {
976 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
977 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap).run();
983 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
984 for (
auto &
T : LocalWPDTargetsMap) {
987 assert(VI.getSummaryList().size() == 1 &&
988 "Devirt of local target has more than one copy");
989 auto &S = VI.getSummaryList()[0];
990 if (!IsExported(S->modulePath(), VI))
994 for (
auto &SlotSummary :
T.second) {
995 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
997 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
998 assert(WPDRes != TIdSum->WPDRes.end());
1000 WPDRes->second.SingleImplName,
1001 Summary.getModuleHash(S->modulePath()));
1011 const auto &ModPaths = Summary->modulePaths();
1016 "combined summary should contain Regular LTO module");
1021 bool DevirtSpeculatively) {
1022 std::unique_ptr<ModuleSummaryIndex>
Summary =
1023 std::make_unique<ModuleSummaryIndex>(
false);
1028 ExitOnError ExitOnErr(
"-wholeprogramdevirt-read-summary: " +
ClReadSummary +
1030 auto ReadSummaryFile =
1032 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1034 Summary = std::move(*SummaryOrErr);
1039 yaml::Input
In(ReadSummaryFile->getBuffer());
1046 DevirtModule(M,
MAM,
1051 DevirtSpeculatively)
1055 ExitOnError ExitOnErr(
1065 yaml::Output Out(OS);
1073void DevirtModule::buildTypeIdentifierMap(
1074 std::vector<VTableBits> &Bits,
1075 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1076 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1077 Bits.reserve(
M.global_size());
1079 for (GlobalVariable &GV :
M.globals()) {
1087 Bits.emplace_back();
1088 Bits.back().GV = &GV;
1089 Bits.back().ObjectSize =
1091 BitsPtr = &
Bits.back();
1094 for (MDNode *
Type : Types) {
1107bool DevirtModule::tryFindVirtualCallTargets(
1108 std::vector<VirtualCallTarget> &TargetsForSlot,
1109 const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset,
1110 ModuleSummaryIndex *ExportSummary) {
1112 if (!TM.Bits->GV->isConstant())
1117 if (!DevirtSpeculatively && TM.Bits->GV->getVCallVisibility() ==
1129 if (FunctionsToSkip.match(Fn->
getName()))
1134 if (Fn->
getName() ==
"__cxa_pure_virtual")
1152 TargetsForSlot.push_back({GV, &TM});
1156 return !TargetsForSlot.empty();
1159bool DevirtIndex::tryFindVirtualCallTargets(
1160 std::vector<ValueInfo> &TargetsForSlot,
1162 for (
const TypeIdOffsetVtableInfo &
P : TIdInfo) {
1173 if (
P.VTableVI.hasLocal() &&
P.VTableVI.getSummaryList().size() > 1)
1175 const GlobalVarSummary *
VS =
nullptr;
1176 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1178 if (!CurVS->vTableFuncs().empty() ||
1201 for (
auto VTP :
VS->vTableFuncs()) {
1202 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1208 TargetsForSlot.push_back(VTP.FuncVI);
1213 return !TargetsForSlot.empty();
1216void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1217 Constant *TheFn,
bool &IsExported) {
1223 for (
auto &&VCallSite : CSInfo.CallSites) {
1224 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1232 VCallSite.emitRemark(
"single-impl",
1235 auto &CB = VCallSite.CB;
1248 MDBuilder(
M.getContext()).createUnlikelyBranchWeights());
1249 Builder.SetInsertPoint(ThenTerm);
1252 auto *CallTrap = Builder.CreateCall(TrapFn);
1261 MDNode *Weights = MDBuilder(
M.getContext()).createLikelyBranchWeights();
1270 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1271 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1293 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1298 if (VCallSite.NumUnsafeUses)
1299 --*VCallSite.NumUnsafeUses;
1301 if (CSInfo.isExported())
1303 CSInfo.markDevirt();
1305 Apply(SlotInfo.CSInfo);
1306 for (
auto &
P : SlotInfo.ConstCSInfo)
1312 if (Callee.getSummaryList().empty())
1319 bool IsExported =
false;
1320 auto &S = Callee.getSummaryList()[0];
1323 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1324 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1325 FS->addCall({Callee, CI});
1326 IsExported |= S->modulePath() != FS->modulePath();
1328 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1329 FS->addCall({Callee, CI});
1330 IsExported |= S->modulePath() != FS->modulePath();
1333 AddCalls(SlotInfo.CSInfo);
1334 for (
auto &
P : SlotInfo.ConstCSInfo)
1339bool DevirtModule::trySingleImplDevirt(
1340 ModuleSummaryIndex *ExportSummary,
1342 WholeProgramDevirtResolution *Res) {
1345 auto *TheFn = TargetsForSlot[0].Fn;
1346 for (
auto &&Target : TargetsForSlot)
1352 TargetsForSlot[0].WasDevirt =
true;
1354 bool IsExported =
false;
1355 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1362 if (TheFn->hasLocalLinkage()) {
1363 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1368 if (Comdat *
C = TheFn->getComdat()) {
1369 if (
C->getName() == TheFn->
getName()) {
1370 Comdat *NewC =
M.getOrInsertComdat(NewName);
1372 for (GlobalObject &GO :
M.global_objects())
1373 if (GO.getComdat() ==
C)
1382 if (ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFn->getGUID()))
1394 VTableSlotSummary &SlotSummary,
1395 VTableSlotInfo &SlotInfo,
1396 WholeProgramDevirtResolution *Res,
1397 std::set<ValueInfo> &DevirtTargets) {
1400 auto TheFn = TargetsForSlot[0];
1401 for (
auto &&Target : TargetsForSlot)
1402 if (TheFn != Target)
1406 auto Size = TheFn.getSummaryList().size();
1412 if (FunctionsToSkip.match(TheFn.name()))
1417 if (TheFn.hasLocal() &&
Size > 1)
1422 DevirtTargets.insert(TheFn);
1424 auto &S = TheFn.getSummaryList()[0];
1425 bool IsExported =
addCalls(SlotInfo, TheFn);
1427 ExportedGUIDs.insert(TheFn.getGUID());
1438 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1440 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1454void DevirtModule::tryICallBranchFunnel(
1456 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1457 Triple
T(
M.getTargetTriple());
1464 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1466 for (
auto &
P : SlotInfo.ConstCSInfo)
1467 if (!
P.second.AllCallSitesDevirted) {
1468 HasNonDevirt =
true;
1486 for (
auto &
T : TargetsForSlot) {
1487 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1496 M.getDataLayout().getProgramAddressSpace(),
1497 getGlobalName(Slot, {},
"branch_funnel"), &
M);
1501 M.getDataLayout().getProgramAddressSpace(),
1502 "branch_funnel", &M);
1504 JT->addParamAttr(0, Attribute::Nest);
1506 std::vector<Value *> JTArgs;
1507 JTArgs.push_back(
JT->arg_begin());
1508 for (
auto &
T : TargetsForSlot) {
1509 JTArgs.push_back(getMemberAddr(
T.TM));
1510 JTArgs.push_back(
T.Fn);
1515 &M, llvm::Intrinsic::icall_branch_funnel, {});
1521 bool IsExported =
false;
1522 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1526 if (!
JT->getEntryCount().has_value()) {
1532void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1533 Function &JT,
bool &IsExported) {
1534 DenseMap<Function *, double> FunctionEntryCounts;
1536 if (CSInfo.isExported())
1538 if (CSInfo.AllCallSitesDevirted)
1541 std::map<CallBase *, CallBase *> CallBases;
1542 for (
auto &&VCallSite : CSInfo.CallSites) {
1543 CallBase &CB = VCallSite.CB;
1545 if (CallBases.find(&CB) != CallBases.end()) {
1562 VCallSite.emitRemark(
"branch-funnel",
JT.getName(), OREGetter);
1566 std::vector<Type *> NewArgs;
1567 NewArgs.push_back(Int8PtrTy);
1569 FunctionType *NewFT =
1573 std::vector<Value *>
Args;
1574 Args.push_back(VCallSite.VTable);
1577 CallBase *NewCS =
nullptr;
1583 auto EC = BFI.getBlockFreq(&
F.getEntryBlock());
1584 auto CC =
F.getEntryCount(
true);
1585 double CallCount = 0.0;
1586 if (
EC.getFrequency() != 0 && CC && CC->getCount() != 0) {
1588 static_cast<double>(
1589 BFI.getBlockFreq(CB.
getParent()).getFrequency()) /
1591 CallCount = CallFreq * CC->getCount();
1593 FunctionEntryCounts[&
JT] += CallCount;
1596 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1604 std::vector<AttributeSet> NewArgAttrs;
1607 M.getContext(), Attribute::Nest)}));
1608 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1609 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1611 AttributeList::get(
M.getContext(),
Attrs.getFnAttrs(),
1612 Attrs.getRetAttrs(), NewArgAttrs));
1614 CallBases[&CB] = NewCS;
1617 if (VCallSite.NumUnsafeUses)
1618 --*VCallSite.NumUnsafeUses;
1625 for (
auto &[Old, New] : CallBases) {
1626 Old->replaceAllUsesWith(New);
1627 Old->eraseFromParent();
1630 Apply(SlotInfo.CSInfo);
1631 for (
auto &
P : SlotInfo.ConstCSInfo)
1633 for (
auto &[
F,
C] : FunctionEntryCounts) {
1634 assert(!
F->getEntryCount(
true) &&
1635 "Unexpected entry count for funnel that was freshly synthesized");
1636 F->setEntryCount(
static_cast<uint64_t
>(std::round(
C)));
1640bool DevirtModule::tryEvaluateFunctionsWithArgs(
1642 ArrayRef<uint64_t> Args) {
1656 Evaluator Eval(
M.getDataLayout(),
nullptr);
1660 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1665 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1669 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1677void DevirtModule::applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1678 uint64_t TheRetVal) {
1679 for (
auto Call : CSInfo.CallSites) {
1683 Call.replaceAndErase(
1684 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1687 CSInfo.markDevirt();
1690bool DevirtModule::tryUniformRetValOpt(
1692 WholeProgramDevirtResolution::ByArg *Res) {
1695 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1697 if (
Target.RetVal != TheRetVal)
1700 if (CSInfo.isExported()) {
1702 Res->
Info = TheRetVal;
1705 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1707 for (
auto &&Target : TargetsForSlot)
1712std::string DevirtModule::getGlobalName(VTableSlot Slot,
1713 ArrayRef<uint64_t> Args,
1715 std::string FullName =
"__typeid_";
1716 raw_string_ostream OS(FullName);
1717 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1718 for (uint64_t Arg : Args)
1724bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1725 Triple
T(
M.getTargetTriple());
1729void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1730 StringRef Name, Constant *
C) {
1732 getGlobalName(Slot, Args, Name),
C, &M);
1736void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1737 StringRef Name, uint32_t Const,
1738 uint32_t &Storage) {
1739 if (shouldExportConstantsAsAbsoluteSymbols()) {
1749Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1751 GlobalVariable *GV =
1752 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1757Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1758 StringRef Name, IntegerType *IntTy,
1760 if (!shouldExportConstantsAsAbsoluteSymbols())
1761 return ConstantInt::get(IntTy, Storage);
1763 Constant *
C = importGlobal(Slot, Args, Name);
1769 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1772 auto SetAbsRange = [&](uint64_t Min, uint64_t
Max) {
1780 SetAbsRange(~0ull, ~0ull);
1782 SetAbsRange(0, 1ull << AbsWidth);
1786void DevirtModule::applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1788 Constant *UniqueMemberAddr) {
1789 for (
auto &&
Call : CSInfo.CallSites) {
1795 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->
getType()));
1798 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1801 CSInfo.markDevirt();
1806 ConstantInt::get(Int64Ty,
M->Offset));
1809bool DevirtModule::tryUniqueRetValOpt(
1811 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1812 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1814 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1817 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1820 UniqueMember =
Target.TM;
1828 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1829 if (CSInfo.isExported()) {
1833 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1837 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1842 for (
auto &&Target : TargetsForSlot)
1849 if (tryUniqueRetValOptFor(
true))
1851 if (tryUniqueRetValOptFor(
false))
1857void DevirtModule::applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
1858 Constant *Byte, Constant *Bit) {
1859 for (
auto Call : CSInfo.CallSites) {
1864 Value *Addr =
B.CreatePtrAdd(
Call.VTable, Byte);
1865 if (RetType->getBitWidth() == 1) {
1867 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1868 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1869 NumVirtConstProp1Bit++;
1870 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1871 OREGetter, IsBitSet);
1873 Value *Val =
B.CreateLoad(RetType, Addr);
1875 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1879 CSInfo.markDevirt();
1882bool DevirtModule::tryVirtualConstProp(
1884 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1895 unsigned BitWidth = RetType->getBitWidth();
1907 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1940 GlobalVariable *GV =
Target.TM->Bits->GV;
1941 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1943 if (TypeAlignment > TableAlignment)
1947 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1948 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1951 WholeProgramDevirtResolution::ByArg *ResByArg =
nullptr;
1953 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1955 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1958 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1959 ResByArg, Slot, CSByConstantArg.first))
1967 uint64_t AllocBefore =
1969 uint64_t AllocAfter =
1974 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1975 for (
auto &&Target : TargetsForSlot) {
1976 TotalPaddingBefore += std::max<int64_t>(
1977 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1978 TotalPaddingAfter += std::max<int64_t>(
1979 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1984 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1991 if (TotalPaddingBefore <= TotalPaddingAfter)
2007 for (
auto &&Target : TargetsForSlot)
2011 if (CSByConstantArg.second.isExported()) {
2013 exportConstant(Slot, CSByConstantArg.first,
"byte", OffsetByte,
2015 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
2021 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
2022 applyVirtualConstProp(CSByConstantArg.second,
2023 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
2029 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
2034 Align Alignment =
M.getDataLayout().getValueOrABITypeAlignment(
2035 B.GV->getAlign(),
B.GV->getValueType());
2036 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
2039 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
2046 B.GV->getInitializer(),
2049 new GlobalVariable(M, NewInit->getType(),
B.GV->isConstant(),
2051 NewGV->setSection(
B.GV->getSection());
2052 NewGV->setComdat(
B.GV->getComdat());
2053 NewGV->setAlignment(
B.GV->getAlign());
2057 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
2062 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2064 NewInit->getType(), NewGV,
2066 ConstantInt::get(Int32Ty, 1)}),
2068 Alias->setVisibility(
B.GV->getVisibility());
2069 Alias->takeName(
B.GV);
2071 B.GV->replaceAllUsesWith(Alias);
2072 B.GV->eraseFromParent();
2075bool DevirtModule::areRemarksEnabled() {
2076 const auto &FL =
M.getFunctionList();
2077 for (
const Function &Fn : FL) {
2081 return DI.isEnabled();
2086void DevirtModule::scanTypeTestUsers(
2087 Function *TypeTestFunc,
2088 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2102 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2108 if (!Assumes.
empty()) {
2109 Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();
2110 for (DevirtCallSite
Call : DevirtCalls)
2111 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
nullptr);
2114 auto RemoveTypeTestAssumes = [&]() {
2116 for (
auto *Assume : Assumes)
2117 Assume->eraseFromParent();
2120 if (CI->use_empty())
2121 CI->eraseFromParent();
2136 if (!TypeIdMap.count(TypeId))
2137 RemoveTypeTestAssumes();
2149 const TypeIdSummary *TidSummary =
2152 RemoveTypeTestAssumes();
2161void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {
2170 Value *Ptr = CI->getArgOperand(0);
2172 Value *TypeIdValue = CI->getArgOperand(2);
2178 bool HasNonCallUses =
false;
2179 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2181 HasNonCallUses, CI, DT);
2190 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2192 Value *LoadedValue =
nullptr;
2194 Intrinsic::type_checked_load_relative) {
2196 &M, Intrinsic::load_relative, {
Int32Ty});
2197 LoadedValue = LoadB.CreateCall(LoadRelFunc, {Ptr,
Offset});
2200 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2203 for (Instruction *LoadedPtr : LoadedPtrs) {
2204 LoadedPtr->replaceAllUsesWith(LoadedValue);
2205 LoadedPtr->eraseFromParent();
2209 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2210 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {Ptr, TypeIdValue});
2212 for (Instruction *Pred : Preds) {
2213 Pred->replaceAllUsesWith(TypeTestCall);
2214 Pred->eraseFromParent();
2221 if (!CI->use_empty()) {
2224 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2225 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2230 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2231 NumUnsafeUses = DevirtCalls.
size();
2238 for (DevirtCallSite
Call : DevirtCalls) {
2239 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
2243 CI->eraseFromParent();
2247void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2251 const TypeIdSummary *TidSummary =
2255 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2256 if (ResI == TidSummary->
WPDRes.end())
2258 const WholeProgramDevirtResolution &Res = ResI->second;
2270 bool IsExported =
false;
2271 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2275 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2276 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2279 auto &ResByArg =
I->second;
2286 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2290 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2291 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2296 Constant *
Byte = importConstant(Slot, CSByConstantArg.first,
"byte",
2298 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2300 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2312 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2315 bool IsExported =
false;
2316 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2321void DevirtModule::removeRedundantTypeTests() {
2323 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2324 if (
U.second == 0) {
2325 U.first->replaceAllUsesWith(True);
2326 U.first->eraseFromParent();
2332DevirtModule::lookUpFunctionValueInfo(Function *TheFn,
2333 ModuleSummaryIndex *ExportSummary) {
2334 assert((ExportSummary !=
nullptr) &&
2335 "Caller guarantees ExportSummary is not nullptr");
2337 const auto TheFnGUID = TheFn->
getGUID();
2338 const auto TheFnGUIDWithExportedName =
2341 ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFnGUID);
2350 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2351 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2356bool DevirtModule::mustBeUnreachableFunction(
2357 Function *
const F, ModuleSummaryIndex *ExportSummary) {
2361 if (!
F->isDeclaration()) {
2367 return ExportSummary &&
2369 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2372bool DevirtModule::run() {
2381 Function *PublicTypeTestFunc =
nullptr;
2384 if (DevirtSpeculatively)
2385 PublicTypeTestFunc =
2392 &M, Intrinsic::type_checked_load_relative);
2399 if (!ExportSummary &&
2400 (((!PublicTypeTestFunc || PublicTypeTestFunc->
use_empty()) &&
2401 (!TypeTestFunc || TypeTestFunc->
use_empty())) ||
2402 !AssumeFunc || AssumeFunc->
use_empty()) &&
2403 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2404 (!TypeCheckedLoadRelativeFunc ||
2405 TypeCheckedLoadRelativeFunc->
use_empty()))
2409 std::vector<VTableBits>
Bits;
2410 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2411 buildTypeIdentifierMap(Bits, TypeIdMap);
2413 if (PublicTypeTestFunc && AssumeFunc)
2414 scanTypeTestUsers(PublicTypeTestFunc, TypeIdMap);
2416 if (TypeTestFunc && AssumeFunc)
2417 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2419 if (TypeCheckedLoadFunc)
2420 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2422 if (TypeCheckedLoadRelativeFunc)
2423 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2425 if (ImportSummary) {
2426 for (
auto &S : CallSlots)
2427 importResolution(S.first, S.second);
2429 removeRedundantTypeTests();
2434 for (GlobalVariable &GV :
M.globals())
2442 if (TypeIdMap.
empty())
2446 if (ExportSummary) {
2447 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2448 for (
auto &
P : TypeIdMap) {
2451 TypeId->getString())]
2455 for (
auto &
P : *ExportSummary) {
2456 for (
auto &S :
P.second.getSummaryList()) {
2461 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2462 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2463 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2466 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2467 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2468 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2471 for (
const FunctionSummary::ConstVCall &VC :
2472 FS->type_test_assume_const_vcalls()) {
2473 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2474 CallSlots[{MD,
VC.VFunc.Offset}]
2475 .ConstCSInfo[
VC.Args]
2476 .addSummaryTypeTestAssumeUser(FS);
2479 for (
const FunctionSummary::ConstVCall &VC :
2480 FS->type_checked_load_const_vcalls()) {
2481 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2482 CallSlots[{MD,
VC.VFunc.Offset}]
2483 .ConstCSInfo[
VC.Args]
2484 .addSummaryTypeCheckedLoadUser(FS);
2492 bool DidVirtualConstProp =
false;
2493 std::map<std::string, GlobalValue *> DevirtTargets;
2494 for (
auto &S : CallSlots) {
2498 std::vector<VirtualCallTarget> TargetsForSlot;
2499 WholeProgramDevirtResolution *Res =
nullptr;
2500 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2502 TypeMemberInfos.size())
2509 Res = &ExportSummary
2510 ->getOrInsertTypeIdSummary(
2512 .WPDRes[S.first.ByteOffset];
2513 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2514 S.first.ByteOffset, ExportSummary)) {
2515 bool SingleImplDevirt =
2516 trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res);
2520 if (!SingleImplDevirt && !DevirtSpeculatively) {
2521 DidVirtualConstProp |=
2522 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2524 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2529 for (
const auto &
T : TargetsForSlot)
2531 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2541 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2542 if (!CSI.AllCallSitesDevirted)
2543 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2544 FS->addTypeTest(GUID);
2546 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2547 for (
auto &CCS : S.second.ConstCSInfo)
2548 AddTypeTestsForTypeCheckedLoads(CCS.second);
2552 if (RemarksEnabled) {
2554 for (
const auto &DT : DevirtTargets) {
2555 GlobalValue *GV = DT.second;
2564 using namespace ore;
2565 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE,
"Devirtualized",
F)
2566 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2570 NumDevirtTargets += DevirtTargets.size();
2572 removeRedundantTypeTests();
2576 if (DidVirtualConstProp)
2583 for (GlobalVariable &GV :
M.globals())
2586 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2587 CI->eraseFromParent();
2592void DevirtIndex::run() {
2593 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2598 assert(!ExportSummary.withInternalizeAndPromote() &&
2599 "Expect index-based WPD to run before internalization and promotion");
2601 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2602 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2611 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2615 for (
auto &
P : ExportSummary) {
2616 for (
auto &S :
P.second.getSummaryList()) {
2621 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2622 for (StringRef Name : NameByGUID[VF.GUID]) {
2623 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2626 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2627 for (StringRef Name : NameByGUID[VF.GUID]) {
2628 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2631 for (
const FunctionSummary::ConstVCall &VC :
2632 FS->type_test_assume_const_vcalls()) {
2633 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2634 CallSlots[{
Name,
VC.VFunc.Offset}]
2635 .ConstCSInfo[
VC.Args]
2636 .addSummaryTypeTestAssumeUser(FS);
2639 for (
const FunctionSummary::ConstVCall &VC :
2640 FS->type_checked_load_const_vcalls()) {
2641 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2642 CallSlots[{
Name,
VC.VFunc.Offset}]
2643 .ConstCSInfo[
VC.Args]
2644 .addSummaryTypeCheckedLoadUser(FS);
2650 std::set<ValueInfo> DevirtTargets;
2652 for (
auto &S : CallSlots) {
2656 std::vector<ValueInfo> TargetsForSlot;
2657 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2661 WholeProgramDevirtResolution *Res =
2662 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2663 ->WPDRes[S.first.ByteOffset];
2664 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2665 S.first.ByteOffset)) {
2667 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2676 for (
const auto &DT : DevirtTargets)
2677 errs() <<
"Devirtualized call to " << DT <<
"\n";
2679 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 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.
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...
Type * getReturnType() const
Returns the type of the ret val.
unsigned getInstructionCount() const
Returns the number of non-debug IR instructions in this function.
static LLVM_ABI Expected< GlobPattern > create(StringRef Pat, std::optional< size_t > MaxSubPatterns={})
static LLVM_ABI GlobalAlias * create(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, Constant *Aliasee, Module *Parent)
If a parent module is specified, the alias is automatically inserted into the end of the specified mo...
bool hasMetadata() const
Return true if this value has any metadata attached to it.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
LLVM_ABI VCallVisibility getVCallVisibility() const
LLVM_ABI bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
@ VCallVisibilityLinkageUnit
MDNode * getMetadata(unsigned KindID) const
Get the current metadata attachments for the given kind, if any.
LLVM_ABI void setVCallVisibilityMetadata(VCallVisibility Visibility)
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
static bool isLocalLinkage(LinkageTypes Linkage)
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
static bool isAvailableExternallyLinkage(LinkageTypes Linkage)
GUID getGUID() const
Return a 64-bit global unique ID constructed from global value name (i.e.
@ HiddenVisibility
The GV is hidden.
void setVisibility(VisibilityTypes V)
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
@ ExternalLinkage
Externally visible function.
Type * getValueType() const
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
MaybeAlign getAlign() const
Returns the alignment of the given variable.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
bool doesNotAccessMemory() const
Whether this function accesses no memory.
Class to hold module path string table and global value map, and encapsulate methods for operating on...
const TypeIdSummary * getTypeIdSummary(StringRef TypeId) const
This returns either a pointer to the type id summary (if present in the summary map) or null (if not ...
ValueInfo getValueInfo(const GlobalValueSummaryMapTy::value_type &R) const
Return a ValueInfo for the index value_type (convenient when iterating index).
const ModuleHash & getModuleHash(const StringRef ModPath) const
Get the module SHA1 hash recorded for the given module path.
static constexpr const char * getRegularLTOModuleName()
bool partiallySplitLTOUnits() const
static std::string getGlobalNameForLocal(StringRef Name, ModuleHash ModHash)
Convenience method for creating a promoted global name for the given value name of a local,...
A Module instance is used to store all the information related to an LLVM module.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
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
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.
static cl::opt< std::string > ClWriteSummary("wholeprogramdevirt-write-summary", cl::desc("Write summary to given bitcode or YAML file after running pass. " "Output file format is deduced from extension: *.bc means writing " "bitcode, otherwise YAML"), cl::Hidden)
LLVM_ABI void updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO)
LLVM_ABI void getVisibleToRegularObjVtableGUIDs(ModuleSummaryIndex &Index, DenseSet< GlobalValue::GUID > &VisibleToRegularObjSymbols, function_ref< bool(StringRef)> IsVisibleToRegularObj)
Based on typeID string, get all associated vtable GUIDS that are visible to regular objects.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void findDevirtualizableCallsForTypeCheckedLoad(SmallVectorImpl< DevirtCallSite > &DevirtCalls, SmallVectorImpl< Instruction * > &LoadedPtrs, SmallVectorImpl< Instruction * > &Preds, bool &HasNonCallUses, const CallInst *CI, DominatorTree &DT)
Given a call to the intrinsic @llvm.type.checked.load, find all devirtualizable call sites based on t...
LLVM_ABI CallBase & versionCallSite(CallBase &CB, Value *Callee, MDNode *BranchWeights)
Predicate and clone the given call site.
LLVM_ABI bool AreStatisticsEnabled()
Check if statistics are enabled.
LLVM_ABI void updateIndexWPDForExports(ModuleSummaryIndex &Summary, function_ref< bool(StringRef, ValueInfo)> isExported, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap)
Call after cross-module importing to update the recorded single impl devirt target names for any loca...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI void setExplicitlyUnknownFunctionEntryCount(Function &F, StringRef PassName)
Analogous to setExplicitlyUnknownBranchWeights, but for functions and their entry counts.
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
static cl::list< std::string > SkipFunctionNames("wholeprogramdevirt-skip", cl::desc("Prevent function(s) from being devirtualized"), cl::Hidden, cl::CommaSeparated)
Provide way to prevent certain function from being devirtualized.
LLVM_ABI void runWholeProgramDevirtOnIndex(ModuleSummaryIndex &Summary, std::set< GlobalValue::GUID > &ExportedGUIDs, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap)
Perform index-based whole program devirtualization on the Summary index.
static cl::opt< PassSummaryAction > ClSummaryAction("wholeprogramdevirt-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
static cl::opt< bool > ClDevirtualizeSpeculatively("devirtualize-speculatively", cl::desc("Enable speculative devirtualization optimization"), cl::init(false))
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
cl::opt< bool > ProfcheckDisableMetadataFixes("profcheck-disable-metadata-fixes", cl::Hidden, cl::init(false), cl::desc("Disable metadata propagation fixes discovered through Issue #147390"))
LLVM_ABI Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
std::vector< TypeIdOffsetVtableInfo > TypeIdCompatibleVtableInfo
List of vtable definitions decorated by a particular type identifier, and their corresponding offsets...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
static cl::opt< bool > PrintSummaryDevirt("wholeprogramdevirt-print-index-based", cl::Hidden, cl::desc("Print index-based devirtualization messages"))
void consumeError(Error Err)
Consume a Error without doing anything.
void findDevirtualizableCallsForTypeTest(SmallVectorImpl< DevirtCallSite > &DevirtCalls, SmallVectorImpl< CallInst * > &Assumes, const CallInst *CI, DominatorTree &DT)
Given a call to the intrinsic @llvm.type.test, find all devirtualizable call sites based on the call ...
LLVM_ABI void updateVCallVisibilityInModule(Module &M, bool WholeProgramVisibilityEnabledInLTO, const DenseSet< GlobalValue::GUID > &DynamicExportSymbols, bool ValidateAllVtablesHaveTypeInfos, function_ref< bool(StringRef)> IsVisibleToRegularObj)
If whole program visibility asserted, then upgrade all public vcall visibility metadata on vtable def...
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
std::pair< Function *, Constant * > getFunctionAtVTableOffset(GlobalVariable *GV, uint64_t Offset, Module &M)
Given a vtable and a specified offset, returns the function and the trivial pointer at the specified ...
LLVM_ABI void updateVCallVisibilityInIndex(ModuleSummaryIndex &Index, bool WholeProgramVisibilityEnabledInLTO, const DenseSet< GlobalValue::GUID > &DynamicExportSymbols, const DenseSet< GlobalValue::GUID > &VisibleToRegularObjSymbols)
If whole program visibility asserted, then upgrade all public vcall visibility metadata on vtable def...
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Class to accumulate and hold information about a callee.
static unsigned getHashValue(const VTableSlotSummary &I)
static bool isEqual(const VTableSlotSummary &LHS, const VTableSlotSummary &RHS)
static VTableSlotSummary getTombstoneKey()
static VTableSlotSummary getEmptyKey()
static VTableSlot getTombstoneKey()
static VTableSlot getEmptyKey()
static bool isEqual(const VTableSlot &LHS, const VTableSlot &RHS)
static unsigned getHashValue(const VTableSlot &I)
An information struct used to provide DenseMap with the various necessary components for a given valu...
The following data structures summarize type metadata information.
std::map< uint64_t, WholeProgramDevirtResolution > WPDRes
Mapping from byte offset to whole-program devirt resolution for that (typeid, byte offset) pair.
@ Unsat
Unsatisfiable type (i.e. no global has this type metadata)
enum llvm::TypeTestResolution::Kind TheKind
Struct that holds a reference to a particular GUID in a global value summary.
ArrayRef< std::unique_ptr< GlobalValueSummary > > getSummaryList() const
const ModuleSummaryIndex * ImportSummary
ModuleSummaryIndex * ExportSummary
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
@ UniformRetVal
Uniform return value optimization.
@ VirtualConstProp
Virtual constant propagation.
@ UniqueRetVal
Unique return value optimization.
uint64_t Info
Additional information for the resolution:
enum llvm::WholeProgramDevirtResolution::ByArg::Kind TheKind
enum llvm::WholeProgramDevirtResolution::Kind TheKind
std::map< std::vector< uint64_t >, ByArg > ResByArg
Resolutions for calls with all constant integer arguments (excluding the first argument,...
std::string SingleImplName
@ SingleImpl
Single implementation devirtualization.
@ BranchFunnel
When retpoline mitigation is enabled, use a branch funnel that is defined in the merged module.
LLVM_ABI VirtualCallTarget(GlobalValue *Fn, const TypeMemberInfo *TM)
const TypeMemberInfo * TM