104using namespace wholeprogramdevirt;
106#define DEBUG_TYPE "wholeprogramdevirt"
108STATISTIC(NumDevirtTargets,
"Number of whole program devirtualization targets");
109STATISTIC(NumSingleImpl,
"Number of single implementation devirtualizations");
111STATISTIC(NumUniformRetVal,
"Number of uniform return value optimizations");
112STATISTIC(NumUniqueRetVal,
"Number of unique return value optimizations");
114 "Number of 1 bit virtual constant propagations");
115STATISTIC(NumVirtConstProp,
"Number of virtual constant propagations");
118 "wholeprogramdevirt-summary-action",
119 cl::desc(
"What to do with the summary when running this pass"),
121 clEnumValN(PassSummaryAction::Import,
"import",
122 "Import typeid resolutions from summary and globals"),
123 clEnumValN(PassSummaryAction::Export,
"export",
124 "Export typeid resolutions to summary and globals")),
128 "wholeprogramdevirt-read-summary",
130 "Read summary from given bitcode or YAML file before running pass"),
134 "wholeprogramdevirt-write-summary",
135 cl::desc(
"Write summary to given bitcode or YAML file after running pass. "
136 "Output file format is deduced from extension: *.bc means writing "
137 "bitcode, otherwise YAML"),
143 cl::desc(
"Maximum number of call targets per "
144 "call site to enable branch funnels"));
148 cl::desc(
"Print index-based devirtualization messages"));
156 cl::desc(
"Enable whole program visibility"));
161 "disable-whole-program-visibility",
cl::Hidden,
162 cl::desc(
"Disable whole program visibility (overrides enabling options)"));
167 cl::desc(
"Prevent function(s) from being devirtualized"),
188 "wholeprogramdevirt-keep-unreachable-function",
189 cl::desc(
"Regard unreachable functions as possible devirtualize targets."),
196 "wholeprogramdevirt-cutoff",
197 cl::desc(
"Max number of devirtualizations for devirt module pass"),
208 cl::desc(
"Type of checking for incorrect devirtualizations"),
212 "Fallback to indirect when incorrect")));
216 std::vector<GlobPattern> Patterns;
217 template <
class T>
void init(
const T &StringList) {
218 for (
const auto &S : StringList)
220 Patterns.push_back(std::move(*Pat));
241 MinByte = std::max(MinByte,
Target.minAfterBytes());
243 MinByte = std::max(MinByte,
Target.minBeforeBytes());
266 std::vector<ArrayRef<uint8_t>> Used;
269 :
Target.TM->Bits->Before.BytesUsed;
271 : MinByte -
Target.minBeforeBytes();
281 for (
unsigned I = 0;; ++
I) {
283 for (
auto &&
B : Used)
286 if (BitsUsed != 0xff)
292 for (
unsigned I = 0;; ++
I) {
293 for (
auto &&
B : Used) {
295 while ((
I + Byte) <
B.size() && Byte < (
Size / 8)) {
301 return (MinByte +
I) * 8;
311 OffsetByte = -(AllocBefore / 8 + 1);
313 OffsetByte = -((AllocBefore + 7) / 8 + (
BitWidth + 7) / 8);
314 OffsetBit = AllocBefore % 8;
318 Target.setBeforeBit(AllocBefore);
328 OffsetByte = AllocAfter / 8;
330 OffsetByte = (AllocAfter + 7) / 8;
331 OffsetBit = AllocAfter % 8;
335 Target.setAfterBit(AllocAfter);
349static unsigned NumDevirtCalls = 0;
377 const VTableSlot &
RHS) {
378 return LHS.TypeID ==
RHS.TypeID &&
LHS.ByteOffset ==
RHS.ByteOffset;
397 return LHS.TypeID ==
RHS.TypeID &&
LHS.ByteOffset ==
RHS.ByteOffset;
423 if (!Summary->isLive())
425 if (
auto *FS = dyn_cast<FunctionSummary>(Summary->getBaseObject())) {
426 if (!FS->fflags().MustBeUnreachable)
441struct VirtualCallSite {
448 unsigned *NumUnsafeUses =
nullptr;
459 <<
NV(
"Optimization", OptName)
460 <<
": devirtualized a call to "
461 <<
NV(
"FunctionName", TargetName));
464 void replaceAndErase(
471 if (
auto *
II = dyn_cast<InvokeInst>(&CB)) {
473 II->getUnwindDest()->removePredecessor(
II->getParent());
490 std::vector<VirtualCallSite> CallSites;
495 bool AllCallSitesDevirted =
true;
502 bool SummaryHasTypeTestAssumeUsers =
false;
511 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
512 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
514 bool isExported()
const {
515 return SummaryHasTypeTestAssumeUsers ||
516 !SummaryTypeCheckedLoadUsers.empty();
520 SummaryTypeCheckedLoadUsers.push_back(FS);
521 AllCallSitesDevirted =
false;
525 SummaryTypeTestAssumeUsers.push_back(FS);
526 SummaryHasTypeTestAssumeUsers =
true;
527 AllCallSitesDevirted =
false;
531 AllCallSitesDevirted =
true;
534 SummaryTypeCheckedLoadUsers.clear();
539struct VTableSlotInfo {
546 std::map<std::vector<uint64_t>,
CallSiteInfo> ConstCSInfo;
548 void addCallSite(
Value *VTable,
CallBase &CB,
unsigned *NumUnsafeUses);
555 std::vector<uint64_t>
Args;
556 auto *CBType = dyn_cast<IntegerType>(CB.
getType());
557 if (!CBType || CBType->getBitWidth() > 64 || CB.
arg_empty())
560 auto *CI = dyn_cast<ConstantInt>(Arg);
561 if (!CI || CI->getBitWidth() > 64)
563 Args.push_back(CI->getZExtValue());
565 return ConstCSInfo[
Args];
569 unsigned *NumUnsafeUses) {
570 auto &CSI = findCallSiteInfo(CB);
571 CSI.AllCallSitesDevirted =
false;
572 CSI.CallSites.push_back({
VTable, CB, NumUnsafeUses});
615 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
616 PatternList FunctionsToSkip;
623 :
M(
M), AARGetter(AARGetter), LookupDomTree(LookupDomTree),
624 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
625 Int8Ty(
Type::getInt8Ty(
M.getContext())),
627 Int32Ty(
Type::getInt32Ty(
M.getContext())),
628 Int64Ty(
Type::getInt64Ty(
M.getContext())),
629 IntPtrTy(
M.getDataLayout().getIntPtrType(
M.getContext(), 0)),
631 RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter) {
632 assert(!(ExportSummary && ImportSummary));
636 bool areRemarksEnabled();
639 scanTypeTestUsers(
Function *TypeTestFunc,
641 void scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc);
643 void buildTypeIdentifierMap(
644 std::vector<VTableBits> &Bits,
648 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
649 const std::set<TypeMemberInfo> &TypeMemberInfos,
653 void applySingleImplDevirt(VTableSlotInfo &SlotInfo,
Constant *TheFn,
657 VTableSlotInfo &SlotInfo,
660 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Constant *JT,
663 VTableSlotInfo &SlotInfo,
666 bool tryEvaluateFunctionsWithArgs(
670 void applyUniformRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
673 CallSiteInfo &CSInfo,
681 bool shouldExportConstantsAsAbsoluteSymbols();
701 void applyUniqueRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
bool IsOne,
703 bool tryUniqueRetValOpt(
unsigned BitWidth,
705 CallSiteInfo &CSInfo,
709 void applyVirtualConstProp(CallSiteInfo &CSInfo,
StringRef FnName,
712 VTableSlotInfo &SlotInfo,
718 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
722 void removeRedundantTypeTests();
755 std::set<GlobalValue::GUID> &ExportedGUIDs;
759 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
763 PatternList FunctionsToSkip;
767 std::set<GlobalValue::GUID> &ExportedGUIDs,
768 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap)
769 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
770 LocalWPDTargetsMap(LocalWPDTargetsMap) {
774 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
780 VTableSlotInfo &SlotInfo,
782 std::set<ValueInfo> &DevirtTargets);
800 if (UseCommandLine) {
801 if (!DevirtModule::runForTesting(M, AARGetter, OREGetter, LookupDomTree))
805 if (!DevirtModule(M, AARGetter, OREGetter, LookupDomTree, ExportSummary,
825 if (
TypeID.ends_with(
".virtual"))
831 if (!
TypeID.consume_front(
"_ZTS"))
839 std::string typeInfo = (
"_ZTI" +
TypeID).str();
840 return IsVisibleToRegularObj(typeInfo);
849 for (
auto Type : Types)
850 if (
auto *
TypeID = dyn_cast<MDString>(
Type->getOperand(1).get()))
852 IsVisibleToRegularObj);
861 Module &M,
bool WholeProgramVisibilityEnabledInLTO,
863 bool ValidateAllVtablesHaveTypeInfos,
880 !(ValidateAllVtablesHaveTypeInfos &&
887 bool WholeProgramVisibilityEnabledInLTO) {
890 if (!PublicTypeTestFunc)
896 auto *CI = cast<CallInst>(U.getUser());
898 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {},
"",
900 CI->replaceAllUsesWith(NewCI);
901 CI->eraseFromParent();
906 auto *CI = cast<CallInst>(U.getUser());
907 CI->replaceAllUsesWith(True);
908 CI->eraseFromParent();
919 for (
const auto &typeID : Index.typeIdCompatibleVtableMap()) {
922 VisibleToRegularObjSymbols.
insert(
P.VTableVI.getGUID());
935 for (
auto &
P : Index) {
938 if (DynamicExportSymbols.
count(
P.first))
940 for (
auto &S :
P.second.SummaryList) {
941 auto *GVar = dyn_cast<GlobalVarSummary>(S.get());
949 if (VisibleToRegularObjSymbols.
count(
P.first))
958 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
959 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap).run();
965 std::map<
ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
966 for (
auto &
T : LocalWPDTargetsMap) {
969 assert(VI.getSummaryList().size() == 1 &&
970 "Devirt of local target has more than one copy");
971 auto &S = VI.getSummaryList()[0];
972 if (!isExported(S->modulePath(), VI))
976 for (
auto &SlotSummary :
T.second) {
977 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
979 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
980 assert(WPDRes != TIdSum->WPDRes.end());
982 WPDRes->second.SingleImplName,
983 Summary.getModuleHash(S->modulePath()));
993 const auto &ModPaths = Summary->modulePaths();
998 "combined summary should contain Regular LTO module");
1002bool DevirtModule::runForTesting(
1006 std::unique_ptr<ModuleSummaryIndex>
Summary =
1007 std::make_unique<ModuleSummaryIndex>(
false);
1014 auto ReadSummaryFile =
1016 if (
Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1018 Summary = std::move(*SummaryOrErr);
1023 yaml::Input
In(ReadSummaryFile->getBuffer());
1030 DevirtModule(M, AARGetter, OREGetter, LookupDomTree,
1048 yaml::Output Out(
OS);
1056void DevirtModule::buildTypeIdentifierMap(
1057 std::vector<VTableBits> &Bits,
1060 Bits.reserve(
M.global_size());
1070 Bits.emplace_back();
1071 Bits.back().GV = &GV;
1072 Bits.back().ObjectSize =
1074 BitsPtr = &
Bits.back();
1082 cast<ConstantAsMetadata>(
Type->getOperand(0))->getValue())
1090bool DevirtModule::tryFindVirtualCallTargets(
1091 std::vector<VirtualCallTarget> &TargetsForSlot,
1092 const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset,
1095 if (!
TM.Bits->GV->isConstant())
1100 if (
TM.Bits->GV->getVCallVisibility() ==
1112 if (FunctionsToSkip.match(Fn->
getName()))
1117 if (Fn->
getName() ==
"__cxa_pure_virtual")
1127 auto GV = dyn_cast<GlobalValue>(
C);
1129 TargetsForSlot.push_back({GV, &
TM});
1133 return !TargetsForSlot.empty();
1136bool DevirtIndex::tryFindVirtualCallTargets(
1137 std::vector<ValueInfo> &TargetsForSlot,
1151 bool LocalFound =
false;
1152 for (
const auto &S :
P.VTableVI.getSummaryList()) {
1158 auto *CurVS = cast<GlobalVarSummary>(S->getBaseObject());
1159 if (!CurVS->vTableFuncs().empty() ||
1181 for (
auto VTP :
VS->vTableFuncs()) {
1182 if (VTP.VTableOffset !=
P.AddressPointOffset + ByteOffset)
1188 TargetsForSlot.push_back(VTP.FuncVI);
1193 return !TargetsForSlot.empty();
1196void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1197 Constant *TheFn,
bool &IsExported) {
1203 for (
auto &&VCallSite : CSInfo.CallSites) {
1204 if (!OptimizedCalls.
insert(&VCallSite.CB).second)
1213 VCallSite.emitRemark(
"single-impl",
1217 auto &CB = VCallSite.CB;
1230 Builder.SetInsertPoint(ThenTerm);
1233 auto *CallTrap = Builder.CreateCall(TrapFn);
1250 NewInst.
setMetadata(LLVMContext::MD_prof,
nullptr);
1251 NewInst.
setMetadata(LLVMContext::MD_callees,
nullptr);
1273 CallsWithPtrAuthBundleRemoved.
push_back(&CB);
1278 if (VCallSite.NumUnsafeUses)
1279 --*VCallSite.NumUnsafeUses;
1281 if (CSInfo.isExported())
1283 CSInfo.markDevirt();
1285 Apply(SlotInfo.CSInfo);
1286 for (
auto &
P : SlotInfo.ConstCSInfo)
1292 if (Callee.getSummaryList().empty())
1299 bool IsExported =
false;
1300 auto &S = Callee.getSummaryList()[0];
1304 for (
auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1305 FS->addCall({Callee, CI});
1306 IsExported |= S->modulePath() != FS->modulePath();
1308 for (
auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1309 FS->addCall({Callee, CI});
1310 IsExported |= S->modulePath() != FS->modulePath();
1314 for (
auto &
P : SlotInfo.ConstCSInfo)
1319bool DevirtModule::trySingleImplDevirt(
1325 auto *TheFn = TargetsForSlot[0].Fn;
1326 for (
auto &&
Target : TargetsForSlot)
1332 TargetsForSlot[0].WasDevirt =
true;
1334 bool IsExported =
false;
1335 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1342 if (TheFn->hasLocalLinkage()) {
1343 std::string NewName = (TheFn->
getName() +
".llvm.merged").str();
1348 if (
Comdat *
C = TheFn->getComdat()) {
1349 if (
C->getName() == TheFn->
getName()) {
1350 Comdat *NewC =
M.getOrInsertComdat(NewName);
1353 if (GO.getComdat() ==
C)
1375 VTableSlotInfo &SlotInfo,
1377 std::set<ValueInfo> &DevirtTargets) {
1380 auto TheFn = TargetsForSlot[0];
1381 for (
auto &&
Target : TargetsForSlot)
1386 auto Size = TheFn.getSummaryList().size();
1392 if (FunctionsToSkip.match(TheFn.name()))
1397 for (
const auto &S : TheFn.getSummaryList())
1403 DevirtTargets.insert(TheFn);
1405 auto &S = TheFn.getSummaryList()[0];
1406 bool IsExported =
AddCalls(SlotInfo, TheFn);
1408 ExportedGUIDs.insert(TheFn.getGUID());
1419 TheFn.name(), ExportSummary.
getModuleHash(S->modulePath()));
1421 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1435void DevirtModule::tryICallBranchFunnel(
1445 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1447 for (
auto &
P : SlotInfo.ConstCSInfo)
1448 if (!
P.second.AllCallSitesDevirted) {
1449 HasNonDevirt =
true;
1459 if (isa<MDString>(
Slot.TypeID)) {
1461 M.getDataLayout().getProgramAddressSpace(),
1462 getGlobalName(Slot, {},
"branch_funnel"), &M);
1466 M.getDataLayout().getProgramAddressSpace(),
1467 "branch_funnel", &M);
1469 JT->addParamAttr(0, Attribute::Nest);
1471 std::vector<Value *> JTArgs;
1472 JTArgs.push_back(
JT->arg_begin());
1473 for (
auto &
T : TargetsForSlot) {
1474 JTArgs.push_back(getMemberAddr(
T.TM));
1475 JTArgs.push_back(
T.Fn);
1480 &M, llvm::Intrinsic::icall_branch_funnel, {});
1486 bool IsExported =
false;
1487 applyICallBranchFunnel(SlotInfo, JT, IsExported);
1492void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1495 if (CSInfo.isExported())
1497 if (CSInfo.AllCallSitesDevirted)
1500 std::map<CallBase *, CallBase *> CallBases;
1501 for (
auto &&VCallSite : CSInfo.CallSites) {
1504 if (CallBases.find(&CB) != CallBases.end()) {
1521 VCallSite.emitRemark(
"branch-funnel",
1522 JT->stripPointerCasts()->getName(), OREGetter);
1526 std::vector<Type *> NewArgs;
1527 NewArgs.push_back(Int8PtrTy);
1535 std::vector<Value *>
Args;
1536 Args.push_back(VCallSite.VTable);
1540 if (isa<CallInst>(CB))
1541 NewCS = IRB.CreateCall(NewFT, IRB.CreateBitCast(JT, NewFTPtr), Args);
1543 NewCS = IRB.CreateInvoke(NewFT, IRB.CreateBitCast(JT, NewFTPtr),
1544 cast<InvokeInst>(CB).getNormalDest(),
1545 cast<InvokeInst>(CB).getUnwindDest(), Args);
1549 std::vector<AttributeSet> NewArgAttrs;
1552 M.getContext(), Attribute::Nest)}));
1553 for (
unsigned I = 0;
I + 2 <
Attrs.getNumAttrSets(); ++
I)
1554 NewArgAttrs.push_back(
Attrs.getParamAttrs(
I));
1557 Attrs.getRetAttrs(), NewArgAttrs));
1559 CallBases[&CB] = NewCS;
1562 if (VCallSite.NumUnsafeUses)
1563 --*VCallSite.NumUnsafeUses;
1570 for (
auto &[Old, New] : CallBases) {
1572 Old->eraseFromParent();
1575 Apply(SlotInfo.CSInfo);
1576 for (
auto &
P : SlotInfo.ConstCSInfo)
1580bool DevirtModule::tryEvaluateFunctionsWithArgs(
1589 auto Fn = dyn_cast<Function>(
Target.Fn);
1600 for (
unsigned I = 0;
I !=
Args.size(); ++
I) {
1605 EvalArgs.
push_back(ConstantInt::get(ArgTy, Args[
I]));
1609 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1610 !isa<ConstantInt>(RetVal))
1612 Target.RetVal = cast<ConstantInt>(RetVal)->getZExtValue();
1617void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
1619 for (
auto Call : CSInfo.CallSites) {
1623 Call.replaceAndErase(
1624 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1625 ConstantInt::get(cast<IntegerType>(
Call.CB.getType()), TheRetVal));
1627 CSInfo.markDevirt();
1630bool DevirtModule::tryUniformRetValOpt(
1635 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1637 if (
Target.RetVal != TheRetVal)
1640 if (CSInfo.isExported()) {
1642 Res->
Info = TheRetVal;
1645 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), TheRetVal);
1647 for (
auto &&
Target : TargetsForSlot)
1652std::string DevirtModule::getGlobalName(VTableSlot Slot,
1655 std::string FullName =
"__typeid_";
1657 OS << cast<MDString>(
Slot.TypeID)->getString() <<
'_' <<
Slot.ByteOffset;
1664bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1672 getGlobalName(Slot, Args,
Name),
C, &M);
1679 if (shouldExportConstantsAsAbsoluteSymbols()) {
1692 M.getOrInsertGlobal(getGlobalName(Slot, Args,
Name), Int8Arr0Ty);
1693 auto *GV = dyn_cast<GlobalVariable>(
C);
1702 if (!shouldExportConstantsAsAbsoluteSymbols())
1703 return ConstantInt::get(IntTy, Storage);
1706 auto *GV = cast<GlobalVariable>(
C->stripPointerCasts());
1711 if (GV->
hasMetadata(LLVMContext::MD_absolute_symbol))
1722 SetAbsRange(~0ull, ~0ull);
1724 SetAbsRange(0, 1ull << AbsWidth);
1728void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
1731 for (
auto &&Call : CSInfo.CallSites) {
1737 B.CreateBitCast(UniqueMemberAddr,
Call.VTable->getType()));
1738 Cmp =
B.CreateZExt(Cmp,
Call.CB.getType());
1740 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1743 CSInfo.markDevirt();
1748 ConstantInt::get(Int64Ty,
M->Offset));
1751bool DevirtModule::tryUniqueRetValOpt(
1756 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1759 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1762 UniqueMember =
Target.TM;
1770 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1771 if (CSInfo.isExported()) {
1775 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1779 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->
getName(), IsOne,
1784 for (
auto &&
Target : TargetsForSlot)
1791 if (tryUniqueRetValOptFor(
true))
1793 if (tryUniqueRetValOptFor(
false))
1799void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo,
StringRef FnName,
1801 for (
auto Call : CSInfo.CallSites) {
1804 auto *RetType = cast<IntegerType>(
Call.CB.getType());
1807 if (RetType->getBitWidth() == 1) {
1809 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1810 auto IsBitSet =
B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1811 NumVirtConstProp1Bit++;
1812 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1813 OREGetter, IsBitSet);
1817 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1821 CSInfo.markDevirt();
1824bool DevirtModule::tryVirtualConstProp(
1830 auto Fn = dyn_cast<Function>(TargetsForSlot[0].Fn);
1837 unsigned BitWidth = RetType->getBitWidth();
1855 auto Fn = dyn_cast<Function>(
Target.Fn);
1861 .doesNotAccessMemory() ||
1867 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1868 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1873 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1875 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1878 if (tryUniqueRetValOpt(
BitWidth, TargetsForSlot, CSByConstantArg.second,
1879 ResByArg, Slot, CSByConstantArg.first))
1891 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1892 for (
auto &&
Target : TargetsForSlot) {
1893 TotalPaddingBefore += std::max<int64_t>(
1894 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1895 TotalPaddingAfter += std::max<int64_t>(
1896 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1901 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1908 if (TotalPaddingBefore <= TotalPaddingAfter)
1916 for (
auto &&
Target : TargetsForSlot)
1920 if (CSByConstantArg.second.isExported()) {
1922 exportConstant(Slot, CSByConstantArg.first,
"byte", OffsetByte,
1924 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
1929 Constant *ByteConst = ConstantInt::get(Int32Ty, OffsetByte);
1930 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
1931 applyVirtualConstProp(CSByConstantArg.second,
1932 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
1938 if (
B.Before.Bytes.empty() &&
B.After.Bytes.empty())
1943 Align Alignment =
M.getDataLayout().getValueOrABITypeAlignment(
1944 B.GV->getAlign(),
B.GV->getValueType());
1945 B.Before.Bytes.resize(
alignTo(
B.Before.Bytes.size(), Alignment));
1948 for (
size_t I = 0,
Size =
B.Before.Bytes.size();
I !=
Size / 2; ++
I)
1955 B.GV->getInitializer(),
1960 NewGV->setSection(
B.GV->getSection());
1961 NewGV->setComdat(
B.GV->getComdat());
1962 NewGV->setAlignment(
B.GV->getAlign());
1966 NewGV->copyMetadata(
B.GV,
B.Before.Bytes.size());
1971 B.GV->getInitializer()->getType(), 0,
B.GV->getLinkage(),
"",
1973 NewInit->getType(), NewGV,
1975 ConstantInt::get(Int32Ty, 1)}),
1977 Alias->setVisibility(
B.GV->getVisibility());
1978 Alias->takeName(
B.GV);
1980 B.GV->replaceAllUsesWith(Alias);
1981 B.GV->eraseFromParent();
1984bool DevirtModule::areRemarksEnabled() {
1985 const auto &FL =
M.getFunctionList();
1990 return DI.isEnabled();
1995void DevirtModule::scanTypeTestUsers(
2004 auto *CI = dyn_cast<CallInst>(
U.getUser());
2011 auto &DT = LookupDomTree(*CI->getFunction());
2015 cast<MetadataAsValue>(CI->getArgOperand(1))->getMetadata();
2017 if (!Assumes.
empty()) {
2018 Value *
Ptr = CI->getArgOperand(0)->stripPointerCasts();
2020 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
nullptr);
2023 auto RemoveTypeTestAssumes = [&]() {
2025 for (
auto *Assume : Assumes)
2026 Assume->eraseFromParent();
2029 if (CI->use_empty())
2030 CI->eraseFromParent();
2045 if (!TypeIdMap.count(TypeId))
2046 RemoveTypeTestAssumes();
2057 else if (ImportSummary && isa<MDString>(TypeId)) {
2061 RemoveTypeTestAssumes();
2070void DevirtModule::scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc) {
2075 auto *CI = dyn_cast<CallInst>(
U.getUser());
2081 Value *TypeIdValue = CI->getArgOperand(2);
2082 Metadata *TypeId = cast<MetadataAsValue>(TypeIdValue)->getMetadata();
2087 bool HasNonCallUses =
false;
2088 auto &DT = LookupDomTree(*CI->getFunction());
2090 HasNonCallUses, CI, DT);
2099 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2101 Value *LoadedValue =
nullptr;
2103 Intrinsic::type_checked_load_relative) {
2105 LoadedValue = LoadB.CreateLoad(Int32Ty,
GEP);
2106 LoadedValue = LoadB.CreateSExt(LoadedValue, IntPtrTy);
2107 GEP = LoadB.CreatePtrToInt(
GEP, IntPtrTy);
2108 LoadedValue = LoadB.CreateAdd(
GEP, LoadedValue);
2109 LoadedValue = LoadB.CreateIntToPtr(LoadedValue, Int8PtrTy);
2112 LoadedValue = LoadB.CreateLoad(Int8PtrTy,
GEP);
2117 LoadedPtr->eraseFromParent();
2121 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2122 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {
Ptr, TypeIdValue});
2126 Pred->eraseFromParent();
2133 if (!CI->use_empty()) {
2136 Pair =
B.CreateInsertValue(Pair, LoadedValue, {0});
2137 Pair =
B.CreateInsertValue(Pair, TypeTestCall, {1});
2138 CI->replaceAllUsesWith(Pair);
2142 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2143 NumUnsafeUses = DevirtCalls.
size();
2151 CallSlots[{TypeId,
Call.Offset}].addCallSite(
Ptr,
Call.CB,
2155 CI->eraseFromParent();
2159void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2160 auto *TypeId = dyn_cast<MDString>(
Slot.TypeID);
2167 auto ResI = TidSummary->
WPDRes.find(
Slot.ByteOffset);
2168 if (ResI == TidSummary->
WPDRes.end())
2182 bool IsExported =
false;
2183 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2187 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2188 auto I = Res.
ResByArg.find(CSByConstantArg.first);
2191 auto &ResByArg =
I->second;
2198 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info);
2202 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
2203 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.
Info,
2208 Constant *
Byte = importConstant(Slot, CSByConstantArg.first,
"byte",
2209 Int32Ty, ResByArg.
Byte);
2210 Constant *
Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
2212 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
2224 M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
2227 bool IsExported =
false;
2228 applyICallBranchFunnel(SlotInfo, JT, IsExported);
2233void DevirtModule::removeRedundantTypeTests() {
2235 for (
auto &&U : NumUnsafeUsesForTypeTest) {
2236 if (
U.second == 0) {
2237 U.first->replaceAllUsesWith(True);
2238 U.first->eraseFromParent();
2244DevirtModule::lookUpFunctionValueInfo(
Function *TheFn,
2246 assert((ExportSummary !=
nullptr) &&
2247 "Caller guarantees ExportSummary is not nullptr");
2249 const auto TheFnGUID = TheFn->
getGUID();
2261 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2262 TheFnVI = ExportSummary->
getValueInfo(TheFnGUIDWithExportedName);
2267bool DevirtModule::mustBeUnreachableFunction(
2272 if (!
F->isDeclaration()) {
2275 return isa<UnreachableInst>(
F->getEntryBlock().getTerminator());
2278 return ExportSummary &&
2280 DevirtModule::lookUpFunctionValueInfo(
F, ExportSummary));
2283bool DevirtModule::run() {
2297 &M, Intrinsic::type_checked_load_relative);
2304 if (!ExportSummary &&
2305 (!TypeTestFunc || TypeTestFunc->
use_empty() || !AssumeFunc ||
2307 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()) &&
2308 (!TypeCheckedLoadRelativeFunc ||
2309 TypeCheckedLoadRelativeFunc->
use_empty()))
2313 std::vector<VTableBits>
Bits;
2315 buildTypeIdentifierMap(Bits, TypeIdMap);
2317 if (TypeTestFunc && AssumeFunc)
2318 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2320 if (TypeCheckedLoadFunc)
2321 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2323 if (TypeCheckedLoadRelativeFunc)
2324 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2326 if (ImportSummary) {
2327 for (
auto &S : CallSlots)
2328 importResolution(S.first, S.second);
2330 removeRedundantTypeTests();
2343 if (TypeIdMap.
empty())
2347 if (ExportSummary) {
2349 for (
auto &
P : TypeIdMap) {
2350 if (
auto *TypeId = dyn_cast<MDString>(
P.first))
2355 for (
auto &
P : *ExportSummary) {
2356 for (
auto &S :
P.second.SummaryList) {
2357 auto *
FS = dyn_cast<FunctionSummary>(S.get());
2362 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2363 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2367 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
2368 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2372 FS->type_test_assume_const_vcalls()) {
2373 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2374 CallSlots[{MD,
VC.VFunc.Offset}]
2375 .ConstCSInfo[
VC.Args]
2376 .addSummaryTypeTestAssumeUser(FS);
2380 FS->type_checked_load_const_vcalls()) {
2381 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
2382 CallSlots[{MD,
VC.VFunc.Offset}]
2383 .ConstCSInfo[
VC.Args]
2384 .addSummaryTypeCheckedLoadUser(FS);
2392 bool DidVirtualConstProp =
false;
2393 std::map<std::string, GlobalValue *> DevirtTargets;
2394 for (
auto &S : CallSlots) {
2398 std::vector<VirtualCallTarget> TargetsForSlot;
2400 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2401 if (ExportSummary && isa<MDString>(S.first.TypeID) &&
2402 TypeMemberInfos.size())
2409 Res = &ExportSummary
2410 ->getOrInsertTypeIdSummary(
2411 cast<MDString>(S.first.TypeID)->getString())
2412 .WPDRes[S.first.ByteOffset];
2413 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2414 S.first.ByteOffset, ExportSummary)) {
2416 if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res)) {
2417 DidVirtualConstProp |=
2418 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2420 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2425 for (
const auto &
T : TargetsForSlot)
2427 DevirtTargets[std::string(
T.Fn->getName())] =
T.Fn;
2434 if (ExportSummary && isa<MDString>(S.first.TypeID)) {
2437 for (
auto *FS : S.second.CSInfo.SummaryTypeCheckedLoadUsers)
2438 FS->addTypeTest(GUID);
2439 for (
auto &CCS : S.second.ConstCSInfo)
2440 for (
auto *FS : CCS.second.SummaryTypeCheckedLoadUsers)
2441 FS->addTypeTest(GUID);
2445 if (RemarksEnabled) {
2447 for (
const auto &DT : DevirtTargets) {
2449 auto F = dyn_cast<Function>(GV);
2451 auto A = dyn_cast<GlobalAlias>(GV);
2452 assert(
A && isa<Function>(
A->getAliasee()));
2453 F = dyn_cast<Function>(
A->getAliasee());
2457 using namespace ore;
2460 <<
NV(
"FunctionName", DT.first));
2464 NumDevirtTargets += DevirtTargets.size();
2466 removeRedundantTypeTests();
2470 if (DidVirtualConstProp)
2480 for (
auto *CI : CallsWithPtrAuthBundleRemoved)
2481 CI->eraseFromParent();
2486void DevirtIndex::run() {
2487 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2491 for (
const auto &
P : ExportSummary.typeIdCompatibleVtableMap()) {
2499 ExportSummary.getOrInsertTypeIdSummary(
P.first);
2503 for (
auto &
P : ExportSummary) {
2504 for (
auto &S :
P.second.SummaryList) {
2505 auto *
FS = dyn_cast<FunctionSummary>(S.get());
2511 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2516 CallSlots[{
Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2520 FS->type_test_assume_const_vcalls()) {
2522 CallSlots[{
Name,
VC.VFunc.Offset}]
2523 .ConstCSInfo[
VC.Args]
2524 .addSummaryTypeTestAssumeUser(FS);
2528 FS->type_checked_load_const_vcalls()) {
2530 CallSlots[{
Name,
VC.VFunc.Offset}]
2531 .ConstCSInfo[
VC.Args]
2532 .addSummaryTypeCheckedLoadUser(FS);
2538 std::set<ValueInfo> DevirtTargets;
2540 for (
auto &S : CallSlots) {
2544 std::vector<ValueInfo> TargetsForSlot;
2545 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2550 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2551 ->WPDRes[S.first.ByteOffset];
2552 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2553 S.first.ByteOffset)) {
2555 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2564 for (
const auto &DT : DevirtTargets)
2565 errs() <<
"Devirtualized call to " << DT <<
"\n";
2567 NumDevirtTargets += DevirtTargets.size();
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.
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
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< 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 bool AddCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee)
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 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, 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 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.
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 Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getInBoundsGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList)
Create an "inbounds" getelementptr.
static Constant * 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 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 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.
Type * getParamType(unsigned i) const
Parameter type accessors.
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)
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 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.
VCallVisibility getVCallVisibility() const
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.
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)
static GUID getGUID(StringRef GlobalName)
Return a 64-bit global unique ID constructed from global value name (i.e.
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.
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.
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
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.
MDNode * createLikelyBranchWeights()
Return metadata containing two branch weights, with significant bias towards true 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,...
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, 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 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.
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.
Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
Function * getDeclarationIfExists(Module *M, ID id, ArrayRef< Type * > Tys, FunctionType *FT=nullptr)
This version supports overloaded intrinsics.
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 '.
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.
@ 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.
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.
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 ...
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...
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 ...
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)