125#define DEBUG_TYPE "wholeprogramdevirt"
127STATISTIC(NumDevirtTargets,
"Number of whole program devirtualization targets");
128STATISTIC(NumSingleImpl,
"Number of single implementation devirtualizations");
130STATISTIC(NumUniformRetVal,
"Number of uniform return value optimizations");
131STATISTIC(NumUniqueRetVal,
"Number of unique return value optimizations");
133 "Number of 1 bit virtual constant propagations");
134STATISTIC(NumVirtConstProp,
"Number of virtual constant propagations");
136 "Controls how many calls should be devirtualized.");
141 "wholeprogramdevirt-summary-action",
142 cl::desc(
"What to do with the summary when running this pass"),
145 "Import typeid resolutions from summary and globals"),
147 "Export typeid resolutions to summary and globals")),
151 "wholeprogramdevirt-read-summary",
153 "Read summary from given bitcode or YAML file before running pass"),
157 "wholeprogramdevirt-write-summary",
158 cl::desc(
"Write summary to given bitcode or YAML file after running pass. "
159 "Output file format is deduced from extension: *.bc means writing "
160 "bitcode, otherwise YAML"),
166 "devirtualize-speculatively",
167 cl::desc(
"Enable speculative devirtualization optimization"),
173 cl::desc(
"Maximum number of call targets per "
174 "call site to enable branch funnels"));
178 cl::desc(
"Print index-based devirtualization messages"));
186 cl::desc(
"Enable whole program visibility"));
191 "disable-whole-program-visibility",
cl::Hidden,
192 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
197 cl::desc(
"Prevent function(s) from being devirtualized"),
220 "wholeprogramdevirt-keep-unreachable-function",
221 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
232 cl::desc(
"Type of checking for incorrect devirtualizations"),
236 "Fallback to indirect when incorrect")));
240 std::vector<GlobPattern> Patterns;
241 template <
class T>
void init(
const T &StringList) {
242 for (
const auto &S : StringList)
244 Patterns.push_back(std::move(*Pat));
246 bool match(StringRef S) {
247 for (
const GlobPattern &
P : Patterns)
260 bool IsAfter, uint64_t
Size) {
262 uint64_t MinByte = 0;
265 MinByte = std::max(MinByte,
Target.minAfterBytes());
267 MinByte = std::max(MinByte,
Target.minBeforeBytes());
290 std::vector<ArrayRef<uint8_t>> Used;
293 :
Target.TM->Bits->Before.BytesUsed;
294 uint64_t
Offset = IsAfter ? MinByte -
Target.minAfterBytes()
295 : MinByte -
Target.minBeforeBytes();
305 for (
unsigned I = 0;; ++
I) {
307 for (
auto &&
B : Used)
310 if (BitsUsed != 0xff)
316 for (
unsigned I = 0;; ++
I) {
317 for (
auto &&
B : Used) {
319 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
335 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
337 OffsetByte = -(AllocBefore / 8 + 1);
339 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
340 OffsetBit = AllocBefore % 8;
344 Target.setBeforeBit(AllocBefore);
352 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
354 OffsetByte = AllocAfter / 8;
356 OffsetByte = (AllocAfter + 7) / 8;
357 OffsetBit = AllocAfter % 8;
361 Target.setAfterBit(AllocAfter);
390 const VTableSlot &RHS) {
391 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
402 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
426 if (!Summary->isLive())
429 if (!FS->fflags().MustBeUnreachable)
444struct VirtualCallSite {
451 unsigned *NumUnsafeUses =
nullptr;
454 emitRemark(
const StringRef OptName,
const StringRef TargetName,
455 function_ref<OptimizationRemarkEmitter &(
Function &)> OREGetter) {
461 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE, OptName, DLoc,
Block)
462 <<
NV(
"Optimization", OptName)
463 <<
": devirtualized a call to "
464 <<
NV(
"FunctionName", TargetName));
467 void replaceAndErase(
468 const StringRef OptName,
const StringRef TargetName,
bool RemarksEnabled,
469 function_ref<OptimizationRemarkEmitter &(
Function &)> OREGetter,
476 II->getUnwindDest()->removePredecessor(
II->getParent());
493 std::vector<VirtualCallSite> CallSites;
502 bool AllCallSitesDevirted =
true;
511 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
515 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
517 bool isExported()
const {
518 return !SummaryTypeCheckedLoadUsers.empty() ||
519 !SummaryTypeTestAssumeUsers.empty();
522 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
523 SummaryTypeCheckedLoadUsers.push_back(FS);
524 AllCallSitesDevirted =
false;
527 void addSummaryTypeTestAssumeUser(FunctionSummary *FS) {
528 SummaryTypeTestAssumeUsers.push_back(FS);
529 AllCallSitesDevirted =
false;
532 void markDevirt() { AllCallSitesDevirted =
true; }
536struct VTableSlotInfo {
543 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
545 void addCallSite(
Value *VTable, CallBase &CB,
unsigned *NumUnsafeUses);
551CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) {
552 std::vector<uint64_t>
Args;
554 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
558 if (!CI || CI->getBitWidth() > 64)
560 Args.push_back(CI->getZExtValue());
562 return ConstCSInfo[
Args];
565void VTableSlotInfo::addCallSite(
Value *VTable, CallBase &CB,
566 unsigned *NumUnsafeUses) {
567 auto &CSI = findCallSiteInfo(CB);
568 CSI.AllCallSitesDevirted =
false;
569 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
577 ModuleSummaryIndex *
const ExportSummary;
578 const ModuleSummaryIndex *
const ImportSummary;
580 IntegerType *
const Int8Ty;
582 IntegerType *
const Int32Ty;
583 IntegerType *
const Int64Ty;
590 const bool RemarksEnabled;
591 std::function<OptimizationRemarkEmitter &(
Function &)> OREGetter;
592 MapVector<VTableSlot, VTableSlotInfo> CallSlots;
597 SmallPtrSet<CallBase *, 8> OptimizedCalls;
611 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
612 PatternList FunctionsToSkip;
614 const bool DevirtSpeculatively;
616 ModuleSummaryIndex *ExportSummary,
617 const ModuleSummaryIndex *ImportSummary,
618 bool DevirtSpeculatively)
621 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
628 RemarksEnabled(areRemarksEnabled()),
629 OREGetter([&](
Function &
F) -> OptimizationRemarkEmitter & {
632 DevirtSpeculatively(DevirtSpeculatively) {
633 assert(!(ExportSummary && ImportSummary));
637 bool areRemarksEnabled();
640 scanTypeTestUsers(
Function *TypeTestFunc,
641 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
642 void scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc);
644 void buildTypeIdentifierMap(
645 std::vector<VTableBits> &Bits,
646 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
649 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
650 const std::set<TypeMemberInfo> &TypeMemberInfos,
652 ModuleSummaryIndex *ExportSummary);
654 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
656 bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
658 VTableSlotInfo &SlotInfo,
659 WholeProgramDevirtResolution *Res);
661 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Function &JT,
664 VTableSlotInfo &SlotInfo,
665 WholeProgramDevirtResolution *Res, VTableSlot Slot);
667 bool tryEvaluateFunctionsWithArgs(
669 ArrayRef<uint64_t> Args);
671 void applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
675 WholeProgramDevirtResolution::ByArg *Res);
679 std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
682 bool shouldExportConstantsAsAbsoluteSymbols();
687 void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
689 void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
690 uint32_t Const, uint32_t &Storage);
694 Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
696 Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
697 StringRef Name, IntegerType *IntTy,
700 Constant *getMemberAddr(
const TypeMemberInfo *M);
702 void applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
bool IsOne,
703 Constant *UniqueMemberAddr);
704 bool tryUniqueRetValOpt(
unsigned BitWidth,
707 WholeProgramDevirtResolution::ByArg *Res,
708 VTableSlot Slot, ArrayRef<uint64_t> Args);
710 void applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
711 Constant *Byte, Constant *Bit);
713 VTableSlotInfo &SlotInfo,
714 WholeProgramDevirtResolution *Res, VTableSlot Slot);
716 void rebuildGlobal(VTableBits &
B);
719 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
723 void removeRedundantTypeTests();
730 static ValueInfo lookUpFunctionValueInfo(
Function *TheFn,
731 ModuleSummaryIndex *ExportSummary);
742 ModuleSummaryIndex *ExportSummary);
747 bool DevirtSpeculatively);
751 ModuleSummaryIndex &ExportSummary;
754 std::set<GlobalValue::GUID> &ExportedGUIDs;
758 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
763 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr;
765 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
767 PatternList FunctionsToSkip;
770 ModuleSummaryIndex &ExportSummary,
771 std::set<GlobalValue::GUID> &ExportedGUIDs,
772 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
773 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr)
774 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
775 LocalWPDTargetsMap(LocalWPDTargetsMap),
776 ExternallyVisibleSymbolNamesPtr(ExternallyVisibleSymbolNamesPtr) {
780 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
785 VTableSlotSummary &SlotSummary,
786 VTableSlotInfo &SlotInfo,
787 WholeProgramDevirtResolution *Res,
788 std::set<ValueInfo> &DevirtTargets);
802 std::optional<ModuleSummaryIndex> Index;
806 "ExportSummary is expected to be empty in non-LTO mode");
809 ExportSummary = Index.has_value() ? &Index.value() :
nullptr;
830 if (
TypeID.ends_with(
".virtual"))
836 if (!
TypeID.consume_front(
"_ZTS"))
844 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
845 return IsVisibleToRegularObj(TypeInfo);
854 for (
auto *
Type : Types)
857 IsVisibleToRegularObj);
866 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
868 bool ValidateAllVtablesHaveTypeInfos,
886 !(ValidateAllVtablesHaveTypeInfos &&
893 bool WholeProgramVisibilityEnabledInLTO) {
897 if (!PublicTypeTestFunc)
905 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
907 CI->replaceAllUsesWith(NewCI);
908 CI->eraseFromParent();
916 CI->replaceAllUsesWith(True);
917 CI->eraseFromParent();
928 for (
const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
931 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
944 for (
auto &
P : Index) {
947 if (DynamicExportSymbols.
count(
P.first))
953 if (VisibleToRegularObjSymbols.
count(
P.first))
955 for (
auto &S :
P.second.getSummaryList()) {
967 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
969 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap,
970 ExternallyVisibleSymbolNamesPtr)
977 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
979 for (
auto &
T : LocalWPDTargetsMap) {
982 assert(VI.getSummaryList().size() == 1 &&
983 "Devirt of local target has more than one copy");
984 auto &S = VI.getSummaryList()[0];
985 if (!IsExported(S->modulePath(), VI))
989 for (
auto &SlotSummary :
T.second) {
990 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
992 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
993 assert(WPDRes != TIdSum->WPDRes.end());
994 if (ExternallyVisibleSymbolNamesPtr)
995 ExternallyVisibleSymbolNamesPtr->
insert(WPDRes->second.SingleImplName);
997 WPDRes->second.SingleImplName,
998 Summary.getModuleHash(S->modulePath()));
1008 const auto &ModPaths = Summary->modulePaths();
1013 "combined summary should contain Regular LTO module");
1018 bool DevirtSpeculatively) {
1019 std::unique_ptr<ModuleSummaryIndex>
Summary =
1020 std::make_unique<ModuleSummaryIndex>(
false);
1025 ExitOnError ExitOnErr(
"-wholeprogramdevirt-read-summary: " +
ClReadSummary +
1027 auto ReadSummaryFile =
1029 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1031 Summary = std::move(*SummaryOrErr);
1036 yaml::Input
In(ReadSummaryFile->getBuffer());
1043 DevirtModule(M,
MAM,
1048 DevirtSpeculatively)
1052 ExitOnError ExitOnErr(
1062 yaml::Output
Out(OS);
1070void DevirtModule::buildTypeIdentifierMap(
1071 std::vector<VTableBits> &Bits,
1072 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1073 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1074 Bits.reserve(
M.global_size());
1076 for (GlobalVariable &GV :
M.globals()) {
1084 Bits.emplace_back();
1085 Bits.back().GV = &GV;
1086 Bits.back().ObjectSize =
1088 BitsPtr = &
Bits.back();
1091 for (MDNode *
Type : Types) {
1104bool DevirtModule::tryFindVirtualCallTargets(
1105 std::vector<VirtualCallTarget> &TargetsForSlot,
1106 const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset,
1107 ModuleSummaryIndex *ExportSummary) {
1109 if (!TM.Bits->GV->isConstant())
1114 if (!DevirtSpeculatively && TM.Bits->GV->getVCallVisibility() ==
1126 if (FunctionsToSkip.match(Fn->
getName()))
1131 if (Fn->
getName() ==
"__cxa_pure_virtual")
1150 if (!GA->isInterposable() && !GA->getAliaseeObject()->isInterposable())
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];
1322 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1323 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1324 FS->addCall({Callee, CI});
1325 IsExported |= S->modulePath() != FS->modulePath();
1327 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1328 FS->addCall({Callee, CI});
1329 IsExported |= S->modulePath() != FS->modulePath();
1332 AddCalls(SlotInfo.CSInfo);
1333 for (
auto &
P : SlotInfo.ConstCSInfo)
1338bool DevirtModule::trySingleImplDevirt(
1339 ModuleSummaryIndex *ExportSummary,
1341 WholeProgramDevirtResolution *Res) {
1344 auto *TheFn = TargetsForSlot[0].Fn;
1345 for (
auto &&Target : TargetsForSlot)
1351 TargetsForSlot[0].WasDevirt =
true;
1353 bool IsExported =
false;
1354 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1361 if (TheFn->hasLocalLinkage()) {
1362 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1367 if (Comdat *
C = TheFn->getComdat()) {
1368 if (
C->getName() == TheFn->
getName()) {
1369 Comdat *NewC =
M.getOrInsertComdat(NewName);
1371 for (GlobalObject &GO :
M.global_objects())
1372 if (GO.getComdat() ==
C)
1381 if (ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFn->getGUID()))
1393 VTableSlotSummary &SlotSummary,
1394 VTableSlotInfo &SlotInfo,
1395 WholeProgramDevirtResolution *Res,
1396 std::set<ValueInfo> &DevirtTargets) {
1399 auto TheFn = TargetsForSlot[0];
1400 for (
auto &&Target : TargetsForSlot)
1401 if (TheFn != Target)
1405 auto Size = TheFn.getSummaryList().size();
1411 if (FunctionsToSkip.match(TheFn.name()))
1416 if (TheFn.hasLocal() &&
Size > 1)
1421 DevirtTargets.insert(TheFn);
1423 auto &S = TheFn.getSummaryList()[0];
1424 bool IsExported =
addCalls(SlotInfo, TheFn);
1426 ExportedGUIDs.insert(TheFn.getGUID());
1436 if (ExternallyVisibleSymbolNamesPtr)
1437 ExternallyVisibleSymbolNamesPtr->insert(TheFn.name());
1439 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1441 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1455void DevirtModule::tryICallBranchFunnel(
1457 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1458 Triple
T(
M.getTargetTriple());
1465 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1467 for (
auto &
P : SlotInfo.ConstCSInfo)
1468 if (!
P.second.AllCallSitesDevirted) {
1469 HasNonDevirt =
true;
1487 for (
auto &
T : TargetsForSlot) {
1488 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1497 M.getDataLayout().getProgramAddressSpace(),
1498 getGlobalName(Slot, {},
"branch_funnel"), &
M);
1502 M.getDataLayout().getProgramAddressSpace(),
1503 "branch_funnel", &M);
1507 std::vector<Value *> JTArgs;
1509 for (
auto &
T : TargetsForSlot) {
1510 JTArgs.push_back(getMemberAddr(
T.TM));
1511 JTArgs.push_back(
T.Fn);
1516 &M, llvm::Intrinsic::icall_branch_funnel, {});
1522 bool IsExported =
false;
1523 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1533void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1535 DenseMap<Function *, double> FunctionEntryCounts;
1537 if (CSInfo.isExported())
1539 if (CSInfo.AllCallSitesDevirted)
1542 std::map<CallBase *, CallBase *> CallBases;
1543 for (
auto &&VCallSite : CSInfo.CallSites) {
1544 CallBase &CB = VCallSite.CB;
1546 if (CallBases.find(&CB) != CallBases.end()) {
1563 VCallSite.emitRemark(
"branch-funnel", JT.
getName(), OREGetter);
1567 std::vector<Type *> NewArgs;
1568 NewArgs.push_back(Int8PtrTy);
1570 FunctionType *NewFT =
1574 std::vector<Value *>
Args;
1575 Args.push_back(VCallSite.VTable);
1578 CallBase *NewCS =
nullptr;
1584 auto EC = BFI.getBlockFreq(&
F.getEntryBlock());
1585 auto CC =
F.getEntryCount();
1586 double CallCount = 0.0;
1587 if (
EC.getFrequency() != 0 && CC && *CC != 0) {
1589 static_cast<double>(
1590 BFI.getBlockFreq(CB.
getParent()).getFrequency()) /
1592 CallCount = CallFreq * *CC;
1594 FunctionEntryCounts[&JT] += CallCount;
1597 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1605 std::vector<AttributeSet> NewArgAttrs;
1608 M.getContext(), Attribute::Nest)}));
1609 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1610 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1612 AttributeList::get(
M.getContext(),
Attrs.getFnAttrs(),
1613 Attrs.getRetAttrs(), NewArgAttrs));
1615 CallBases[&CB] = NewCS;
1618 if (VCallSite.NumUnsafeUses)
1619 --*VCallSite.NumUnsafeUses;
1626 for (
auto &[Old, New] : CallBases) {
1627 Old->replaceAllUsesWith(New);
1628 Old->eraseFromParent();
1631 Apply(SlotInfo.CSInfo);
1632 for (
auto &
P : SlotInfo.ConstCSInfo)
1634 for (
auto &[
F,
C] : FunctionEntryCounts) {
1636 "Unexpected entry count for funnel that was freshly synthesized");
1637 F->setEntryCount(
static_cast<uint64_t>(std::round(
C)));
1641bool DevirtModule::tryEvaluateFunctionsWithArgs(
1643 ArrayRef<uint64_t> Args) {
1657 Evaluator Eval(
M.getDataLayout(),
nullptr);
1661 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1666 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1670 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1678void DevirtModule::applyUniformRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1680 for (
auto Call : CSInfo.CallSites) {
1684 Call.replaceAndErase(
1685 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1688 CSInfo.markDevirt();
1691bool DevirtModule::tryUniformRetValOpt(
1693 WholeProgramDevirtResolution::ByArg *Res) {
1696 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1698 if (
Target.RetVal != TheRetVal)
1701 if (CSInfo.isExported()) {
1703 Res->
Info = TheRetVal;
1706 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1708 for (
auto &&Target : TargetsForSlot)
1713std::string DevirtModule::getGlobalName(VTableSlot Slot,
1714 ArrayRef<uint64_t> Args,
1716 std::string FullName =
"__typeid_";
1717 raw_string_ostream OS(FullName);
1718 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1725bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1726 Triple
T(
M.getTargetTriple());
1730void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1731 StringRef Name, Constant *
C) {
1733 getGlobalName(Slot, Args, Name),
C, &M);
1737void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1738 StringRef Name, uint32_t Const,
1739 uint32_t &Storage) {
1740 if (shouldExportConstantsAsAbsoluteSymbols()) {
1750Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1752 GlobalVariable *GV =
1753 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1758Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1759 StringRef Name, IntegerType *IntTy,
1761 if (!shouldExportConstantsAsAbsoluteSymbols())
1762 return ConstantInt::get(IntTy, Storage);
1764 Constant *
C = importGlobal(Slot, Args, Name);
1770 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1780 if (AbsWidth ==
IntPtrTy->getBitWidth()) {
1784 SetAbsRange(0, 1ull << AbsWidth);
1789void DevirtModule::applyUniqueRetValOpt(
CallSiteInfo &CSInfo, StringRef FnName,
1791 Constant *UniqueMemberAddr) {
1792 for (
auto &&
Call : CSInfo.CallSites) {
1798 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->
getType()));
1801 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1804 CSInfo.markDevirt();
1809 ConstantInt::get(Int64Ty,
M->Offset));
1812bool DevirtModule::tryUniqueRetValOpt(
1814 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1815 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1817 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1820 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1823 UniqueMember =
Target.TM;
1831 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1832 if (CSInfo.isExported()) {
1836 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1840 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1845 for (
auto &&Target : TargetsForSlot)
1852 if (tryUniqueRetValOptFor(
true))
1854 if (tryUniqueRetValOptFor(
false))
1860void DevirtModule::applyVirtualConstProp(
CallSiteInfo &CSInfo, StringRef FnName,
1861 Constant *Byte, Constant *Bit) {
1862 for (
auto Call : CSInfo.CallSites) {
1867 Value *Addr =
B.CreatePtrAdd(
Call.VTable, Byte);
1868 if (RetType->getBitWidth() == 1) {
1870 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1871 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1872 NumVirtConstProp1Bit++;
1873 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1874 OREGetter, IsBitSet);
1876 Value *Val =
B.CreateLoad(RetType, Addr);
1878 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1882 CSInfo.markDevirt();
1885bool DevirtModule::tryVirtualConstProp(
1887 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1898 unsigned BitWidth = RetType->getBitWidth();
1910 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1943 GlobalVariable *GV =
Target.TM->Bits->GV;
1944 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1946 if (TypeAlignment > TableAlignment)
1950 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1951 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1954 WholeProgramDevirtResolution::ByArg *ResByArg =
nullptr;
1956 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1958 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1961 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1962 ResByArg, Slot, CSByConstantArg.first))
1977 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1978 for (
auto &&Target : TargetsForSlot) {
1979 TotalPaddingBefore += std::max<int64_t>(
1980 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1981 TotalPaddingAfter += std::max<int64_t>(
1982 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1987 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1994 if (TotalPaddingBefore <= TotalPaddingAfter)
2010 for (
auto &&Target : TargetsForSlot)
2014 if (CSByConstantArg.second.isExported()) {
2016 ResByArg->
Byte = OffsetByte;
2017 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
2023 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
2024 applyVirtualConstProp(CSByConstantArg.second,
2025 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
2031 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
2037 B.GV->getAlign(),
B.GV->getValueType());
2038 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
2041 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
2048 B.GV->getInitializer(),
2051 new GlobalVariable(M, NewInit->getType(),
B.GV->isConstant(),
2053 NewGV->setSection(
B.GV->getSection());
2054 NewGV->setComdat(
B.GV->getComdat());
2055 NewGV->setAlignment(
B.GV->getAlign());
2059 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
2064 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2066 M.getDataLayout(), NewInit->getType(), NewGV,
2067 {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 1)},
2070 Alias->setVisibility(
B.GV->getVisibility());
2071 Alias->takeName(
B.GV);
2073 B.GV->replaceAllUsesWith(Alias);
2074 B.GV->eraseFromParent();
2077bool DevirtModule::areRemarksEnabled() {
2078 const auto &FL =
M.getFunctionList();
2083 return DI.isEnabled();
2113 if (
Value *
Merge = GetMergeUser(U, &TypeTest))
2116 while (!Worklist.
empty()) {
2118 if (!VisitedMerges.
insert(V).second)
2123 if (Assume->getArgOperand(0) == V) {
2125 "assume must not be both direct and merged");
2137void DevirtModule::scanTypeTestUsers(
2139 DenseMap<
Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2142 SmallPtrSet<Value *, 8> VisitedMerges;
2157 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2163 if (!Assumes.
empty()) {
2164 Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();
2165 for (DevirtCallSite
Call : DevirtCalls)
2166 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
nullptr);
2169 auto RemoveTypeTestAssumes = [&]() {
2177 for (
auto *Assume : Assumes)
2178 Assume->eraseFromParent();
2181 if (CI->use_empty())
2182 CI->eraseFromParent();
2197 if (!TypeIdMap.count(TypeId))
2198 RemoveTypeTestAssumes();
2210 const TypeIdSummary *TidSummary =
2213 RemoveTypeTestAssumes();
2222void DevirtModule::scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc) {
2231 Value *Ptr = CI->getArgOperand(0);
2233 Value *TypeIdValue = CI->getArgOperand(2);
2239 bool HasNonCallUses =
false;
2240 auto &DT =
FAM.
getResult<DominatorTreeAnalysis>(*CI->getFunction());
2242 HasNonCallUses, CI, DT);
2251 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2253 Value *LoadedValue =
nullptr;
2255 Intrinsic::type_checked_load_relative) {
2257 &M, Intrinsic::load_relative, {Int32Ty});
2258 LoadedValue = LoadB.CreateCall(LoadRelFunc, {Ptr,
Offset});
2261 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2264 for (Instruction *LoadedPtr : LoadedPtrs) {
2265 LoadedPtr->replaceAllUsesWith(LoadedValue);
2266 LoadedPtr->eraseFromParent();
2270 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2271 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {Ptr, TypeIdValue});
2273 for (Instruction *Pred : Preds) {
2274 Pred->replaceAllUsesWith(TypeTestCall);
2275 Pred->eraseFromParent();
2282 if (!CI->use_empty()) {
2285 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2286 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2291 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2292 NumUnsafeUses = DevirtCalls.
size();
2299 for (DevirtCallSite
Call : DevirtCalls) {
2300 CallSlots[{TypeId,
Call.Offset}].addCallSite(Ptr,
Call.CB,
2304 CI->eraseFromParent();
2308void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2312 const TypeIdSummary *TidSummary =
2316 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2317 if (ResI == TidSummary->
WPDRes.end())
2319 const WholeProgramDevirtResolution &Res = ResI->second;
2325 Value *SingleImplVal =
2330 if (!
A->isInterposable() && !
A->getAliaseeObject()->isInterposable())
2331 SingleImplVal =
A->getAliaseeObject();
2335 bool IsExported =
false;
2336 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2340 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2341 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2344 auto &ResByArg =
I->second;
2351 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2355 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2356 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2362 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2364 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2376 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2379 bool IsExported =
false;
2380 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2385void DevirtModule::removeRedundantTypeTests() {
2387 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2388 if (
U.second == 0) {
2389 U.first->replaceAllUsesWith(True);
2390 U.first->eraseFromParent();
2396DevirtModule::lookUpFunctionValueInfo(
Function *TheFn,
2397 ModuleSummaryIndex *ExportSummary) {
2398 assert((ExportSummary !=
nullptr) &&
2399 "Caller guarantees ExportSummary is not nullptr");
2401 const auto TheFnGUID = TheFn->
getGUID();
2402 const auto TheFnGUIDWithExportedName =
2405 ValueInfo TheFnVI = ExportSummary->
getValueInfo(TheFnGUID);
2414 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2415 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2420bool DevirtModule::mustBeUnreachableFunction(
2421 Function *
const F, ModuleSummaryIndex *ExportSummary) {
2425 if (!
F->isDeclaration()) {
2431 return ExportSummary &&
2433 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2436bool DevirtModule::run() {
2445 Function *PublicTypeTestFunc =
nullptr;
2448 if (DevirtSpeculatively)
2449 PublicTypeTestFunc =
2456 &M, Intrinsic::type_checked_load_relative);
2463 if (!ExportSummary &&
2464 (((!PublicTypeTestFunc || PublicTypeTestFunc->
use_empty()) &&
2465 (!TypeTestFunc || TypeTestFunc->
use_empty())) ||
2466 !AssumeFunc || AssumeFunc->
use_empty()) &&
2467 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2468 (!TypeCheckedLoadRelativeFunc ||
2469 TypeCheckedLoadRelativeFunc->
use_empty()))
2473 std::vector<VTableBits>
Bits;
2474 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2475 buildTypeIdentifierMap(Bits, TypeIdMap);
2477 if (PublicTypeTestFunc && AssumeFunc)
2478 scanTypeTestUsers(PublicTypeTestFunc, TypeIdMap);
2480 if (TypeTestFunc && AssumeFunc)
2481 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2483 if (TypeCheckedLoadFunc)
2484 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2486 if (TypeCheckedLoadRelativeFunc)
2487 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2489 if (ImportSummary) {
2490 for (
auto &S : CallSlots)
2491 importResolution(S.first, S.second);
2493 removeRedundantTypeTests();
2498 for (GlobalVariable &GV :
M.globals())
2506 if (TypeIdMap.
empty())
2510 if (ExportSummary) {
2511 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2512 for (
auto &
P : TypeIdMap) {
2515 TypeId->getString())]
2519 for (
auto &
P : *ExportSummary) {
2520 for (
auto &S :
P.second.getSummaryList()) {
2525 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2526 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2527 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2530 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2531 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2532 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2535 for (
const FunctionSummary::ConstVCall &VC :
2536 FS->type_test_assume_const_vcalls()) {
2537 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2538 CallSlots[{MD,
VC.VFunc.Offset}]
2539 .ConstCSInfo[
VC.Args]
2540 .addSummaryTypeTestAssumeUser(FS);
2543 for (
const FunctionSummary::ConstVCall &VC :
2544 FS->type_checked_load_const_vcalls()) {
2545 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2546 CallSlots[{MD,
VC.VFunc.Offset}]
2547 .ConstCSInfo[
VC.Args]
2548 .addSummaryTypeCheckedLoadUser(FS);
2556 bool DidVirtualConstProp =
false;
2557 std::map<std::string, GlobalValue *> DevirtTargets;
2558 for (
auto &S : CallSlots) {
2562 std::vector<VirtualCallTarget> TargetsForSlot;
2563 WholeProgramDevirtResolution *Res =
nullptr;
2564 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2566 TypeMemberInfos.size())
2573 Res = &ExportSummary
2574 ->getOrInsertTypeIdSummary(
2576 .WPDRes[S.first.ByteOffset];
2577 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2578 S.first.ByteOffset, ExportSummary)) {
2579 bool SingleImplDevirt =
2580 trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res);
2584 if (!SingleImplDevirt && !DevirtSpeculatively) {
2585 DidVirtualConstProp |=
2586 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2588 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2593 for (
const auto &
T : TargetsForSlot)
2595 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2605 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2606 if (!CSI.AllCallSitesDevirted)
2607 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2608 FS->addTypeTest(GUID);
2610 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2611 for (
auto &CCS : S.second.ConstCSInfo)
2612 AddTypeTestsForTypeCheckedLoads(CCS.second);
2616 if (RemarksEnabled) {
2618 for (
const auto &DT : DevirtTargets) {
2619 GlobalValue *GV = DT.second;
2628 using namespace ore;
2629 OREGetter(*F).emit(OptimizationRemark(
DEBUG_TYPE,
"Devirtualized",
F)
2630 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2634 NumDevirtTargets += DevirtTargets.size();
2636 removeRedundantTypeTests();
2640 if (DidVirtualConstProp)
2647 for (GlobalVariable &GV :
M.globals())
2650 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2651 CI->eraseFromParent();
2656void DevirtIndex::run() {
2657 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2662 assert(!ExportSummary.withInternalizeAndPromote() &&
2663 "Expect index-based WPD to run before internalization and promotion");
2665 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2666 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2675 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2679 for (
auto &
P : ExportSummary) {
2680 for (
auto &S :
P.second.getSummaryList()) {
2685 for (FunctionSummary::VFuncId VF :
FS->type_test_assume_vcalls()) {
2686 for (StringRef Name : NameByGUID[VF.GUID]) {
2687 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2690 for (FunctionSummary::VFuncId VF :
FS->type_checked_load_vcalls()) {
2691 for (StringRef Name : NameByGUID[VF.GUID]) {
2692 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2695 for (
const FunctionSummary::ConstVCall &VC :
2696 FS->type_test_assume_const_vcalls()) {
2697 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2698 CallSlots[{
Name,
VC.VFunc.Offset}]
2699 .ConstCSInfo[
VC.Args]
2700 .addSummaryTypeTestAssumeUser(FS);
2703 for (
const FunctionSummary::ConstVCall &VC :
2704 FS->type_checked_load_const_vcalls()) {
2705 for (StringRef Name : NameByGUID[
VC.VFunc.GUID]) {
2706 CallSlots[{
Name,
VC.VFunc.Offset}]
2707 .ConstCSInfo[
VC.Args]
2708 .addSummaryTypeCheckedLoadUser(FS);
2714 std::set<ValueInfo> DevirtTargets;
2716 for (
auto &S : CallSlots) {
2720 std::vector<ValueInfo> TargetsForSlot;
2721 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2725 WholeProgramDevirtResolution *Res =
2726 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2727 ->WPDRes[S.first.ByteOffset];
2728 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2729 S.first.ByteOffset)) {
2731 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2740 for (
const auto &DT : DevirtTargets)
2741 errs() <<
"Devirtualized call to " << DT <<
"\n";
2743 NumDevirtTargets += DevirtTargets.size();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This is the interface for LLVM's primary stateless and local alias analysis.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
This file defines the SmallPtrSet class.
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 void findAssumesThroughMergesForTypeTest(SmallVectorImpl< CallInst * > &Assumes, CallInst &TypeTest, SmallPtrSetImpl< Value * > &VisitedMerges)
Find assumes whose conditions depend on this type test through phi or select nodes.
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
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.
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).
This class represents a function call, abstracting a target machine's calling convention.
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 * 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_SUPPRESS_DEPRECATED_DECLARATIONS_PUSH 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 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...
std::optional< uint64_t > getEntryCount() const
Get the entry count for this function.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
adds the attribute to the list of attributes for the given arg.
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 GEPNoWrapFlags inBounds()
static LLVM_ABI Expected< GlobPattern > create(StringRef Pat, std::optional< size_t > MaxSubPatterns={}, bool SlashAgnostic=false)
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...
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
bool hasMetadata() const
Return true if this GlobalObject has any metadata attached to it.
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 metadata of given kind attached to this GlobalObject.
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)
LLVM_ABI const GlobalObject * getAliaseeObject() const
LLVM_ABI GUID getGUID() const
Return a 64-bit global unique ID for this value.
@ 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
LLVM_ABI bool isInterposable(bool CheckNoIPA=true) const
Return true if this global's definition can be substituted with an arbitrary definition at link time ...
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.
iterator_range< user_iterator > users()
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.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
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)
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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'.
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
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.
iterator_range< user_iterator > users()
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
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.
@ BasicBlock
Various leaf nodes.
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.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
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.
DiagnosticInfoOptimizationBase::Argument NV
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.
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.
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.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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)
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
LLVM_ABI 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.
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)
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.
LLVM_ABI 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.
LLVM_ABI 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 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