106using namespace wholeprogramdevirt;
108#define DEBUG_TYPE "wholeprogramdevirt"
110STATISTIC(NumDevirtTargets,
"Number of whole program devirtualization targets");
111STATISTIC(NumSingleImpl,
"Number of single implementation devirtualizations");
113STATISTIC(NumUniformRetVal,
"Number of uniform return value optimizations");
114STATISTIC(NumUniqueRetVal,
"Number of unique return value optimizations");
116 "Number of 1 bit virtual constant propagations");
117STATISTIC(NumVirtConstProp,
"Number of virtual constant propagations");
120 "wholeprogramdevirt-summary-action",
121 cl::desc(
"What to do with the summary when running this pass"),
123 clEnumValN(PassSummaryAction::Import,
"import",
124 "Import typeid resolutions from summary and globals"),
125 clEnumValN(PassSummaryAction::Export,
"export",
126 "Export typeid resolutions to summary and globals")),
130 "wholeprogramdevirt-read-summary",
132 "Read summary from given bitcode or YAML file before running pass"),
136 "wholeprogramdevirt-write-summary",
137 cl::desc(
"Write summary to given bitcode or YAML file after running pass. "
138 "Output file format is deduced from extension: *.bc means writing "
139 "bitcode, otherwise YAML"),
145 cl::desc(
"Maximum number of call targets per "
146 "call site to enable branch funnels"));
150 cl::desc(
"Print index-based devirtualization messages"));
158 cl::desc(
"Enable whole program visibility"));
163 "disable-whole-program-visibility",
cl::Hidden,
164 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
169 cl::desc(
"Prevent function(s) from being devirtualized"),
180 cl::desc(
"Type of checking for incorrect devirtualizations"),
184 "Fallback to indirect when incorrect")));
188 std::vector<GlobPattern> Patterns;
189 template <
class T>
void init(
const T &StringList) {
190 for (
const auto &S : StringList)
192 Patterns.push_back(std::move(*Pat));
213 MinByte = std::max(MinByte,
Target.minAfterBytes());
215 MinByte = std::max(MinByte,
Target.minBeforeBytes());
238 std::vector<ArrayRef<uint8_t>> Used;
241 :
Target.TM->Bits->Before.BytesUsed;
243 : MinByte -
Target.minBeforeBytes();
253 for (
unsigned I = 0;; ++
I) {
254 uint8_t BitsUsed = 0;
255 for (
auto &&
B : Used)
258 if (BitsUsed != 0xff)
264 for (
unsigned I = 0;; ++
I) {
265 for (
auto &&
B : Used) {
267 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
273 return (MinByte +
I) * 8;
283 OffsetByte = -(AllocBefore / 8 + 1);
285 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
286 OffsetBit = AllocBefore % 8;
290 Target.setBeforeBit(AllocBefore);
300 OffsetByte = AllocAfter / 8;
302 OffsetByte = (AllocAfter + 7) / 8;
303 OffsetBit = AllocAfter % 8;
307 Target.setAfterBit(AllocAfter);
346 const VTableSlot &
RHS) {
347 return LHS.TypeID ==
RHS.TypeID &&
LHS.ByteOffset ==
RHS.ByteOffset;
366 return LHS.TypeID ==
RHS.TypeID &&
LHS.ByteOffset ==
RHS.ByteOffset;
389 if (!Summary->isLive())
391 if (
auto *FS = dyn_cast<FunctionSummary>(Summary->getBaseObject())) {
392 if (!FS->fflags().MustBeUnreachable)
407struct VirtualCallSite {
414 unsigned *NumUnsafeUses =
nullptr;
425 <<
NV(
"Optimization", OptName)
426 <<
": devirtualized a call to "
427 <<
NV(
"FunctionName", TargetName));
430 void replaceAndErase(
435 emitRemark(OptName, TargetName, OREGetter);
437 if (
auto *II = dyn_cast<InvokeInst>(&CB)) {
439 II->getUnwindDest()->removePredecessor(II->getParent());
456 std::vector<VirtualCallSite> CallSites;
461 bool AllCallSitesDevirted =
true;
468 bool SummaryHasTypeTestAssumeUsers =
false;
477 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
478 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
480 bool isExported()
const {
481 return SummaryHasTypeTestAssumeUsers ||
482 !SummaryTypeCheckedLoadUsers.empty();
486 SummaryTypeCheckedLoadUsers.push_back(FS);
487 AllCallSitesDevirted =
false;
491 SummaryTypeTestAssumeUsers.push_back(FS);
492 SummaryHasTypeTestAssumeUsers =
true;
493 AllCallSitesDevirted =
false;
497 AllCallSitesDevirted =
true;
500 SummaryTypeCheckedLoadUsers.clear();
505struct VTableSlotInfo {
512 std::map<std::vector<uint64_t>, CallSiteInfo> ConstCSInfo;
514 void addCallSite(
Value *VTable,
CallBase &CB,
unsigned *NumUnsafeUses);
517 CallSiteInfo &findCallSiteInfo(
CallBase &CB);
520CallSiteInfo &VTableSlotInfo::findCallSiteInfo(
CallBase &CB) {
521 std::vector<uint64_t>
Args;
522 auto *CBType = dyn_cast<IntegerType>(CB.
getType());
523 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
526 auto *CI = dyn_cast<ConstantInt>(Arg);
527 if (!CI || CI->getBitWidth() > 64)
529 Args.push_back(CI->getZExtValue());
531 return ConstCSInfo[
Args];
535 unsigned *NumUnsafeUses) {
536 auto &CSI = findCallSiteInfo(CB);
537 CSI.AllCallSitesDevirted =
false;
538 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
581 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
582 PatternList FunctionsToSkip;
589 :
M(
M), AARGetter(AARGetter), LookupDomTree(LookupDomTree),
590 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
591 Int8Ty(
Type::getInt8Ty(
M.getContext())),
594 Int64Ty(
Type::getInt64Ty(
M.getContext())),
595 IntPtrTy(
M.getDataLayout().getIntPtrType(
M.getContext(), 0)),
597 RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter) {
598 assert(!(ExportSummary && ImportSummary));
602 bool areRemarksEnabled();
605 scanTypeTestUsers(
Function *TypeTestFunc,
607 void scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc);
609 void buildTypeIdentifierMap(
610 std::vector<VTableBits> &Bits,
614 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
615 const std::set<TypeMemberInfo> &TypeMemberInfos,
619 void applySingleImplDevirt(VTableSlotInfo &SlotInfo,
Constant *TheFn,
623 VTableSlotInfo &SlotInfo,
626 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Constant *JT,
629 VTableSlotInfo &SlotInfo,
632 bool tryEvaluateFunctionsWithArgs(
636 void applyUniformRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
639 CallSiteInfo &CSInfo,
647 bool shouldExportConstantsAsAbsoluteSymbols();
667 void applyUniqueRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
bool IsOne,
669 bool tryUniqueRetValOpt(
unsigned BitWidth,
671 CallSiteInfo &CSInfo,
675 void applyVirtualConstProp(CallSiteInfo &CSInfo,
StringRef FnName,
678 VTableSlotInfo &SlotInfo,
684 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
688 void removeRedundantTypeTests();
721 std::set<GlobalValue::GUID> &ExportedGUIDs;
725 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
729 PatternList FunctionsToSkip;
733 std::set<GlobalValue::GUID> &ExportedGUIDs,
734 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap)
735 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
736 LocalWPDTargetsMap(LocalWPDTargetsMap) {
740 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
746 VTableSlotInfo &SlotInfo,
748 std::set<ValueInfo> &DevirtTargets);
766 if (UseCommandLine) {
767 if (!DevirtModule::runForTesting(M, AARGetter, OREGetter, LookupDomTree))
771 if (!DevirtModule(M, AARGetter, OREGetter, LookupDomTree, ExportSummary,
791 if (
TypeID.ends_with(
".virtual"))
797 if (!
TypeID.consume_front(
"_ZTS"))
805 std::string typeInfo = (
"_ZTI" +
TypeID).str();
806 return IsVisibleToRegularObj(typeInfo);
815 for (
auto Type : Types)
816 if (
auto *
TypeID = dyn_cast<MDString>(
Type->getOperand(1).get()))
818 IsVisibleToRegularObj);
827 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
829 bool ValidateAllVtablesHaveTypeInfos,
846 !(ValidateAllVtablesHaveTypeInfos &&
853 bool WholeProgramVisibilityEnabledInLTO) {
856 if (!PublicTypeTestFunc)
862 auto *CI = cast<CallInst>(U.getUser());
864 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)},
865 std::nullopt,
"", CI);
867 CI->eraseFromParent();
872 auto *CI = cast<CallInst>(U.getUser());
873 CI->replaceAllUsesWith(True);
874 CI->eraseFromParent();
885 for (
const auto &typeID :
Index.typeIdCompatibleVtableMap()) {
888 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
904 if (DynamicExportSymbols.
count(
P.first))
906 for (
auto &S :
P.second.SummaryList) {
907 auto *GVar = dyn_cast<GlobalVarSummary>(S.get());
915 if (VisibleToRegularObjSymbols.
count(
P.first))
924 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
925 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap).run();
931 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
932 for (
auto &
T : LocalWPDTargetsMap) {
935 assert(VI.getSummaryList().size() == 1 &&
936 "Devirt of local target has more than one copy");
937 auto &S = VI.getSummaryList()[0];
938 if (!isExported(S->modulePath(), VI))
942 for (
auto &SlotSummary :
T.second) {
943 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
945 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
946 assert(WPDRes != TIdSum->WPDRes.end());
948 WPDRes->second.SingleImplName,
949 Summary.getModuleHash(S->modulePath()));
959 const auto &ModPaths = Summary->modulePaths();
964 "combined summary should contain Regular LTO module");
968bool DevirtModule::runForTesting(
972 std::unique_ptr<ModuleSummaryIndex>
Summary =
973 std::make_unique<ModuleSummaryIndex>(
false);
980 auto ReadSummaryFile =
982 if (
Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
984 Summary = std::move(*SummaryOrErr);
989 yaml::Input
In(ReadSummaryFile->getBuffer());
996 DevirtModule(M, AARGetter, OREGetter, LookupDomTree,
1014 yaml::Output Out(
OS);
1022void DevirtModule::buildTypeIdentifierMap(
1023 std::vector<VTableBits> &Bits,
1026 Bits.reserve(
M.global_size());
1036 Bits.emplace_back();
1037 Bits.back().GV = &GV;
1038 Bits.back().ObjectSize =
1040 BitsPtr = &
Bits.back();
1048 cast<ConstantAsMetadata>(
Type->getOperand(0))->getValue())
1056bool DevirtModule::tryFindVirtualCallTargets(
1057 std::vector<VirtualCallTarget> &TargetsForSlot,
1058 const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset,
1061 if (!
TM.Bits->GV->isConstant())
1066 if (
TM.Bits->GV->getVCallVisibility() ==
1071 TM.Offset + ByteOffset, M,
TM.Bits->GV);
1075 auto C =
Ptr->stripPointerCasts();
1077 auto Fn = dyn_cast<Function>(
C);
1078 auto A = dyn_cast<GlobalAlias>(
C);
1080 Fn = dyn_cast<Function>(
A->getAliasee());
1085 if (FunctionsToSkip.match(Fn->getName()))
1090 if (Fn->getName() ==
"__cxa_pure_virtual")
1100 auto GV = dyn_cast<GlobalValue>(
C);
1102 TargetsForSlot.push_back({GV, &
TM});
1106 return !TargetsForSlot.empty();
1109bool DevirtIndex::tryFindVirtualCallTargets(
1110 std::vector<ValueInfo> &TargetsForSlot,
1124 bool LocalFound =
false;
1125 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1131 auto *CurVS = cast<GlobalVarSummary>(S->getBaseObject());
1132 if (!CurVS->vTableFuncs().empty() ||
1154 for (
auto VTP :
VS->vTableFuncs()) {
1155 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1161 TargetsForSlot.push_back(VTP.FuncVI);
1166 return !TargetsForSlot.empty();
1169void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1170 Constant *TheFn,
bool &IsExported) {
1175 auto Apply = [&](CallSiteInfo &CSInfo) {
1176 for (
auto &&VCallSite : CSInfo.CallSites) {
1177 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1181 VCallSite.emitRemark(
"single-impl",
1184 auto &CB = VCallSite.CB;
1197 Builder.SetInsertPoint(ThenTerm);
1199 auto *CallTrap =
Builder.CreateCall(TrapFn);
1217 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1218 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1240 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1245 if (VCallSite.NumUnsafeUses)
1246 --*VCallSite.NumUnsafeUses;
1248 if (CSInfo.isExported())
1250 CSInfo.markDevirt();
1252 Apply(SlotInfo.CSInfo);
1253 for (
auto &
P : SlotInfo.ConstCSInfo)
1259 if (Callee.getSummaryList().empty())
1266 bool IsExported =
false;
1267 auto &S = Callee.getSummaryList()[0];
1269 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1270 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1271 FS->addCall({Callee, CI});
1272 IsExported |= S->modulePath() != FS->modulePath();
1274 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1275 FS->addCall({Callee, CI});
1276 IsExported |= S->modulePath() != FS->modulePath();
1280 for (
auto &
P : SlotInfo.ConstCSInfo)
1285bool DevirtModule::trySingleImplDevirt(
1291 auto *TheFn = TargetsForSlot[0].Fn;
1292 for (
auto &&
Target : TargetsForSlot)
1298 TargetsForSlot[0].WasDevirt =
true;
1300 bool IsExported =
false;
1301 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1308 if (TheFn->hasLocalLinkage()) {
1309 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1314 if (
Comdat *
C = TheFn->getComdat()) {
1315 if (
C->getName() == TheFn->
getName()) {
1316 Comdat *NewC =
M.getOrInsertComdat(NewName);
1319 if (GO.getComdat() ==
C)
1341 VTableSlotInfo &SlotInfo,
1343 std::set<ValueInfo> &DevirtTargets) {
1346 auto TheFn = TargetsForSlot[0];
1347 for (
auto &&
Target : TargetsForSlot)
1352 auto Size = TheFn.getSummaryList().size();
1358 if (FunctionsToSkip.match(TheFn.name()))
1363 for (
const auto &S : TheFn.getSummaryList())
1369 DevirtTargets.insert(TheFn);
1371 auto &S = TheFn.getSummaryList()[0];
1372 bool IsExported =
AddCalls(SlotInfo, TheFn);
1374 ExportedGUIDs.insert(TheFn.getGUID());
1385 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1387 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1401void DevirtModule::tryICallBranchFunnel(
1411 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1413 for (
auto &
P : SlotInfo.ConstCSInfo)
1414 if (!
P.second.AllCallSitesDevirted) {
1415 HasNonDevirt =
true;
1425 if (isa<MDString>(
Slot.TypeID)) {
1427 M.getDataLayout().getProgramAddressSpace(),
1428 getGlobalName(Slot, {},
"branch_funnel"), &M);
1432 M.getDataLayout().getProgramAddressSpace(),
1433 "branch_funnel", &M);
1435 JT->addParamAttr(0, Attribute::Nest);
1437 std::vector<Value *> JTArgs;
1438 JTArgs.push_back(
JT->arg_begin());
1439 for (
auto &
T : TargetsForSlot) {
1440 JTArgs.push_back(getMemberAddr(
T.TM));
1441 JTArgs.push_back(
T.Fn);
1452 bool IsExported =
false;
1453 applyICallBranchFunnel(SlotInfo, JT, IsExported);
1458void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1460 auto Apply = [&](CallSiteInfo &CSInfo) {
1461 if (CSInfo.isExported())
1463 if (CSInfo.AllCallSitesDevirted)
1466 std::map<CallBase *, CallBase *> CallBases;
1467 for (
auto &&VCallSite : CSInfo.CallSites) {
1470 if (CallBases.find(&CB) != CallBases.end()) {
1487 VCallSite.emitRemark(
"branch-funnel",
1488 JT->stripPointerCasts()->getName(), OREGetter);
1492 std::vector<Type *> NewArgs;
1493 NewArgs.push_back(Int8PtrTy);
1501 std::vector<Value *>
Args;
1502 Args.push_back(VCallSite.VTable);
1506 if (isa<CallInst>(CB))
1507 NewCS = IRB.CreateCall(NewFT, IRB.CreateBitCast(JT, NewFTPtr), Args);
1509 NewCS = IRB.CreateInvoke(NewFT, IRB.CreateBitCast(JT, NewFTPtr),
1510 cast<InvokeInst>(CB).getNormalDest(),
1511 cast<InvokeInst>(CB).getUnwindDest(), Args);
1515 std::vector<AttributeSet> NewArgAttrs;
1518 M.getContext(), Attribute::Nest)}));
1519 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1520 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1523 Attrs.getRetAttrs(), NewArgAttrs));
1525 CallBases[&CB] = NewCS;
1528 if (VCallSite.NumUnsafeUses)
1529 --*VCallSite.NumUnsafeUses;
1536 for (
auto &[Old, New] : CallBases) {
1538 Old->eraseFromParent();
1541 Apply(SlotInfo.CSInfo);
1542 for (
auto &
P : SlotInfo.ConstCSInfo)
1546bool DevirtModule::tryEvaluateFunctionsWithArgs(
1555 auto Fn = dyn_cast<Function>(
Target.Fn);
1559 if (Fn->arg_size() !=
Args.size() + 1)
1566 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1568 dyn_cast<IntegerType>(Fn->getFunctionType()->getParamType(
I + 1));
1575 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1576 !isa<ConstantInt>(RetVal))
1578 Target.RetVal = cast<ConstantInt>(RetVal)->getZExtValue();
1583void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
1585 for (
auto Call : CSInfo.CallSites) {
1589 Call.replaceAndErase(
1590 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1593 CSInfo.markDevirt();
1596bool DevirtModule::tryUniformRetValOpt(
1601 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1603 if (
Target.RetVal != TheRetVal)
1606 if (CSInfo.isExported()) {
1608 Res->
Info = TheRetVal;
1611 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), TheRetVal);
1613 for (
auto &&
Target : TargetsForSlot)
1618std::string DevirtModule::getGlobalName(VTableSlot Slot,
1621 std::string FullName =
"__typeid_";
1623 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1630bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1638 getGlobalName(Slot, Args,
Name),
C, &M);
1645 if (shouldExportConstantsAsAbsoluteSymbols()) {
1658 M.getOrInsertGlobal(getGlobalName(Slot, Args,
Name), Int8Arr0Ty);
1659 auto *GV = dyn_cast<GlobalVariable>(
C);
1668 if (!shouldExportConstantsAsAbsoluteSymbols())
1672 auto *GV = cast<GlobalVariable>(
C->stripPointerCasts());
1677 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1688 SetAbsRange(~0ull, ~0ull);
1690 SetAbsRange(0, 1ull << AbsWidth);
1694void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
1697 for (
auto &&Call : CSInfo.CallSites) {
1703 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->getType()));
1704 Cmp =
B.CreateZExt(Cmp,
Call.CB.getType());
1706 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1709 CSInfo.markDevirt();
1718bool DevirtModule::tryUniqueRetValOpt(
1723 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1726 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1729 UniqueMember =
Target.TM;
1737 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1738 if (CSInfo.isExported()) {
1742 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1746 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), IsOne,
1751 for (
auto &&
Target : TargetsForSlot)
1758 if (tryUniqueRetValOptFor(
true))
1760 if (tryUniqueRetValOptFor(
false))
1766void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo,
StringRef FnName,
1768 for (
auto Call : CSInfo.CallSites) {
1771 auto *RetType = cast<IntegerType>(
Call.CB.getType());
1774 if (RetType->getBitWidth() == 1) {
1776 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1778 NumVirtConstProp1Bit++;
1779 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1780 OREGetter, IsBitSet);
1784 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1788 CSInfo.markDevirt();
1791bool DevirtModule::tryVirtualConstProp(
1797 auto Fn = dyn_cast<Function>(TargetsForSlot[0].Fn);
1801 auto RetType = dyn_cast<IntegerType>(Fn->getReturnType());
1804 unsigned BitWidth = RetType->getBitWidth();
1822 auto Fn = dyn_cast<Function>(
Target.Fn);
1826 if (Fn->isDeclaration() ||
1828 .doesNotAccessMemory() ||
1829 Fn->arg_empty() || !Fn->arg_begin()->use_empty() ||
1830 Fn->getReturnType() != RetType)
1834 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1835 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1840 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1842 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1845 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1846 ResByArg, Slot, CSByConstantArg.first))
1858 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1859 for (
auto &&
Target : TargetsForSlot) {
1860 TotalPaddingBefore += std::max<int64_t>(
1861 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1862 TotalPaddingAfter += std::max<int64_t>(
1863 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1868 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1875 if (TotalPaddingBefore <= TotalPaddingAfter)
1883 for (
auto &&
Target : TargetsForSlot)
1887 if (CSByConstantArg.second.isExported()) {
1889 exportConstant(Slot, CSByConstantArg.first,
"byte", OffsetByte,
1891 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
1898 applyVirtualConstProp(CSByConstantArg.second,
1899 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
1905 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
1910 Align Alignment =
M.getDataLayout().getValueOrABITypeAlignment(
1911 B.GV->getAlign(),
B.GV->getValueType());
1912 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
1915 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
1922 B.GV->getInitializer(),
1927 NewGV->setSection(
B.GV->getSection());
1928 NewGV->setComdat(
B.GV->getComdat());
1929 NewGV->setAlignment(
B.GV->getAlign());
1933 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
1938 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
1940 NewInit->getType(), NewGV,
1942 ConstantInt::get(Int32Ty, 1)}),
1944 Alias->setVisibility(
B.GV->getVisibility());
1945 Alias->takeName(
B.GV);
1947 B.GV->replaceAllUsesWith(Alias);
1948 B.GV->eraseFromParent();
1951bool DevirtModule::areRemarksEnabled() {
1952 const auto &FL =
M.getFunctionList();
1957 return DI.isEnabled();
1962void DevirtModule::scanTypeTestUsers(
1971 auto *CI = dyn_cast<CallInst>(
U.getUser());
1978 auto &DT = LookupDomTree(*CI->getFunction());
1982 cast<MetadataAsValue>(CI->getArgOperand(1))->getMetadata();
1984 if (!Assumes.
empty()) {
1985 Value *
Ptr = CI->getArgOperand(0)->stripPointerCasts();
1987 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
nullptr);
1990 auto RemoveTypeTestAssumes = [&]() {
1992 for (
auto *Assume : Assumes)
1993 Assume->eraseFromParent();
1996 if (CI->use_empty())
1997 CI->eraseFromParent();
2012 if (!TypeIdMap.count(TypeId))
2013 RemoveTypeTestAssumes();
2024 else if (ImportSummary && isa<MDString>(TypeId)) {
2028 RemoveTypeTestAssumes();
2037void DevirtModule::scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc) {
2041 auto *CI = dyn_cast<CallInst>(
U.getUser());
2047 Value *TypeIdValue = CI->getArgOperand(2);
2048 Metadata *TypeId = cast<MetadataAsValue>(TypeIdValue)->getMetadata();
2053 bool HasNonCallUses =
false;
2054 auto &DT = LookupDomTree(*CI->getFunction());
2056 HasNonCallUses, CI, DT);
2065 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2067 Value *LoadedValue =
nullptr;
2069 Intrinsic::type_checked_load_relative) {
2071 LoadedValue = LoadB.CreateLoad(
Int32Ty,
GEP);
2072 LoadedValue = LoadB.CreateSExt(LoadedValue, IntPtrTy);
2073 GEP = LoadB.CreatePtrToInt(
GEP, IntPtrTy);
2074 LoadedValue = LoadB.CreateAdd(
GEP, LoadedValue);
2075 LoadedValue = LoadB.CreateIntToPtr(LoadedValue, Int8PtrTy);
2078 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2083 LoadedPtr->eraseFromParent();
2087 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2088 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {
Ptr, TypeIdValue});
2092 Pred->eraseFromParent();
2099 if (!CI->use_empty()) {
2102 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2103 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2104 CI->replaceAllUsesWith(Pair);
2108 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2109 NumUnsafeUses = DevirtCalls.
size();
2117 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
2121 CI->eraseFromParent();
2125void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2126 auto *TypeId = dyn_cast<MDString>(
Slot.TypeID);
2133 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2134 if (ResI == TidSummary->
WPDRes.end())
2148 bool IsExported =
false;
2149 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2153 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2154 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2157 auto &ResByArg =
I->second;
2164 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2168 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2169 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2174 Constant *
Byte = importConstant(Slot, CSByConstantArg.first,
"byte",
2176 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2178 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2190 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2193 bool IsExported =
false;
2194 applyICallBranchFunnel(SlotInfo, JT, IsExported);
2199void DevirtModule::removeRedundantTypeTests() {
2201 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2202 if (
U.second == 0) {
2203 U.first->replaceAllUsesWith(True);
2204 U.first->eraseFromParent();
2210DevirtModule::lookUpFunctionValueInfo(
Function *TheFn,
2212 assert((ExportSummary !=
nullptr) &&
2213 "Caller guarantees ExportSummary is not nullptr");
2215 const auto TheFnGUID = TheFn->
getGUID();
2227 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2228 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2233bool DevirtModule::mustBeUnreachableFunction(
2236 if (!
F->isDeclaration()) {
2239 return isa<UnreachableInst>(
F->getEntryBlock().getTerminator());
2242 return ExportSummary &&
2244 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2247bool DevirtModule::run() {
2260 Function *TypeCheckedLoadRelativeFunc =
2267 if (!ExportSummary &&
2268 (!TypeTestFunc || TypeTestFunc->
use_empty() || !AssumeFunc ||
2270 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2271 (!TypeCheckedLoadRelativeFunc ||
2272 TypeCheckedLoadRelativeFunc->
use_empty()))
2276 std::vector<VTableBits>
Bits;
2278 buildTypeIdentifierMap(Bits, TypeIdMap);
2280 if (TypeTestFunc && AssumeFunc)
2281 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2283 if (TypeCheckedLoadFunc)
2284 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2286 if (TypeCheckedLoadRelativeFunc)
2287 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2289 if (ImportSummary) {
2290 for (
auto &S : CallSlots)
2291 importResolution(S.first, S.second);
2293 removeRedundantTypeTests();
2306 if (TypeIdMap.
empty())
2310 if (ExportSummary) {
2312 for (
auto &
P : TypeIdMap) {
2313 if (
auto *TypeId = dyn_cast<MDString>(
P.first))
2318 for (
auto &
P : *ExportSummary) {
2319 for (
auto &S :
P.second.SummaryList) {
2320 auto *
FS = dyn_cast<FunctionSummary>(S.get());
2325 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2326 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2330 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2331 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2335 FS->type_test_assume_const_vcalls()) {
2336 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2337 CallSlots[{MD,
VC.VFunc.Offset}]
2338 .ConstCSInfo[
VC.Args]
2339 .addSummaryTypeTestAssumeUser(FS);
2343 FS->type_checked_load_const_vcalls()) {
2344 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2345 CallSlots[{MD,
VC.VFunc.Offset}]
2346 .ConstCSInfo[
VC.Args]
2347 .addSummaryTypeCheckedLoadUser(FS);
2355 bool DidVirtualConstProp =
false;
2356 std::map<std::string, GlobalValue *> DevirtTargets;
2357 for (
auto &S : CallSlots) {
2361 std::vector<VirtualCallTarget> TargetsForSlot;
2363 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2364 if (ExportSummary && isa<MDString>(S.first.TypeID) &&
2365 TypeMemberInfos.size())
2372 Res = &ExportSummary
2373 ->getOrInsertTypeIdSummary(
2374 cast<MDString>(S.first.TypeID)->getString())
2375 .WPDRes[S.first.ByteOffset];
2376 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2377 S.first.ByteOffset, ExportSummary)) {
2379 if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res)) {
2380 DidVirtualConstProp |=
2381 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2383 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2388 for (
const auto &
T : TargetsForSlot)
2390 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2397 if (ExportSummary && isa<MDString>(S.first.TypeID)) {
2400 for (
auto *FS : S.second.CSInfo.SummaryTypeCheckedLoadUsers)
2401 FS->addTypeTest(GUID);
2402 for (
auto &CCS : S.second.ConstCSInfo)
2403 for (
auto *FS : CCS.second.SummaryTypeCheckedLoadUsers)
2404 FS->addTypeTest(GUID);
2408 if (RemarksEnabled) {
2410 for (
const auto &DT : DevirtTargets) {
2412 auto F = dyn_cast<Function>(GV);
2414 auto A = dyn_cast<GlobalAlias>(GV);
2415 assert(
A && isa<Function>(
A->getAliasee()));
2416 F = dyn_cast<Function>(
A->getAliasee());
2420 using namespace ore;
2423 <<
NV(
"FunctionName", DT.first));
2427 NumDevirtTargets += DevirtTargets.size();
2429 removeRedundantTypeTests();
2433 if (DidVirtualConstProp)
2443 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2444 CI->eraseFromParent();
2449void DevirtIndex::run() {
2450 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2454 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2462 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2466 for (
auto &
P : ExportSummary) {
2467 for (
auto &S :
P.second.SummaryList) {
2468 auto *
FS = dyn_cast<FunctionSummary>(S.get());
2474 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2479 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2483 FS->type_test_assume_const_vcalls()) {
2485 CallSlots[{
Name,
VC.VFunc.Offset}]
2486 .ConstCSInfo[
VC.Args]
2487 .addSummaryTypeTestAssumeUser(FS);
2491 FS->type_checked_load_const_vcalls()) {
2493 CallSlots[{
Name,
VC.VFunc.Offset}]
2494 .ConstCSInfo[
VC.Args]
2495 .addSummaryTypeCheckedLoadUser(FS);
2501 std::set<ValueInfo> DevirtTargets;
2503 for (
auto &S : CallSlots) {
2507 std::vector<ValueInfo> TargetsForSlot;
2508 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2513 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2514 ->WPDRes[S.first.ByteOffset];
2515 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2516 S.first.ByteOffset)) {
2518 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2527 for (
const auto &DT : DevirtTargets)
2528 errs() <<
"Devirtualized call to " << DT <<
"\n";
2530 NumDevirtTargets += DevirtTargets.size();
static const Function * getParent(const Value *V)
This is the interface for LLVM's primary stateless and local alias analysis.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines DenseMapInfo traits for DenseMap.
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
Provides passes for computing function attributes based on interprocedural analyses.
static cl::opt< std::string > ClReadSummary("lowertypetests-read-summary", cl::desc("Read summary from given YAML file before running pass"), cl::Hidden)
static cl::opt< PassSummaryAction > ClSummaryAction("lowertypetests-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
static cl::opt< std::string > ClWriteSummary("lowertypetests-write-summary", cl::desc("Write summary to given YAML file after running pass"), cl::Hidden)
This file implements a map that provides insertion order iteration.
static bool mustBeUnreachableFunction(const Function &F)
Module.h This file contains the declarations for the Module class.
FunctionAnalysisManager FAM
const char LLVMTargetMachineRef TM
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static cl::opt< bool > DisableWholeProgramVisibility("disable-whole-program-visibility", cl::Hidden, cl::desc("Disable whole program visibility (overrides enabling options)"))
Provide a way to force disable whole program for debugging or workarounds, when enabled via the linke...
WPDCheckMode
Mechanism to add runtime checking of devirtualization decisions, optionally trapping or falling back ...
static cl::opt< PassSummaryAction > ClSummaryAction("wholeprogramdevirt-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
static cl::opt< bool > WholeProgramVisibility("whole-program-visibility", cl::Hidden, cl::desc("Enable whole program visibility"))
Provide a way to force enable whole program visibility in tests.
static bool typeIDVisibleToRegularObj(StringRef TypeID, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary)
static cl::list< std::string > SkipFunctionNames("wholeprogramdevirt-skip", cl::desc("Prevent function(s) from being devirtualized"), cl::Hidden, cl::CommaSeparated)
Provide way to prevent certain function from being devirtualized.
static cl::opt< std::string > ClWriteSummary("wholeprogramdevirt-write-summary", cl::desc("Write summary to given bitcode or YAML file after running pass. " "Output file format is deduced from extension: *.bc means writing " "bitcode, otherwise YAML"), cl::Hidden)
static cl::opt< unsigned > ClThreshold("wholeprogramdevirt-branch-funnel-threshold", cl::Hidden, cl::init(10), cl::desc("Maximum number of call targets per " "call site to enable branch funnels"))
static cl::opt< WPDCheckMode > DevirtCheckMode("wholeprogramdevirt-check", cl::Hidden, cl::desc("Type of checking for incorrect devirtualizations"), cl::values(clEnumValN(WPDCheckMode::None, "none", "No checking"), clEnumValN(WPDCheckMode::Trap, "trap", "Trap when incorrect"), clEnumValN(WPDCheckMode::Fallback, "fallback", "Fallback to indirect when incorrect")))
static cl::opt< std::string > ClReadSummary("wholeprogramdevirt-read-summary", cl::desc("Read summary from given bitcode or YAML file before running pass"), cl::Hidden)
static bool skipUpdateDueToValidation(GlobalVariable &GV, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static bool AddCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee)
static cl::opt< bool > PrintSummaryDevirt("wholeprogramdevirt-print-index-based", cl::Hidden, cl::desc("Print index-based devirtualization messages"))
A manager for alias analyses.
A container for analyses that lazily runs them and caches their results.
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 AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)
Create an AttributeList with the specified parameters in it.
static AttributeSet get(LLVMContext &C, const AttrBuilder &B)
StringRef getValueAsString() const
Return the attribute's value as a string.
bool isValid() const
Return true if the attribute is any kind of attribute.
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
static BranchInst * Create(BasicBlock *IfTrue, Instruction *InsertBefore=nullptr)
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
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
static CallBase * removeOperandBundle(CallBase *CB, uint32_t ID, Instruction *InsertPt=nullptr)
Create a clone of CB with operand bundle ID removed.
Value * getCalledOperand() const
void setAttributes(AttributeList A)
Set the parameter attributes for this call.
FunctionType * getFunctionType() const
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
void setCalledOperand(Value *V)
AttributeList getAttributes() const
Return the parameter attributes for this call.
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="", Instruction *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 Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, bool InBounds=false, std::optional< unsigned > InRangeIndex=std::nullopt, Type *OnlyIfReducedTy=nullptr)
Getelementptr form.
static Constant * getBitCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static ConstantInt * getTrue(LLVMContext &Context)
static Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
static Constant * getAnon(ArrayRef< Constant * > V, bool Packed=false)
Return an anonymous struct that has the specified elements.
This is an important base class in LLVM.
const Constant * stripPointerCasts() const
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Implements a dense probed hash-table based set.
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
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.
This class evaluates LLVM IR, producing the Constant representing each SSA instruction.
Helper for check-and-exit error handling.
Tagged union holding either a T or a Error.
Function summary information to aid decisions and implementation of importing.
ArrayRef< Type * > params() const
Type * getReturnType() const
static 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)
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...
This class implements a glob pattern matcher similar to the one found in bash, but with some key diff...
static Expected< GlobPattern > create(StringRef Pat, std::optional< size_t > MaxSubPatterns={})
static 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.
void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
MDNode * getMetadata(unsigned KindID) const
Get the current metadata attachments for the given kind, if any.
VCallVisibility getVCallVisibility() const
bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
@ VCallVisibilityLinkageUnit
void setVCallVisibilityMetadata(VCallVisibility Visibility)
static bool isLocalLinkage(LinkageTypes Linkage)
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.
static GUID getGUID(StringRef GlobalName)
Return a 64-bit global unique ID constructed from global value name (i.e.
void setVisibility(VisibilityTypes V)
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
@ ExternalLinkage
Externally visible function.
Global variable summary information to aid decisions and implementation of importing.
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
const BasicBlock * getParent() const
void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Class to represent integer types.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
MDNode * createBranchWeights(uint32_t TrueWeight, uint32_t FalseWeight)
Return metadata containing two branch weights.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
This class implements a map that also provides access to all stored values in a deterministic order.
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,...
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 PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
static PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, Instruction *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.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
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.
Triple - Helper class for working with autoconf configuration names.
The instances of the Type class are immutable: once they are created, they are never changed.
TypeID
Definitions of all of the base types for the Type system.
static Type * getVoidTy(LLVMContext &C)
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.
void setName(const Twine &Name)
Change the name of the value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
iterator_range< use_iterator > uses()
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.
A raw_ostream that writes to a file descriptor.
A raw_ostream that writes to an std::string.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
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.
StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
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
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
uint64_t findLowestOffset(ArrayRef< VirtualCallTarget > Targets, bool IsAfter, uint64_t Size)
void setAfterReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocAfter, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)
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.
MemoryEffects computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR)
Returns the memory access properties of this copy of the function.
void writeIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out, const std::map< std::string, GVSummaryMapTy > *ModuleToSummariesForIndex=nullptr)
Write the specified module summary index to the given raw output stream, where it will be written in ...
@ Export
Export information to summary.
@ Import
Import information from summary.
void append_range(Container &C, Range &&R)
Wrapper function to append a range to a container.
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...
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
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.
Expected< std::unique_ptr< ModuleSummaryIndex > > getModuleSummaryIndex(MemoryBufferRef Buffer)
Parse the specified bitcode buffer, returning the module summary index.
void updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO)
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...
CallBase & versionCallSite(CallBase &CB, Value *Callee, MDNode *BranchWeights)
Predicate and clone the given call site.
bool AreStatisticsEnabled()
Check if statistics are enabled.
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...
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
void runWholeProgramDevirtOnIndex(ModuleSummaryIndex &Summary, std::set< GlobalValue::GUID > &ExportedGUIDs, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap)
Perform index-based whole program devirtualization on the Summary index.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
constexpr unsigned BitWidth
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
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...
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 ...
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...
Constant * getPointerAtOffset(Constant *I, uint64_t Offset, Module &M, Constant *TopLevelGlobal=nullptr)
Processes a Constant recursively looking into elements of arrays, structs and expressions to find a t...
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.
This struct is a compact representation of a valid (non-zero power of two) alignment.
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...
A call site that could be devirtualized.
A specification for a virtual function call with all constant integer arguments.
An "identifier" for a virtual function.
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
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.
VirtualCallTarget(GlobalValue *Fn, const TypeMemberInfo *TM)