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"),
190 "wholeprogramdevirt-keep-unreachable-function",
191 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
198 "wholeprogramdevirt-cutoff",
199 cl::desc(
"Max number of devirtualizations for devirt module pass"),
210 cl::desc(
"Type of checking for incorrect devirtualizations"),
214 "Fallback to indirect when incorrect")));
218 std::vector<GlobPattern> Patterns;
219 template <
class T>
void init(
const T &StringList) {
220 for (
const auto &S : StringList)
222 Patterns.push_back(std::move(*Pat));
243 MinByte = std::max(MinByte,
Target.minAfterBytes());
245 MinByte = std::max(MinByte,
Target.minBeforeBytes());
268 std::vector<ArrayRef<uint8_t>> Used;
271 :
Target.TM->Bits->Before.BytesUsed;
273 : MinByte -
Target.minBeforeBytes();
283 for (
unsigned I = 0;; ++
I) {
285 for (
auto &&
B : Used)
288 if (BitsUsed != 0xff)
294 for (
unsigned I = 0;; ++
I) {
295 for (
auto &&
B : Used) {
297 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
315 OffsetByte = -(AllocBefore / 8 + 1);
317 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
318 OffsetBit = AllocBefore % 8;
322 Target.setBeforeBit(AllocBefore);
332 OffsetByte = AllocAfter / 8;
334 OffsetByte = (AllocAfter + 7) / 8;
335 OffsetBit = AllocAfter % 8;
339 Target.setAfterBit(AllocAfter);
353static unsigned NumDevirtCalls = 0;
381 const VTableSlot &
RHS) {
382 return LHS.TypeID ==
RHS.TypeID &&
LHS.ByteOffset ==
RHS.ByteOffset;
401 return LHS.TypeID ==
RHS.TypeID &&
LHS.ByteOffset ==
RHS.ByteOffset;
427 if (!Summary->isLive())
429 if (
auto *FS = dyn_cast<FunctionSummary>(Summary->getBaseObject())) {
430 if (!FS->fflags().MustBeUnreachable)
445struct VirtualCallSite {
452 unsigned *NumUnsafeUses =
nullptr;
463 <<
NV(
"Optimization", OptName)
464 <<
": devirtualized a call to "
465 <<
NV(
"FunctionName", TargetName));
468 void replaceAndErase(
475 if (
auto *
II = dyn_cast<InvokeInst>(&CB)) {
477 II->getUnwindDest()->removePredecessor(
II->getParent());
494 std::vector<VirtualCallSite> CallSites;
503 bool AllCallSitesDevirted =
true;
512 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
516 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
518 bool isExported()
const {
519 return !SummaryTypeCheckedLoadUsers.empty() ||
520 !SummaryTypeTestAssumeUsers.empty();
524 SummaryTypeCheckedLoadUsers.push_back(FS);
525 AllCallSitesDevirted =
false;
529 SummaryTypeTestAssumeUsers.push_back(FS);
530 AllCallSitesDevirted =
false;
533 void markDevirt() { AllCallSitesDevirted =
true; }
537struct VTableSlotInfo {
544 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
546 void addCallSite(
Value *VTable,
CallBase &CB,
unsigned *NumUnsafeUses);
553 std::vector<uint64_t>
Args;
554 auto *CBType = dyn_cast<IntegerType>(CB.
getType());
555 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
558 auto *CI = dyn_cast<ConstantInt>(Arg);
559 if (!CI || CI->getBitWidth() > 64)
561 Args.push_back(CI->getZExtValue());
563 return ConstCSInfo[
Args];
567 unsigned *NumUnsafeUses) {
568 auto &CSI = findCallSiteInfo(CB);
569 CSI.AllCallSitesDevirted =
false;
570 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
591 const bool RemarksEnabled;
612 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
613 PatternList FunctionsToSkip;
620 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
621 Int8Ty(
Type::getInt8Ty(
M.getContext())),
623 Int32Ty(
Type::getInt32Ty(
M.getContext())),
624 Int64Ty(
Type::getInt64Ty(
M.getContext())),
625 IntPtrTy(
M.getDataLayout().getIntPtrType(
M.getContext(), 0)),
627 RemarksEnabled(areRemarksEnabled()),
631 assert(!(ExportSummary && ImportSummary));
635 bool areRemarksEnabled();
638 scanTypeTestUsers(
Function *TypeTestFunc,
640 void scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc);
642 void buildTypeIdentifierMap(
643 std::vector<VTableBits> &Bits,
647 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
648 const std::set<TypeMemberInfo> &TypeMemberInfos,
652 void applySingleImplDevirt(VTableSlotInfo &SlotInfo,
Constant *TheFn,
656 VTableSlotInfo &SlotInfo,
659 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Constant *JT,
662 VTableSlotInfo &SlotInfo,
665 bool tryEvaluateFunctionsWithArgs(
669 void applyUniformRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
672 CallSiteInfo &CSInfo,
680 bool shouldExportConstantsAsAbsoluteSymbols();
700 void applyUniqueRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
bool IsOne,
702 bool tryUniqueRetValOpt(
unsigned BitWidth,
704 CallSiteInfo &CSInfo,
708 void applyVirtualConstProp(CallSiteInfo &CSInfo,
StringRef FnName,
711 VTableSlotInfo &SlotInfo,
717 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
721 void removeRedundantTypeTests();
751 std::set<GlobalValue::GUID> &ExportedGUIDs;
755 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
759 PatternList FunctionsToSkip;
763 std::set<GlobalValue::GUID> &ExportedGUIDs,
764 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap)
765 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
766 LocalWPDTargetsMap(LocalWPDTargetsMap) {
770 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
776 VTableSlotInfo &SlotInfo,
778 std::set<ValueInfo> &DevirtTargets);
786 if (UseCommandLine) {
787 if (!DevirtModule::runForTesting(M,
MAM))
791 if (!DevirtModule(M,
MAM, ExportSummary, ImportSummary).run())
809 if (
TypeID.ends_with(
".virtual"))
815 if (!
TypeID.consume_front(
"_ZTS"))
823 std::string TypeInfo = (
"_ZTI" +
TypeID).str();
824 return IsVisibleToRegularObj(TypeInfo);
833 for (
auto *
Type : Types)
834 if (
auto *
TypeID = dyn_cast<MDString>(
Type->getOperand(1).get()))
836 IsVisibleToRegularObj);
845 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
847 bool ValidateAllVtablesHaveTypeInfos,
864 !(ValidateAllVtablesHaveTypeInfos &&
871 bool WholeProgramVisibilityEnabledInLTO) {
874 if (!PublicTypeTestFunc)
880 auto *CI = cast<CallInst>(U.getUser());
882 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
884 CI->replaceAllUsesWith(NewCI);
885 CI->eraseFromParent();
890 auto *CI = cast<CallInst>(U.getUser());
891 CI->replaceAllUsesWith(True);
892 CI->eraseFromParent();
903 for (
const auto &
TypeID : Index.typeIdCompatibleVtableMap()) {
906 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
919 for (
auto &
P : Index) {
922 if (DynamicExportSymbols.
count(
P.first))
924 for (
auto &S :
P.second.SummaryList) {
925 auto *GVar = dyn_cast<GlobalVarSummary>(S.get());
933 if (VisibleToRegularObjSymbols.
count(
P.first))
942 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
943 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap).run();
949 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
950 for (
auto &
T : LocalWPDTargetsMap) {
953 assert(VI.getSummaryList().size() == 1 &&
954 "Devirt of local target has more than one copy");
955 auto &S = VI.getSummaryList()[0];
956 if (!IsExported(S->modulePath(), VI))
960 for (
auto &SlotSummary :
T.second) {
961 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
963 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
964 assert(WPDRes != TIdSum->WPDRes.end());
966 WPDRes->second.SingleImplName,
967 Summary.getModuleHash(S->modulePath()));
977 const auto &ModPaths = Summary->modulePaths();
982 "combined summary should contain Regular LTO module");
987 std::unique_ptr<ModuleSummaryIndex>
Summary =
988 std::make_unique<ModuleSummaryIndex>(
false);
995 auto ReadSummaryFile =
997 if (
Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
999 Summary = std::move(*SummaryOrErr);
1004 yaml::Input
In(ReadSummaryFile->getBuffer());
1011 DevirtModule(M,
MAM,
1029 yaml::Output Out(
OS);
1037void DevirtModule::buildTypeIdentifierMap(
1038 std::vector<VTableBits> &Bits,
1041 Bits.reserve(
M.global_size());
1051 Bits.emplace_back();
1052 Bits.back().GV = &GV;
1053 Bits.back().ObjectSize =
1055 BitsPtr = &
Bits.back();
1063 cast<ConstantAsMetadata>(
Type->getOperand(0))->getValue())
1071bool DevirtModule::tryFindVirtualCallTargets(
1072 std::vector<VirtualCallTarget> &TargetsForSlot,
1073 const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset,
1076 if (!
TM.Bits->GV->isConstant())
1081 if (
TM.Bits->GV->getVCallVisibility() ==
1093 if (FunctionsToSkip.match(Fn->
getName()))
1098 if (Fn->
getName() ==
"__cxa_pure_virtual")
1108 auto *GV = dyn_cast<GlobalValue>(
C);
1110 TargetsForSlot.push_back({GV, &
TM});
1114 return !TargetsForSlot.empty();
1117bool DevirtIndex::tryFindVirtualCallTargets(
1118 std::vector<ValueInfo> &TargetsForSlot,
1132 bool LocalFound =
false;
1133 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1139 auto *CurVS = cast<GlobalVarSummary>(S->getBaseObject());
1140 if (!CurVS->vTableFuncs().empty() ||
1162 for (
auto VTP :
VS->vTableFuncs()) {
1163 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1169 TargetsForSlot.push_back(VTP.FuncVI);
1174 return !TargetsForSlot.empty();
1177void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1178 Constant *TheFn,
bool &IsExported) {
1184 for (
auto &&VCallSite : CSInfo.CallSites) {
1185 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1194 VCallSite.emitRemark(
"single-impl",
1198 auto &CB = VCallSite.CB;
1212 Builder.SetInsertPoint(ThenTerm);
1215 auto *CallTrap = Builder.CreateCall(TrapFn);
1232 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1233 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1255 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1260 if (VCallSite.NumUnsafeUses)
1261 --*VCallSite.NumUnsafeUses;
1263 if (CSInfo.isExported())
1265 CSInfo.markDevirt();
1267 Apply(SlotInfo.CSInfo);
1268 for (
auto &
P : SlotInfo.ConstCSInfo)
1274 if (Callee.getSummaryList().empty())
1281 bool IsExported =
false;
1282 auto &S = Callee.getSummaryList()[0];
1286 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1287 FS->addCall({Callee, CI});
1288 IsExported |= S->modulePath() != FS->modulePath();
1290 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1291 FS->addCall({Callee, CI});
1292 IsExported |= S->modulePath() != FS->modulePath();
1295 AddCalls(SlotInfo.CSInfo);
1296 for (
auto &
P : SlotInfo.ConstCSInfo)
1301bool DevirtModule::trySingleImplDevirt(
1307 auto *TheFn = TargetsForSlot[0].Fn;
1308 for (
auto &&
Target : TargetsForSlot)
1314 TargetsForSlot[0].WasDevirt =
true;
1316 bool IsExported =
false;
1317 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1324 if (TheFn->hasLocalLinkage()) {
1325 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1330 if (
Comdat *
C = TheFn->getComdat()) {
1331 if (
C->getName() == TheFn->
getName()) {
1332 Comdat *NewC =
M.getOrInsertComdat(NewName);
1335 if (GO.getComdat() ==
C)
1357 VTableSlotInfo &SlotInfo,
1359 std::set<ValueInfo> &DevirtTargets) {
1362 auto TheFn = TargetsForSlot[0];
1363 for (
auto &&
Target : TargetsForSlot)
1368 auto Size = TheFn.getSummaryList().size();
1374 if (FunctionsToSkip.match(TheFn.name()))
1379 for (
const auto &S : TheFn.getSummaryList())
1385 DevirtTargets.insert(TheFn);
1387 auto &S = TheFn.getSummaryList()[0];
1388 bool IsExported =
addCalls(SlotInfo, TheFn);
1390 ExportedGUIDs.insert(TheFn.getGUID());
1401 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1403 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1417void DevirtModule::tryICallBranchFunnel(
1427 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1429 for (
auto &
P : SlotInfo.ConstCSInfo)
1430 if (!
P.second.AllCallSitesDevirted) {
1431 HasNonDevirt =
true;
1449 for (
auto &
T : TargetsForSlot) {
1450 if (
T.TM->Bits->GV->hasAvailableExternallyLinkage())
1457 if (isa<MDString>(
Slot.TypeID)) {
1459 M.getDataLayout().getProgramAddressSpace(),
1460 getGlobalName(Slot, {},
"branch_funnel"), &M);
1464 M.getDataLayout().getProgramAddressSpace(),
1465 "branch_funnel", &M);
1467 JT->addParamAttr(0, Attribute::Nest);
1469 std::vector<Value *> JTArgs;
1470 JTArgs.push_back(
JT->arg_begin());
1471 for (
auto &
T : TargetsForSlot) {
1472 JTArgs.push_back(getMemberAddr(
T.TM));
1473 JTArgs.push_back(
T.Fn);
1478 &M, llvm::Intrinsic::icall_branch_funnel, {});
1484 bool IsExported =
false;
1485 applyICallBranchFunnel(SlotInfo, JT, IsExported);
1490void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1493 if (CSInfo.isExported())
1495 if (CSInfo.AllCallSitesDevirted)
1498 std::map<CallBase *, CallBase *> CallBases;
1499 for (
auto &&VCallSite : CSInfo.CallSites) {
1502 if (CallBases.find(&CB) != CallBases.end()) {
1519 VCallSite.emitRemark(
"branch-funnel",
1520 JT->stripPointerCasts()->getName(), OREGetter);
1524 std::vector<Type *> NewArgs;
1525 NewArgs.push_back(Int8PtrTy);
1531 std::vector<Value *>
Args;
1532 Args.push_back(VCallSite.VTable);
1536 if (isa<CallInst>(CB))
1537 NewCS = IRB.CreateCall(NewFT, JT, Args);
1540 IRB.CreateInvoke(NewFT, JT, cast<InvokeInst>(CB).getNormalDest(),
1541 cast<InvokeInst>(CB).getUnwindDest(), Args);
1545 std::vector<AttributeSet> NewArgAttrs;
1548 M.getContext(), Attribute::Nest)}));
1549 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1550 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1553 Attrs.getRetAttrs(), NewArgAttrs));
1555 CallBases[&CB] = NewCS;
1558 if (VCallSite.NumUnsafeUses)
1559 --*VCallSite.NumUnsafeUses;
1566 for (
auto &[Old, New] : CallBases) {
1568 Old->eraseFromParent();
1571 Apply(SlotInfo.CSInfo);
1572 for (
auto &
P : SlotInfo.ConstCSInfo)
1576bool DevirtModule::tryEvaluateFunctionsWithArgs(
1585 auto *Fn = dyn_cast<Function>(
Target.Fn);
1596 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1601 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1605 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1606 !isa<ConstantInt>(RetVal))
1608 Target.RetVal = cast<ConstantInt>(RetVal)->getZExtValue();
1613void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
1615 for (
auto Call : CSInfo.CallSites) {
1619 Call.replaceAndErase(
1620 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1621 ConstantInt::get(cast<IntegerType>(
Call.CB.getType()), TheRetVal));
1623 CSInfo.markDevirt();
1626bool DevirtModule::tryUniformRetValOpt(
1631 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1633 if (
Target.RetVal != TheRetVal)
1636 if (CSInfo.isExported()) {
1638 Res->
Info = TheRetVal;
1641 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1643 for (
auto &&
Target : TargetsForSlot)
1648std::string DevirtModule::getGlobalName(VTableSlot Slot,
1651 std::string FullName =
"__typeid_";
1653 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1660bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1668 getGlobalName(Slot, Args,
Name),
C, &M);
1675 if (shouldExportConstantsAsAbsoluteSymbols()) {
1688 M.getOrInsertGlobal(getGlobalName(Slot, Args,
Name), Int8Arr0Ty);
1696 if (!shouldExportConstantsAsAbsoluteSymbols())
1697 return ConstantInt::get(IntTy, Storage);
1700 auto *GV = cast<GlobalVariable>(
C->stripPointerCasts());
1705 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1716 SetAbsRange(~0ull, ~0ull);
1718 SetAbsRange(0, 1ull << AbsWidth);
1722void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
1725 for (
auto &&Call : CSInfo.CallSites) {
1731 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->getType()));
1732 Cmp =
B.CreateZExt(Cmp,
Call.CB.getType());
1734 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1737 CSInfo.markDevirt();
1742 ConstantInt::get(Int64Ty,
M->Offset));
1745bool DevirtModule::tryUniqueRetValOpt(
1750 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1753 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1756 UniqueMember =
Target.TM;
1764 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1765 if (CSInfo.isExported()) {
1769 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1773 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1778 for (
auto &&
Target : TargetsForSlot)
1785 if (tryUniqueRetValOptFor(
true))
1787 if (tryUniqueRetValOptFor(
false))
1793void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo,
StringRef FnName,
1795 for (
auto Call : CSInfo.CallSites) {
1798 auto *RetType = cast<IntegerType>(
Call.CB.getType());
1801 if (RetType->getBitWidth() == 1) {
1803 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1804 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1805 NumVirtConstProp1Bit++;
1806 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1807 OREGetter, IsBitSet);
1811 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1815 CSInfo.markDevirt();
1818bool DevirtModule::tryVirtualConstProp(
1824 auto *Fn = dyn_cast<Function>(TargetsForSlot[0].Fn);
1831 unsigned BitWidth = RetType->getBitWidth();
1843 Align TypeAlignment =
M.getDataLayout().getABIIntegerTypeAlignment(
BitWidth);
1859 auto *Fn = dyn_cast<Function>(
Target.Fn);
1877 Align TableAlignment =
M.getDataLayout().getValueOrABITypeAlignment(
1879 if (TypeAlignment > TableAlignment)
1883 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1884 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1889 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1891 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1894 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1895 ResByArg, Slot, CSByConstantArg.first))
1910 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1911 for (
auto &&
Target : TargetsForSlot) {
1912 TotalPaddingBefore += std::max<int64_t>(
1913 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1914 TotalPaddingAfter += std::max<int64_t>(
1915 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1920 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1927 if (TotalPaddingBefore <= TotalPaddingAfter)
1943 for (
auto &&
Target : TargetsForSlot)
1947 if (CSByConstantArg.second.isExported()) {
1949 exportConstant(Slot, CSByConstantArg.first,
"byte", OffsetByte,
1951 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
1956 Constant *ByteConst = ConstantInt::get(Int32Ty, OffsetByte);
1957 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
1958 applyVirtualConstProp(CSByConstantArg.second,
1959 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
1965 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
1970 Align Alignment =
M.getDataLayout().getValueOrABITypeAlignment(
1971 B.GV->getAlign(),
B.GV->getValueType());
1972 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
1975 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
1982 B.GV->getInitializer(),
1987 NewGV->setSection(
B.GV->getSection());
1988 NewGV->setComdat(
B.GV->getComdat());
1989 NewGV->setAlignment(
B.GV->getAlign());
1993 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
1998 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
2000 NewInit->getType(), NewGV,
2002 ConstantInt::get(Int32Ty, 1)}),
2004 Alias->setVisibility(
B.GV->getVisibility());
2005 Alias->takeName(
B.GV);
2007 B.GV->replaceAllUsesWith(Alias);
2008 B.GV->eraseFromParent();
2011bool DevirtModule::areRemarksEnabled() {
2012 const auto &FL =
M.getFunctionList();
2017 return DI.isEnabled();
2022void DevirtModule::scanTypeTestUsers(
2031 auto *CI = dyn_cast<CallInst>(
U.getUser());
2042 cast<MetadataAsValue>(CI->getArgOperand(1))->getMetadata();
2044 if (!Assumes.
empty()) {
2045 Value *
Ptr = CI->getArgOperand(0)->stripPointerCasts();
2047 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
nullptr);
2050 auto RemoveTypeTestAssumes = [&]() {
2052 for (
auto *Assume : Assumes)
2053 Assume->eraseFromParent();
2056 if (CI->use_empty())
2057 CI->eraseFromParent();
2072 if (!TypeIdMap.count(TypeId))
2073 RemoveTypeTestAssumes();
2084 else if (ImportSummary && isa<MDString>(TypeId)) {
2088 RemoveTypeTestAssumes();
2097void DevirtModule::scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc) {
2102 auto *CI = dyn_cast<CallInst>(
U.getUser());
2108 Value *TypeIdValue = CI->getArgOperand(2);
2109 Metadata *TypeId = cast<MetadataAsValue>(TypeIdValue)->getMetadata();
2114 bool HasNonCallUses =
false;
2117 HasNonCallUses, CI, DT);
2126 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2128 Value *LoadedValue =
nullptr;
2130 Intrinsic::type_checked_load_relative) {
2132 &M, Intrinsic::load_relative, {Int32Ty});
2133 LoadedValue = LoadB.CreateCall(LoadRelFunc, {
Ptr,
Offset});
2136 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2140 LoadedPtr->replaceAllUsesWith(LoadedValue);
2141 LoadedPtr->eraseFromParent();
2145 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2146 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {
Ptr, TypeIdValue});
2150 Pred->eraseFromParent();
2157 if (!CI->use_empty()) {
2160 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2161 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2162 CI->replaceAllUsesWith(Pair);
2166 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2167 NumUnsafeUses = DevirtCalls.
size();
2175 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
2179 CI->eraseFromParent();
2183void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2184 auto *TypeId = dyn_cast<MDString>(
Slot.TypeID);
2191 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2192 if (ResI == TidSummary->
WPDRes.end())
2206 bool IsExported =
false;
2207 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2211 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2212 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2215 auto &ResByArg =
I->second;
2222 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2226 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2227 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2232 Constant *
Byte = importConstant(Slot, CSByConstantArg.first,
"byte",
2233 Int32Ty, ResByArg.
Byte);
2234 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2236 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2248 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2251 bool IsExported =
false;
2252 applyICallBranchFunnel(SlotInfo, JT, IsExported);
2257void DevirtModule::removeRedundantTypeTests() {
2259 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2260 if (
U.second == 0) {
2261 U.first->replaceAllUsesWith(True);
2262 U.first->eraseFromParent();
2268DevirtModule::lookUpFunctionValueInfo(
Function *TheFn,
2270 assert((ExportSummary !=
nullptr) &&
2271 "Caller guarantees ExportSummary is not nullptr");
2273 const auto TheFnGUID = TheFn->
getGUID();
2274 const auto TheFnGUIDWithExportedName =
2286 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2287 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2292bool DevirtModule::mustBeUnreachableFunction(
2297 if (!
F->isDeclaration()) {
2300 return isa<UnreachableInst>(
F->getEntryBlock().getTerminator());
2303 return ExportSummary &&
2305 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2308bool DevirtModule::run() {
2322 &M, Intrinsic::type_checked_load_relative);
2329 if (!ExportSummary &&
2330 (!TypeTestFunc || TypeTestFunc->
use_empty() || !AssumeFunc ||
2332 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2333 (!TypeCheckedLoadRelativeFunc ||
2334 TypeCheckedLoadRelativeFunc->
use_empty()))
2338 std::vector<VTableBits>
Bits;
2340 buildTypeIdentifierMap(Bits, TypeIdMap);
2342 if (TypeTestFunc && AssumeFunc)
2343 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2345 if (TypeCheckedLoadFunc)
2346 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2348 if (TypeCheckedLoadRelativeFunc)
2349 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2351 if (ImportSummary) {
2352 for (
auto &S : CallSlots)
2353 importResolution(S.first, S.second);
2355 removeRedundantTypeTests();
2368 if (TypeIdMap.
empty())
2372 if (ExportSummary) {
2374 for (
auto &
P : TypeIdMap) {
2375 if (
auto *TypeId = dyn_cast<MDString>(
P.first))
2377 TypeId->getString())]
2381 for (
auto &
P : *ExportSummary) {
2382 for (
auto &S :
P.second.SummaryList) {
2383 auto *
FS = dyn_cast<FunctionSummary>(S.get());
2388 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2389 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2393 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2394 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2398 FS->type_test_assume_const_vcalls()) {
2399 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2400 CallSlots[{MD,
VC.VFunc.Offset}]
2401 .ConstCSInfo[
VC.Args]
2402 .addSummaryTypeTestAssumeUser(FS);
2406 FS->type_checked_load_const_vcalls()) {
2407 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2408 CallSlots[{MD,
VC.VFunc.Offset}]
2409 .ConstCSInfo[
VC.Args]
2410 .addSummaryTypeCheckedLoadUser(FS);
2418 bool DidVirtualConstProp =
false;
2419 std::map<std::string, GlobalValue *> DevirtTargets;
2420 for (
auto &S : CallSlots) {
2424 std::vector<VirtualCallTarget> TargetsForSlot;
2426 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2427 if (ExportSummary && isa<MDString>(S.first.TypeID) &&
2428 TypeMemberInfos.size())
2435 Res = &ExportSummary
2436 ->getOrInsertTypeIdSummary(
2437 cast<MDString>(S.first.TypeID)->getString())
2438 .WPDRes[S.first.ByteOffset];
2439 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2440 S.first.ByteOffset, ExportSummary)) {
2442 if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res)) {
2443 DidVirtualConstProp |=
2444 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2446 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2451 for (
const auto &
T : TargetsForSlot)
2453 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2460 if (ExportSummary && isa<MDString>(S.first.TypeID)) {
2462 cast<MDString>(S.first.TypeID)->getString());
2463 auto AddTypeTestsForTypeCheckedLoads = [&](
CallSiteInfo &CSI) {
2464 if (!CSI.AllCallSitesDevirted)
2465 for (
auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2466 FS->addTypeTest(GUID);
2468 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2469 for (
auto &CCS : S.second.ConstCSInfo)
2470 AddTypeTestsForTypeCheckedLoads(CCS.second);
2474 if (RemarksEnabled) {
2476 for (
const auto &DT : DevirtTargets) {
2478 auto *
F = dyn_cast<Function>(GV);
2480 auto *
A = dyn_cast<GlobalAlias>(GV);
2481 assert(
A && isa<Function>(
A->getAliasee()));
2482 F = dyn_cast<Function>(
A->getAliasee());
2486 using namespace ore;
2488 <<
"devirtualized " <<
NV(
"FunctionName", DT.first));
2492 NumDevirtTargets += DevirtTargets.size();
2494 removeRedundantTypeTests();
2498 if (DidVirtualConstProp)
2508 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2509 CI->eraseFromParent();
2514void DevirtIndex::run() {
2515 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2519 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2528 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2532 for (
auto &
P : ExportSummary) {
2533 for (
auto &S :
P.second.SummaryList) {
2534 auto *
FS = dyn_cast<FunctionSummary>(S.get());
2540 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2545 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2549 FS->type_test_assume_const_vcalls()) {
2551 CallSlots[{
Name,
VC.VFunc.Offset}]
2552 .ConstCSInfo[
VC.Args]
2553 .addSummaryTypeTestAssumeUser(FS);
2557 FS->type_checked_load_const_vcalls()) {
2559 CallSlots[{
Name,
VC.VFunc.Offset}]
2560 .ConstCSInfo[
VC.Args]
2561 .addSummaryTypeCheckedLoadUser(FS);
2567 std::set<ValueInfo> DevirtTargets;
2569 for (
auto &S : CallSlots) {
2573 std::vector<ValueInfo> TargetsForSlot;
2574 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2579 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2580 ->WPDRes[S.first.ByteOffset];
2581 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2582 S.first.ByteOffset)) {
2584 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2593 for (
const auto &DT : DevirtTargets)
2594 errs() <<
"Devirtualized call to " << DT <<
"\n";
2596 NumDevirtTargets += DevirtTargets.size();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This is the interface for LLVM's primary stateless and local alias analysis.
static GCRegistry::Add< 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 void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE, bool Skip)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
static cl::opt< std::string > ClReadSummary("lowertypetests-read-summary", cl::desc("Read summary from given YAML file before running pass"), cl::Hidden)
static cl::opt< PassSummaryAction > ClSummaryAction("lowertypetests-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
static cl::opt< std::string > ClWriteSummary("lowertypetests-write-summary", cl::desc("Write summary to given YAML file after running pass"), cl::Hidden)
This file implements a map that provides insertion order iteration.
static bool mustBeUnreachableFunction(const Function &F)
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
const SmallVectorImpl< MachineOperand > & Cond
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static cl::opt< bool > DisableWholeProgramVisibility("disable-whole-program-visibility", cl::Hidden, cl::desc("Disable whole program visibility (overrides enabling options)"))
Provide a way to force disable whole program for debugging or workarounds, when enabled via the linke...
WPDCheckMode
Mechanism to add runtime checking of devirtualization decisions, optionally trapping or falling back ...
static cl::opt< PassSummaryAction > ClSummaryAction("wholeprogramdevirt-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
static cl::opt< bool > WholeProgramVisibility("whole-program-visibility", cl::Hidden, cl::desc("Enable whole program visibility"))
Provide a way to force enable whole program visibility in tests.
static bool typeIDVisibleToRegularObj(StringRef TypeID, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary)
static cl::list< std::string > SkipFunctionNames("wholeprogramdevirt-skip", cl::desc("Prevent function(s) from being devirtualized"), cl::Hidden, cl::CommaSeparated)
Provide way to prevent certain function from being devirtualized.
static cl::opt< std::string > ClWriteSummary("wholeprogramdevirt-write-summary", cl::desc("Write summary to given bitcode or YAML file after running pass. " "Output file format is deduced from extension: *.bc means writing " "bitcode, otherwise YAML"), cl::Hidden)
static bool addCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee)
static cl::opt< unsigned > ClThreshold("wholeprogramdevirt-branch-funnel-threshold", cl::Hidden, cl::init(10), cl::desc("Maximum number of call targets per " "call site to enable branch funnels"))
static cl::opt< WPDCheckMode > DevirtCheckMode("wholeprogramdevirt-check", cl::Hidden, cl::desc("Type of checking for incorrect devirtualizations"), cl::values(clEnumValN(WPDCheckMode::None, "none", "No checking"), clEnumValN(WPDCheckMode::Trap, "trap", "Trap when incorrect"), clEnumValN(WPDCheckMode::Fallback, "fallback", "Fallback to indirect when incorrect")))
static cl::opt< bool > WholeProgramDevirtKeepUnreachableFunction("wholeprogramdevirt-keep-unreachable-function", cl::desc("Regard unreachable functions as possible devirtualize targets."), cl::Hidden, cl::init(true))
With Clang, a pure virtual class's deleting destructor is emitted as a llvm.trap intrinsic followed b...
static cl::opt< std::string > ClReadSummary("wholeprogramdevirt-read-summary", cl::desc("Read summary from given bitcode or YAML file before running pass"), cl::Hidden)
static bool skipUpdateDueToValidation(GlobalVariable &GV, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static cl::opt< unsigned > WholeProgramDevirtCutoff("wholeprogramdevirt-cutoff", cl::desc("Max number of devirtualizations for devirt module pass"), cl::init(0))
If explicitly specified, the devirt module pass will stop transformation once the total number of dev...
static cl::opt< bool > PrintSummaryDevirt("wholeprogramdevirt-print-index-based", cl::Hidden, cl::desc("Print index-based devirtualization messages"))
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 LLVM_ABI AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)
Create an AttributeList with the specified parameters in it.
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.
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, InsertPosition 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
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 * getInBoundsGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList)
Create an "inbounds" getelementptr.
static LLVM_ABI Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReducedTy=nullptr)
Getelementptr form.
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
static Constant * getAnon(ArrayRef< Constant * > V, bool Packed=false)
Return an anonymous struct that has the specified elements.
This is an important base class in LLVM.
const Constant * stripPointerCasts() const
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Implements a dense probed hash-table based set.
Analysis pass which computes a DominatorTree.
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.
Type * getParamType(unsigned i) const
Parameter type accessors.
ArrayRef< Type * > params() const
Type * getReturnType() const
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
FunctionType * getFunctionType() const
Returns the FunctionType for me.
const BasicBlock & front() const
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
Type * getReturnType() const
Returns the type of the ret val.
This class implements a glob pattern matcher similar to the one found in bash, but with some key diff...
static LLVM_ABI Expected< GlobPattern > create(StringRef Pat, std::optional< size_t > MaxSubPatterns={})
static LLVM_ABI GlobalAlias * create(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, Constant *Aliasee, Module *Parent)
If a parent module is specified, the alias is automatically inserted into the end of the specified mo...
bool hasMetadata() const
Return true if this value has any metadata attached to it.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
LLVM_ABI VCallVisibility getVCallVisibility() const
LLVM_ABI bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
@ VCallVisibilityLinkageUnit
MDNode * getMetadata(unsigned KindID) const
Get the current metadata attachments for the given kind, if any.
LLVM_ABI void setVCallVisibilityMetadata(VCallVisibility Visibility)
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
static bool isLocalLinkage(LinkageTypes Linkage)
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
static bool isAvailableExternallyLinkage(LinkageTypes Linkage)
GUID getGUID() const
Return a 64-bit global unique ID constructed from global value name (i.e.
@ HiddenVisibility
The GV is hidden.
void setVisibility(VisibilityTypes V)
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
@ ExternalLinkage
Externally visible function.
Type * getValueType() const
Global variable summary information to aid decisions and implementation of importing.
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
MaybeAlign getAlign() const
Returns the alignment of the given 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.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
Class to represent integer types.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
LLVM_ABI MDNode * createLikelyBranchWeights()
Return metadata containing two branch weights, with significant bias towards true destination.
LLVM_ABI MDNode * createUnlikelyBranchWeights()
Return metadata containing two branch weights, with significant bias towards false destination.
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,...
bool doesNotAccessMemory() const
Whether this function accesses no memory.
Class to hold module path string table and global value map, and encapsulate methods for operating on...
const TypeIdSummary * getTypeIdSummary(StringRef TypeId) const
This returns either a pointer to the type id summary (if present in the summary map) or null (if not ...
ValueInfo getValueInfo(const GlobalValueSummaryMapTy::value_type &R) const
Return a ValueInfo for the index value_type (convenient when iterating index).
const ModuleHash & getModuleHash(const StringRef ModPath) const
Get the module SHA1 hash recorded for the given module path.
static constexpr const char * getRegularLTOModuleName()
bool partiallySplitLTOUnits() const
static std::string getGlobalNameForLocal(StringRef Name, ModuleHash ModHash)
Convenience method for creating a promoted global name for the given value name of a local,...
A Module instance is used to store all the information related to an LLVM module.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
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 LLVM_ABI 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.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
self_iterator getIterator()
A raw_ostream that writes to a file descriptor.
A raw_ostream that writes to an std::string.
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.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
LLVM_ABI Function * getDeclarationIfExists(const Module *M, ID id)
Look up the Function declaration of the intrinsic id in the Module M and return it if it exists.
bool match(Val *V, const Pattern &P)
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
@ Assume
Do not drop type tests (default).
DiagnosticInfoOptimizationBase::Argument NV
@ 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 MemoryEffects computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR)
Returns the memory access properties of this copy of the function.
@ Export
Export information to summary.
@ Import
Import information from summary.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
LLVM_ABI bool hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO)
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
LLVM_ABI void writeIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out, const ModuleToSummariesForIndexTy *ModuleToSummariesForIndex=nullptr, const GVSummaryPtrSet *DecSummaries=nullptr)
Write the specified module summary index to the given raw output stream, where it will be written in ...
LLVM_ABI Expected< std::unique_ptr< ModuleSummaryIndex > > getModuleSummaryIndex(MemoryBufferRef Buffer)
Parse the specified bitcode buffer, returning the module summary index.
LLVM_ABI void updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO)
LLVM_ABI void getVisibleToRegularObjVtableGUIDs(ModuleSummaryIndex &Index, DenseSet< GlobalValue::GUID > &VisibleToRegularObjSymbols, function_ref< bool(StringRef)> IsVisibleToRegularObj)
Based on typeID string, get all associated vtable GUIDS that are visible to regular objects.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void findDevirtualizableCallsForTypeCheckedLoad(SmallVectorImpl< DevirtCallSite > &DevirtCalls, SmallVectorImpl< Instruction * > &LoadedPtrs, SmallVectorImpl< Instruction * > &Preds, bool &HasNonCallUses, const CallInst *CI, DominatorTree &DT)
Given a call to the intrinsic @llvm.type.checked.load, find all devirtualizable call sites based on t...
LLVM_ABI CallBase & versionCallSite(CallBase &CB, Value *Callee, MDNode *BranchWeights)
Predicate and clone the given call site.
LLVM_ABI bool AreStatisticsEnabled()
Check if statistics are enabled.
LLVM_ABI void updateIndexWPDForExports(ModuleSummaryIndex &Summary, function_ref< bool(StringRef, ValueInfo)> isExported, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap)
Call after cross-module importing to update the recorded single impl devirt target names for any loca...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
LLVM_ABI void runWholeProgramDevirtOnIndex(ModuleSummaryIndex &Summary, std::set< GlobalValue::GUID > &ExportedGUIDs, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap)
Perform index-based whole program devirtualization on the Summary index.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
constexpr unsigned BitWidth
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...
void consumeError(Error Err)
Consume a Error without doing anything.
void findDevirtualizableCallsForTypeTest(SmallVectorImpl< DevirtCallSite > &DevirtCalls, SmallVectorImpl< CallInst * > &Assumes, const CallInst *CI, DominatorTree &DT)
Given a call to the intrinsic @llvm.type.test, find all devirtualizable call sites based on the call ...
LLVM_ABI void updateVCallVisibilityInModule(Module &M, bool WholeProgramVisibilityEnabledInLTO, const DenseSet< GlobalValue::GUID > &DynamicExportSymbols, bool ValidateAllVtablesHaveTypeInfos, function_ref< bool(StringRef)> IsVisibleToRegularObj)
If whole program visibility asserted, then upgrade all public vcall visibility metadata on vtable def...
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.
This struct is a compact representation of a valid (non-zero power of two) alignment.
uint64_t value() const
This is a hole in the type system and should not be abused.
Class to accumulate and hold information about a callee.
static unsigned getHashValue(const VTableSlotSummary &I)
static bool isEqual(const VTableSlotSummary &LHS, const VTableSlotSummary &RHS)
static VTableSlotSummary getTombstoneKey()
static VTableSlotSummary getEmptyKey()
static VTableSlot getTombstoneKey()
static VTableSlot getEmptyKey()
static bool isEqual(const VTableSlot &LHS, const VTableSlot &RHS)
static unsigned getHashValue(const VTableSlot &I)
An information struct used to provide DenseMap with the various necessary components for a given valu...
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
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)