93 #define DEBUG_TYPE "wholeprogramdevirt" 96 "wholeprogramdevirt-summary-action",
97 cl::desc(
"What to do with the summary when running this pass"),
100 "Import typeid resolutions from summary and globals"),
102 "Export typeid resolutions to summary and globals")),
106 "wholeprogramdevirt-read-summary",
107 cl::desc(
"Read summary from given YAML file before running pass"),
111 "wholeprogramdevirt-write-summary",
112 cl::desc(
"Write summary to given YAML file after running pass"),
118 cl::desc(
"Maximum number of call targets per " 119 "call site to enable branch funnels"));
126 bool IsAfter, uint64_t
Size) {
128 uint64_t MinByte = 0;
156 std::vector<ArrayRef<uint8_t>> Used;
159 :
Target.TM->Bits->Before.BytesUsed;
160 uint64_t
Offset = IsAfter ? MinByte -
Target.minAfterBytes()
161 : MinByte -
Target.minBeforeBytes();
166 Used.push_back(VTUsed.
slice(Offset));
171 for (
unsigned I = 0;; ++
I) {
172 uint8_t BitsUsed = 0;
173 for (
auto &&
B : Used)
176 if (BitsUsed != 0xff)
177 return (MinByte +
I) * 8 +
183 for (
unsigned I = 0;; ++
I) {
184 for (
auto &&
B : Used) {
186 while ((
I + Byte) <
B.size() && Byte < (Size / 8)) {
192 return (MinByte +
I) * 8;
200 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
202 OffsetByte = -(AllocBefore / 8 + 1);
204 OffsetByte = -((AllocBefore + 7) / 8 + (BitWidth + 7) / 8);
205 OffsetBit = AllocBefore % 8;
209 Target.setBeforeBit(AllocBefore);
211 Target.setBeforeBytes(AllocBefore, (BitWidth + 7) / 8);
217 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
219 OffsetByte = AllocAfter / 8;
221 OffsetByte = (AllocAfter + 7) / 8;
222 OffsetBit = AllocAfter % 8;
226 Target.setAfterBit(AllocAfter);
228 Target.setAfterBytes(AllocAfter, (BitWidth + 7) / 8);
234 IsBigEndian(Fn->
getParent()->getDataLayout().isBigEndian()), WasDevirt(
false) {}
264 const VTableSlot &RHS) {
265 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
275 struct VirtualCallSite {
282 unsigned *NumUnsafeUses;
293 <<
NV(
"Optimization", OptName)
294 <<
": devirtualized a call to " 295 <<
NV(
"FunctionName", TargetName));
298 void replaceAndErase(
303 emitRemark(OptName, TargetName, OREGetter);
304 CS->replaceAllUsesWith(New);
307 II->getUnwindDest()->removePredecessor(II->getParent());
309 CS->eraseFromParent();
319 struct CallSiteInfo {
324 std::vector<VirtualCallSite> CallSites;
329 bool AllCallSitesDevirted =
true;
336 bool SummaryHasTypeTestAssumeUsers =
false;
345 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
347 bool isExported()
const {
348 return SummaryHasTypeTestAssumeUsers ||
349 !SummaryTypeCheckedLoadUsers.empty();
352 void markSummaryHasTypeTestAssumeUsers() {
353 SummaryHasTypeTestAssumeUsers =
true;
354 AllCallSitesDevirted =
false;
358 SummaryTypeCheckedLoadUsers.push_back(FS);
359 AllCallSitesDevirted =
false;
363 AllCallSitesDevirted =
true;
366 SummaryTypeCheckedLoadUsers.clear();
371 struct VTableSlotInfo {
378 std::map<std::vector<uint64_t>, CallSiteInfo> ConstCSInfo;
380 void addCallSite(
Value *VTable,
CallSite CS,
unsigned *NumUnsafeUses);
383 CallSiteInfo &findCallSiteInfo(
CallSite CS);
386 CallSiteInfo &VTableSlotInfo::findCallSiteInfo(
CallSite CS) {
387 std::vector<uint64_t>
Args;
389 if (!CI || CI->getBitWidth() > 64 || CS.
arg_empty())
393 if (!CI || CI->getBitWidth() > 64)
395 Args.push_back(CI->getZExtValue());
397 return ConstCSInfo[
Args];
401 unsigned *NumUnsafeUses) {
402 auto &CSI = findCallSiteInfo(CS);
403 CSI.AllCallSitesDevirted =
false;
404 CSI.CallSites.push_back({VTable, CS, NumUnsafeUses});
407 struct DevirtModule {
434 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
441 : M(M), AARGetter(AARGetter), LookupDomTree(LookupDomTree),
442 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
448 RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter) {
449 assert(!(ExportSummary && ImportSummary));
452 bool areRemarksEnabled();
455 void scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc);
457 void buildTypeIdentifierMap(
458 std::vector<VTableBits> &
Bits,
462 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
463 const std::set<TypeMemberInfo> &TypeMemberInfos,
464 uint64_t ByteOffset);
466 void applySingleImplDevirt(VTableSlotInfo &SlotInfo,
Constant *TheFn,
469 VTableSlotInfo &SlotInfo,
472 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Constant *
JT,
475 VTableSlotInfo &SlotInfo,
478 bool tryEvaluateFunctionsWithArgs(
482 void applyUniformRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
485 CallSiteInfo &CSInfo,
493 bool shouldExportConstantsAsAbsoluteSymbols();
513 void applyUniqueRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
bool IsOne,
515 bool tryUniqueRetValOpt(
unsigned BitWidth,
517 CallSiteInfo &CSInfo,
521 void applyVirtualConstProp(CallSiteInfo &CSInfo,
StringRef FnName,
524 VTableSlotInfo &SlotInfo,
530 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
534 void removeRedundantTypeTests();
546 struct WholeProgramDevirt :
public ModulePass {
549 bool UseCommandLine =
false;
554 WholeProgramDevirt() :
ModulePass(ID), UseCommandLine(
true) {
560 :
ModulePass(ID), ExportSummary(ExportSummary),
561 ImportSummary(ImportSummary) {
565 bool runOnModule(
Module &M)
override {
574 std::unique_ptr<OptimizationRemarkEmitter> ORE;
576 ORE = make_unique<OptimizationRemarkEmitter>(
F);
581 return this->getAnalysis<DominatorTreeWrapperPass>(
F).getDomTree();
585 return DevirtModule::runForTesting(M,
LegacyAARGetter(*
this), OREGetter,
588 return DevirtModule(M,
LegacyAARGetter(*
this), OREGetter, LookupDomTree,
589 ExportSummary, ImportSummary)
603 "Whole program devirtualization",
false,
false)
609 char WholeProgramDevirt::
ID = 0;
614 return new WholeProgramDevirt(ExportSummary, ImportSummary);
629 if (!DevirtModule(M, AARGetter, OREGetter, LookupDomTree, ExportSummary,
636 bool DevirtModule::runForTesting(
647 auto ReadSummaryFile =
650 yaml::Input
In(ReadSummaryFile->getBuffer());
657 M, AARGetter, OREGetter, LookupDomTree,
669 yaml::Output Out(OS);
676 void DevirtModule::buildTypeIdentifierMap(
677 std::vector<VTableBits> &
Bits,
685 if (GV.isDeclaration() || Types.
empty())
691 Bits.back().GV = &GV;
692 Bits.back().ObjectSize =
694 BitsPtr = &Bits.back();
702 cast<ConstantAsMetadata>(
Type->getOperand(0))->getValue())
705 TypeIdMap[
TypeID].insert({BitsPtr, Offset});
719 if (
auto *
C = dyn_cast<ConstantStruct>(I)) {
725 return getPointerAtOffset(cast<Constant>(I->
getOperand(Op)),
728 if (
auto *
C = dyn_cast<ConstantArray>(I)) {
732 unsigned Op = Offset / ElemSize;
736 return getPointerAtOffset(cast<Constant>(I->
getOperand(Op)),
742 bool DevirtModule::tryFindVirtualCallTargets(
743 std::vector<VirtualCallTarget> &TargetsForSlot,
744 const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset) {
760 if (
Fn->
getName() ==
"__cxa_pure_virtual")
763 TargetsForSlot.push_back({
Fn, &
TM});
767 return !TargetsForSlot.
empty();
770 void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
771 Constant *TheFn,
bool &IsExported) {
772 auto Apply = [&](CallSiteInfo &CSInfo) {
773 for (
auto &&VCallSite : CSInfo.CallSites) {
775 VCallSite.emitRemark(
"single-impl",
778 TheFn, VCallSite.CS.getCalledValue()->
getType()));
780 if (VCallSite.NumUnsafeUses)
781 --*VCallSite.NumUnsafeUses;
783 if (CSInfo.isExported())
787 Apply(SlotInfo.CSInfo);
788 for (
auto &
P : SlotInfo.ConstCSInfo)
792 bool DevirtModule::trySingleImplDevirt(
797 Function *TheFn = TargetsForSlot[0].Fn;
798 for (
auto &&
Target : TargetsForSlot)
804 TargetsForSlot[0].WasDevirt =
true;
806 bool IsExported =
false;
807 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
815 std::string NewName = (TheFn->
getName() +
"$merged").str();
825 if (GO.getComdat() ==
C)
841 void DevirtModule::tryICallBranchFunnel(
851 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
853 for (
auto &
P : SlotInfo.ConstCSInfo)
854 if (!
P.second.AllCallSitesDevirted) {
865 if (isa<MDString>(Slot.TypeID)) {
868 getGlobalName(Slot, {},
"branch_funnel"), &M);
873 "branch_funnel", &M);
877 std::vector<Value *> JTArgs;
878 JTArgs.push_back(JT->arg_begin());
879 for (
auto &
T : TargetsForSlot) {
880 JTArgs.push_back(getMemberAddr(
T.TM));
881 JTArgs.push_back(
T.Fn);
892 bool IsExported =
false;
893 applyICallBranchFunnel(SlotInfo, JT, IsExported);
898 void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
900 auto Apply = [&](CallSiteInfo &CSInfo) {
901 if (CSInfo.isExported())
903 if (CSInfo.AllCallSitesDevirted)
905 for (
auto &&VCallSite : CSInfo.CallSites) {
915 VCallSite.emitRemark(
"branch-funnel",
920 std::vector<Type *> NewArgs;
921 NewArgs.push_back(Int8PtrTy);
923 NewArgs.push_back(
T);
929 std::vector<Value *>
Args;
930 Args.push_back(IRB.CreateBitCast(VCallSite.VTable, Int8PtrTy));
936 NewCS = IRB.CreateCall(IRB.CreateBitCast(JT, NewFT),
Args);
938 NewCS = IRB.CreateInvoke(
939 IRB.CreateBitCast(JT, NewFT),
945 std::vector<AttributeSet> NewArgAttrs;
956 CS->eraseFromParent();
959 if (VCallSite.NumUnsafeUses)
960 --*VCallSite.NumUnsafeUses;
967 Apply(SlotInfo.CSInfo);
968 for (
auto &
P : SlotInfo.ConstCSInfo)
972 bool DevirtModule::tryEvaluateFunctionsWithArgs(
985 for (
unsigned I = 0; I != Args.
size(); ++
I) {
987 Target.Fn->getFunctionType()->getParamType(I + 1));
994 if (!Eval.EvaluateFunction(
Target.Fn, RetVal, EvalArgs) ||
995 !isa<ConstantInt>(
RetVal))
997 Target.RetVal = cast<ConstantInt>(
RetVal)->getZExtValue();
1002 void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
1003 uint64_t TheRetVal) {
1004 for (
auto Call : CSInfo.CallSites)
1005 Call.replaceAndErase(
1006 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1008 CSInfo.markDevirt();
1011 bool DevirtModule::tryUniformRetValOpt(
1016 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1018 if (
Target.RetVal != TheRetVal)
1021 if (CSInfo.isExported()) {
1023 Res->
Info = TheRetVal;
1026 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].
Fn->
getName(), TheRetVal);
1028 for (
auto &&
Target : TargetsForSlot)
1033 std::string DevirtModule::getGlobalName(VTableSlot Slot,
1036 std::string FullName =
"__typeid_";
1038 OS << cast<MDString>(Slot.TypeID)->getString() <<
'_' << Slot.ByteOffset;
1039 for (uint64_t
Arg : Args)
1045 bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1054 getGlobalName(Slot, Args, Name), C, &M);
1061 if (shouldExportConstantsAsAbsoluteSymbols()) {
1083 if (!shouldExportConstantsAsAbsoluteSymbols())
1086 Constant *C = importGlobal(Slot, Args, Name);
1095 auto SetAbsRange = [&](uint64_t Min, uint64_t Max) {
1102 if (AbsWidth == IntPtrTy->getBitWidth())
1103 SetAbsRange(~0ull, ~0ull);
1105 SetAbsRange(0, 1ull << AbsWidth);
1109 void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo,
StringRef FnName,
1112 for (
auto &&Call : CSInfo.CallSites) {
1116 B.CreateBitCast(Call.VTable, Int8PtrTy), UniqueMemberAddr);
1117 Cmp =
B.CreateZExt(Cmp, Call.CS->getType());
1118 Call.replaceAndErase(
"unique-ret-val", FnName, RemarksEnabled, OREGetter,
1121 CSInfo.markDevirt();
1130 bool DevirtModule::tryUniqueRetValOpt(
1135 auto tryUniqueRetValOptFor = [&](
bool IsOne) {
1138 if (
Target.RetVal == (IsOne ? 1 : 0)) {
1141 UniqueMember =
Target.TM;
1149 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1150 if (CSInfo.isExported()) {
1154 exportGlobal(Slot, Args,
"unique_member", UniqueMemberAddr);
1158 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].
Fn->
getName(), IsOne,
1163 for (
auto &&
Target : TargetsForSlot)
1169 if (BitWidth == 1) {
1170 if (tryUniqueRetValOptFor(
true))
1172 if (tryUniqueRetValOptFor(
false))
1178 void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo,
StringRef FnName,
1180 for (
auto Call : CSInfo.CallSites) {
1181 auto *RetType = cast<IntegerType>(Call.CS.getType());
1184 B.CreateGEP(Int8Ty,
B.CreateBitCast(Call.VTable, Int8PtrTy), Byte);
1185 if (RetType->getBitWidth() == 1) {
1186 Value *Bits =
B.CreateLoad(Addr);
1187 Value *BitsAndBit =
B.CreateAnd(Bits, Bit);
1189 Call.replaceAndErase(
"virtual-const-prop-1-bit", FnName, RemarksEnabled,
1190 OREGetter, IsBitSet);
1192 Value *ValAddr =
B.CreateBitCast(Addr, RetType->getPointerTo());
1193 Value *Val =
B.CreateLoad(RetType, ValAddr);
1194 Call.replaceAndErase(
"virtual-const-prop", FnName, RemarksEnabled,
1198 CSInfo.markDevirt();
1201 bool DevirtModule::tryVirtualConstProp(
1208 unsigned BitWidth = RetType->getBitWidth();
1223 if (
Target.Fn->isDeclaration() ||
1226 Target.Fn->arg_empty() || !
Target.Fn->arg_begin()->use_empty() ||
1227 Target.Fn->getReturnType() != RetType)
1231 for (
auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1232 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1237 ResByArg = &Res->
ResByArg[CSByConstantArg.first];
1239 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1242 if (tryUniqueRetValOpt(BitWidth, TargetsForSlot, CSByConstantArg.second,
1243 ResByArg, Slot, CSByConstantArg.first))
1248 uint64_t AllocBefore =
1250 uint64_t AllocAfter =
1255 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1256 for (
auto &&
Target : TargetsForSlot) {
1257 TotalPaddingBefore += std::max<int64_t>(
1258 (AllocBefore + 7) / 8 -
Target.allocatedBeforeBytes() - 1, 0);
1259 TotalPaddingAfter += std::max<int64_t>(
1260 (AllocAfter + 7) / 8 -
Target.allocatedAfterBytes() - 1, 0);
1265 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1272 if (TotalPaddingBefore <= TotalPaddingAfter)
1280 for (
auto &&
Target : TargetsForSlot)
1284 if (CSByConstantArg.second.isExported()) {
1286 exportConstant(Slot, CSByConstantArg.first,
"byte", OffsetByte,
1288 exportConstant(Slot, CSByConstantArg.first,
"bit", 1ULL << OffsetBit,
1295 applyVirtualConstProp(CSByConstantArg.second,
1296 TargetsForSlot[0].Fn->
getName(), ByteConst, BitConst);
1306 unsigned PointerSize = M.getDataLayout().getPointerSize();
1335 NewInit->getType(), NewGV,
1340 Alias->takeName(B.
GV);
1346 bool DevirtModule::areRemarksEnabled() {
1347 const auto &FL = M.getFunctionList();
1358 void DevirtModule::scanTypeTestUsers(
Function *TypeTestFunc,
1376 auto &DT = LookupDomTree(*CI->getFunction());
1380 if (!Assumes.
empty()) {
1382 cast<MetadataAsValue>(CI->getArgOperand(1))->getMetadata();
1390 if (SeenCallSites.
insert(Call.CS).second)
1391 CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CS,
nullptr);
1396 for (
auto Assume : Assumes)
1397 Assume->eraseFromParent();
1400 if (CI->use_empty())
1401 CI->eraseFromParent();
1405 void DevirtModule::scanTypeCheckedLoadUsers(
Function *TypeCheckedLoadFunc) {
1408 for (
auto I = TypeCheckedLoadFunc->
use_begin(),
1409 E = TypeCheckedLoadFunc->
use_end();
1416 Value *Ptr = CI->getArgOperand(0);
1417 Value *Offset = CI->getArgOperand(1);
1418 Value *TypeIdValue = CI->getArgOperand(2);
1419 Metadata *TypeId = cast<MetadataAsValue>(TypeIdValue)->getMetadata();
1424 bool HasNonCallUses =
false;
1425 auto &DT = LookupDomTree(*CI->getFunction());
1427 HasNonCallUses, CI, DT);
1436 (LoadedPtrs.
size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
1443 LoadedPtr->eraseFromParent();
1447 IRBuilder<> CallB((Preds.
size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
1452 Pred->eraseFromParent();
1459 if (!CI->use_empty()) {
1462 Pair = B.CreateInsertValue(Pair, LoadedValue, {0});
1463 Pair = B.CreateInsertValue(Pair, TypeTestCall, {1});
1468 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
1469 NumUnsafeUses = DevirtCalls.
size();
1477 CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CS,
1481 CI->eraseFromParent();
1485 void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
1487 ImportSummary->getTypeIdSummary(cast<MDString>(Slot.TypeID)->getString());
1490 auto ResI = TidSummary->
WPDRes.find(Slot.ByteOffset);
1491 if (ResI == TidSummary->
WPDRes.end())
1498 auto *SingleImpl = M.getOrInsertFunction(
1502 bool IsExported =
false;
1503 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
1507 for (
auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
1508 auto I = Res.
ResByArg.find(CSByConstantArg.first);
1511 auto &ResByArg = I->second;
1516 switch (ResByArg.TheKind) {
1518 applyUniformRetValOpt(CSByConstantArg.second,
"", ResByArg.Info);
1522 importGlobal(Slot, CSByConstantArg.first,
"unique_member");
1523 applyUniqueRetValOpt(CSByConstantArg.second,
"", ResByArg.Info,
1528 Constant *Byte = importConstant(Slot, CSByConstantArg.first,
"byte",
1530 Constant *Bit = importConstant(Slot, CSByConstantArg.first,
"bit", Int8Ty,
1532 applyVirtualConstProp(CSByConstantArg.second,
"", Byte, Bit);
1541 auto *JT = M.getOrInsertFunction(getGlobalName(Slot, {},
"branch_funnel"),
1543 bool IsExported =
false;
1544 applyICallBranchFunnel(SlotInfo, JT, IsExported);
1549 void DevirtModule::removeRedundantTypeTests() {
1551 for (
auto &&U : NumUnsafeUsesForTypeTest) {
1552 if (U.second == 0) {
1554 U.first->eraseFromParent();
1559 bool DevirtModule::run() {
1568 if ((ExportSummary && ExportSummary->partiallySplitLTOUnits()) ||
1569 (ImportSummary && ImportSummary->partiallySplitLTOUnits())) {
1570 if ((TypeTestFunc && !TypeTestFunc->
use_empty()) ||
1571 (TypeCheckedLoadFunc && !TypeCheckedLoadFunc->
use_empty()))
1573 "or llvm.type.checked.load");
1580 if (!ExportSummary &&
1581 (!TypeTestFunc || TypeTestFunc->
use_empty() || !AssumeFunc ||
1583 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->
use_empty()))
1586 if (TypeTestFunc && AssumeFunc)
1587 scanTypeTestUsers(TypeTestFunc, AssumeFunc);
1589 if (TypeCheckedLoadFunc)
1590 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
1592 if (ImportSummary) {
1593 for (
auto &S : CallSlots)
1594 importResolution(S.first, S.second);
1596 removeRedundantTypeTests();
1604 std::vector<VTableBits>
Bits;
1606 buildTypeIdentifierMap(Bits, TypeIdMap);
1607 if (TypeIdMap.
empty())
1611 if (ExportSummary) {
1613 for (
auto &
P : TypeIdMap) {
1614 if (
auto *TypeId = dyn_cast<MDString>(
P.first))
1619 for (
auto &
P : *ExportSummary) {
1620 for (
auto &S :
P.second.SummaryList) {
1626 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
1627 CallSlots[{MD, VF.Offset}]
1628 .CSInfo.markSummaryHasTypeTestAssumeUsers();
1632 for (
Metadata *MD : MetadataByGUID[VF.GUID]) {
1633 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
1637 FS->type_test_assume_const_vcalls()) {
1638 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
1639 CallSlots[{MD,
VC.VFunc.Offset}]
1640 .ConstCSInfo[
VC.Args]
1641 .markSummaryHasTypeTestAssumeUsers();
1645 FS->type_checked_load_const_vcalls()) {
1646 for (
Metadata *MD : MetadataByGUID[
VC.VFunc.GUID]) {
1647 CallSlots[{MD,
VC.VFunc.Offset}]
1648 .ConstCSInfo[
VC.Args]
1649 .addSummaryTypeCheckedLoadUser(FS);
1657 bool DidVirtualConstProp =
false;
1658 std::map<std::string, Function*> DevirtTargets;
1659 for (
auto &S : CallSlots) {
1663 std::vector<VirtualCallTarget> TargetsForSlot;
1664 if (tryFindVirtualCallTargets(TargetsForSlot, TypeIdMap[S.first.TypeID],
1665 S.first.ByteOffset)) {
1667 if (ExportSummary && isa<MDString>(S.first.TypeID))
1668 Res = &ExportSummary
1669 ->getOrInsertTypeIdSummary(
1670 cast<MDString>(S.first.TypeID)->getString())
1671 .WPDRes[S.first.ByteOffset];
1673 if (!trySingleImplDevirt(TargetsForSlot, S.second, Res)) {
1674 DidVirtualConstProp |=
1675 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
1677 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
1682 for (
const auto &
T : TargetsForSlot)
1684 DevirtTargets[
T.Fn->getName()] =
T.Fn;
1691 if (ExportSummary && isa<MDString>(S.first.TypeID)) {
1694 for (
auto FS : S.second.CSInfo.SummaryTypeCheckedLoadUsers)
1695 FS->addTypeTest(GUID);
1696 for (
auto &CCS : S.second.ConstCSInfo)
1697 for (
auto FS : CCS.second.SummaryTypeCheckedLoadUsers)
1698 FS->addTypeTest(GUID);
1702 if (RemarksEnabled) {
1704 for (
const auto &DT : DevirtTargets) {
1707 using namespace ore;
1714 removeRedundantTypeTests();
1718 if (DidVirtualConstProp)
void setVisibility(VisibilityTypes V)
StringRef getSection() const
Get the custom section of this global if it has one.
A parsed version of the target data layout string in and methods for querying it. ...
const std::string & getTargetTriple() const
Get the target triple which is a string describing the target host.
bool hasLocalLinkage() const
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
DiagnosticInfoOptimizationBase::Argument NV
CallingConv::ID getCallingConv() const
Get the calling convention of the call.
Whole program devirtualization
static unsigned getHashValue(const VTableSlot &I)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
This class represents lattice values for constants.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
A Module instance is used to store all the information related to an LLVM module. ...
static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant *> IdxList, bool InBounds=false, Optional< unsigned > InRangeIndex=None, Type *OnlyIfReducedTy=nullptr)
Getelementptr form.
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 ...
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
VirtualCallTarget(Function *Fn, const TypeMemberInfo *TM)
Implements a dense probed hash-table based set.
const StructLayout * getStructLayout(StructType *Ty) const
Returns a StructLayout object, indicating the alignment of the struct, its size, and the offsets of i...
void push_back(const T &Elt)
This provides a very simple, boring adaptor for a begin and end iterator into a range type...
Helper for check-and-exit error handling.
void initializeWholeProgramDevirtPass(PassRegistry &)
This class represents a function call, abstracting a target machine's calling convention.
An immutable pass that tracks lazily created AssumptionCache objects.
An efficient, type-erasing, non-owning reference to a callable.
static Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
uint64_t Info
Additional information for the resolution:
Like Internal, but omit from symbol table.
Externally visible function.
static cl::opt< unsigned > ClThreshold("wholeprogramdevirt-branch-funnel-threshold", cl::Hidden, cl::init(10), cl::ZeroOrMore, cl::desc("Maximum number of call targets per " "call site to enable branch funnels"))
This class implements a map that also provides access to all stored values in a deterministic order...
Analysis pass which computes a DominatorTree.
uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew=0)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
const GlobalListType & getGlobalList() const
Get the Module's list of global variables (constant).
static IntegerType * getInt64Ty(LLVMContext &C)
MemoryAccessKind computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR)
Returns the memory access properties of this copy of the function.
Virtual constant propagation.
void setAfterReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocAfter, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)
std::map< uint64_t, WholeProgramDevirtResolution > WPDRes
Mapping from byte offset to whole-program devirt resolution for that (typeid, byte offset) pair...
unsigned getElementContainingOffset(uint64_t Offset) const
Given a valid byte offset into the structure, returns the structure index that contains it...
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Export information to summary.
const char * getName() const
getName - Get the target name.
iterator_range< global_object_iterator > global_objects()
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, Instruction *InsertBefore=nullptr)
void setBeforeReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocBefore, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)
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...
AnalysisUsage & addRequired()
Used to lazily calculate structure layout information for a target machine, based on the DataLayout s...
#define INITIALIZE_PASS_DEPENDENCY(depName)
amdgpu Simplify well known AMD library false Value Value const Twine & Name
StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
When retpoline mitigation is enabled, use a branch funnel that is defined in the merged module...
LLVMContext & getContext() const
Get the global data context.
The returned value is undefined.
bool isConstant() const
If the value is a global constant, its value is immutable throughout the runtime execution of the pro...
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
This class is a functor to be used in legacy module or SCC passes for computing AA results for a func...
TypeID
Definitions of all of the base types for the Type system.
No attributes have been set.
AttributeSet getRetAttributes() const
The attributes for the ret value are returned.
InstrTy * getInstruction() const
void setName(const Twine &Name)
Change the name of the value.
static bool isEqual(const VTableSlot &LHS, const VTableSlot &RHS)
enum llvm::WholeProgramDevirtResolution::Kind TheKind
Uniform return value optimization.
static VTableSlot getTombstoneKey()
Class to represent function types.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Type * getType() const
All values are typed, get the type of this value.
ValTy * getArgOperand(unsigned i) const
Class to represent array types.
AttributeSet getParamAttributes(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
LinkageTypes getLinkage() const
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
Class to hold module path string table and global value map, and encapsulate methods for operating on...
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
Function * getDeclaration(Module *M, ID id, ArrayRef< Type *> Tys=None)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
Value * getOperand(unsigned i) const
Class to represent pointers.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
bool isCall() const
Return true if a CallInst is enclosed.
static Constant * getBitCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
IntegerType * getIntPtrType(LLVMContext &C, unsigned AddressSpace=0) const
Returns an integer type with size at least as big as that of a pointer in the given address space...
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata *> MDs)
void setAttributes(AttributeList PAL)
Set the parameter attributes of the call.
initializer< Ty > init(const Ty &Val)
bool hasAttribute(AttrKind Val) const
Return true if the attribute is present.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
A set of analyses that are preserved following a run of a transformation pass.
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
static AttributeSet get(LLVMContext &C, const AttrBuilder &B)
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB=ZB_Width)
Count number of 0's from the least significant bit to the most stopping at the first 1...
VisibilityTypes getVisibility() const
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Import information from summary.
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
A call site that could be devirtualized.
size_t size() const
size - Get the array size.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This is an important base class in LLVM.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
bool isPointerTy() const
True if this is an instance of PointerType.
A manager for alias analyses.
std::pair< iterator, bool > insert(const ValueT &V)
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it...
INITIALIZE_PASS_BEGIN(WholeProgramDevirt, "wholeprogramdevirt", "Whole program devirtualization", false, false) INITIALIZE_PASS_END(WholeProgramDevirt
ArrayRef< Type * > params() const
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
Represent the analysis usage information of a pass.
void addAttribute(unsigned i, Attribute::AttrKind Kind)
adds the attribute to the list of attributes.
static Type * getVoidTy(LLVMContext &C)
void setCallingConv(CallingConv::ID CC)
Set the calling convention of the call.
static FunctionType * get(Type *Result, ArrayRef< Type *> Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
void reserve(size_type NumEntries)
Grow the densemap so that it can contain at least NumEntries items before resizing again...
Class to represent integer types.
enum llvm::WholeProgramDevirtResolution::ByArg::Kind TheKind
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
const Constant * stripPointerCasts() const
Comdat * getOrInsertComdat(StringRef Name)
Return the Comdat in the module with the specified name.
const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs, and aliases.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
unsigned getNumArgOperands() const
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
std::string & str()
Flushes the stream contents to the target string and returns the string's reference.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
Triple - Helper class for working with autoconf configuration names.
An "identifier" for a virtual function.
This class evaluates LLVM IR, producing the Constant representing each SSA instruction.
Value * CreateGEP(Value *Ptr, ArrayRef< Value *> IdxList, const Twine &Name="")
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
unsigned getNumOperands() const
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the generic address space (address sp...
This is the shared class of boolean and integer constants.
void setSelectionKind(SelectionKind Val)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
Single implementation devirtualization.
Type * getReturnType() const
uint64_t getSizeInBytes() const
unsigned getProgramAddressSpace() const
static Constant * get(Type *Ty, uint64_t V, bool isSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
static BranchInst * Create(BasicBlock *IfTrue, Instruction *InsertBefore=nullptr)
static ConstantInt * getTrue(LLVMContext &Context)
BBTy * getParent() const
Get the basic block containing the call site.
void setLinkage(LinkageTypes LT)
std::string SingleImplName
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Target - Wrapper for Target specific information.
unsigned getNumAttrSets() const
A specification for a virtual function call with all constant integer arguments.
GUID getGUID() const
Return a 64-bit global unique ID constructed from global value name (i.e.
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...
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
amdgpu Simplify well known AMD library false Value Value * Arg
const Comdat * getComdat() const
ModulePass * createWholeProgramDevirtPass(ModuleSummaryIndex *ExportSummary, const ModuleSummaryIndex *ImportSummary)
This pass implements whole-program devirtualization using type metadata.
uint64_t getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
std::vector< uint8_t > Bytes
FunTy * getCaller() const
Return the caller function for this call site.
std::map< std::vector< uint64_t >, ByArg > ResByArg
Resolutions for calls with all constant integer arguments (excluding the first argument, "this"), where the key is the argument vector.
Constant * getOrInsertGlobal(StringRef Name, Type *Ty, function_ref< GlobalVariable *()> CreateGlobalCallback)
Look up the specified global in the module symbol table.
A raw_ostream that writes to a file descriptor.
uint64_t getElementOffset(unsigned Idx) const
static IntegerType * getInt32Ty(LLVMContext &C)
uint64_t findLowestOffset(ArrayRef< VirtualCallTarget > Targets, bool IsAfter, uint64_t Size)
LLVM_NODISCARD bool empty() const
StringRef getValueAsString() const
Return the attribute's value as a string.
StringRef getName() const
Return a constant reference to the value's name.
static VTableSlot getEmptyKey()
static Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
const BasicBlockListType & getBasicBlockList() const
Get the underlying elements of the Function...
Rename collisions when linking (static functions).
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value *> Args=None, const Twine &Name="", MDNode *FPMathTag=nullptr)
static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
Provides passes for computing function attributes based on interprocedural analyses.
Function summary information to aid decisions and implementation of importing.
LLVM_NODISCARD bool empty() const
Type * getType() const
Return the type of the instruction that generated this call site.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful, otherwise returning null.
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)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
LLVM Value Representation.
FunctionType * getFunctionType() const
static const Function * getParent(const Value *V)
AttributeSet getFnAttributes() const
The function attributes are returned.
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
static Constant * getAnon(ArrayRef< Constant *> V, bool Packed=false)
Return an anonymous struct that has the specified elements.
static Constant * get(LLVMContext &Context, ArrayRef< ElementTy > Elts)
get() constructor - Return a constant with array type with an element count and element type matching...
const TypeMemberInfo * TM
Type * getElementType() const
iterator_range< global_iterator > globals()
StringRef - Represent a constant reference to a string, i.e.
This is the interface for LLVM's primary stateless and local alias analysis.
static cl::opt< std::string > ClReadSummary("wholeprogramdevirt-read-summary", cl::desc("Read summary from given YAML file before running pass"), cl::Hidden)
static cl::opt< std::string > ClWriteSummary("wholeprogramdevirt-write-summary", cl::desc("Write summary to given YAML file after running pass"), cl::Hidden)
A container for analyses that lazily runs them and caches their results.
Legacy analysis pass which computes a DominatorTree.
AttributeList getAttributes() const
Get the parameter attributes of the call.
static IntegerType * getInt8Ty(LLVMContext &C)
void setSection(StringRef S)
Change the section for this global.
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...
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute >> Attrs)
Create an AttributeList with the specified parameters in it.
Unique return value optimization.
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...