aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2024-07-27 23:34:35 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-10-23 18:26:01 +0000
commit0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583 (patch)
tree6cf5ab1f05330c6773b1f3f64799d56a9c7a1faa /contrib/llvm-project/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
parent6b9f7133aba44189d9625c352bc2c2a59baf18ef (diff)
parentac9a064cb179f3425b310fa2847f8764ac970a4d (diff)
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp126
1 files changed, 101 insertions, 25 deletions
diff --git a/contrib/llvm-project/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp b/contrib/llvm-project/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
index 1f15e9478324..e9490ccba821 100644
--- a/contrib/llvm-project/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
+++ b/contrib/llvm-project/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
@@ -22,6 +22,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
+#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/IndirectCallPromotionAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryProfileInfo.h"
@@ -82,6 +83,10 @@ static cl::opt<std::string> ModuleSummaryDotFile(
extern cl::opt<bool> ScalePartialSampleProfileWorkingSetSize;
+extern cl::opt<unsigned> MaxNumVTableAnnotations;
+
+extern cl::opt<bool> MemProfReportHintedSizes;
+
// Walk through the operands of a given User via worklist iteration and populate
// the set of GlobalValue references encountered. Invoked either on an
// Instruction or a GlobalVariable (which walks its initializer).
@@ -92,9 +97,12 @@ extern cl::opt<bool> ScalePartialSampleProfileWorkingSetSize;
// global vars at all. When importing function we aren't interested if any
// instruction in it takes an address of any basic block, because instruction
// can only take an address of basic block located in the same function.
+// Set `RefLocalLinkageIFunc` to true if the analyzed value references a
+// local-linkage ifunc.
static bool findRefEdges(ModuleSummaryIndex &Index, const User *CurUser,
SetVector<ValueInfo, std::vector<ValueInfo>> &RefEdges,
- SmallPtrSet<const User *, 8> &Visited) {
+ SmallPtrSet<const User *, 8> &Visited,
+ bool &RefLocalLinkageIFunc) {
bool HasBlockAddress = false;
SmallVector<const User *, 32> Worklist;
if (Visited.insert(CurUser).second)
@@ -116,14 +124,37 @@ static bool findRefEdges(ModuleSummaryIndex &Index, const User *CurUser,
// We have a reference to a global value. This should be added to
// the reference set unless it is a callee. Callees are handled
// specially by WriteFunction and are added to a separate list.
- if (!(CB && CB->isCallee(&OI)))
+ if (!(CB && CB->isCallee(&OI))) {
+ // If an ifunc has local linkage, do not add it into ref edges, and
+ // sets `RefLocalLinkageIFunc` to true. The referencer is not eligible
+ // for import. An ifunc doesn't have summary and ThinLTO cannot
+ // promote it; importing the referencer may cause linkage errors.
+ if (auto *GI = dyn_cast_if_present<GlobalIFunc>(GV);
+ GI && GI->hasLocalLinkage()) {
+ RefLocalLinkageIFunc = true;
+ continue;
+ }
RefEdges.insert(Index.getOrInsertValueInfo(GV));
+ }
continue;
}
if (Visited.insert(Operand).second)
Worklist.push_back(Operand);
}
}
+
+ const Instruction *I = dyn_cast<Instruction>(CurUser);
+ if (I) {
+ uint64_t TotalCount = 0;
+ // MaxNumVTableAnnotations is the maximum number of vtables annotated on
+ // the instruction.
+ auto ValueDataArray = getValueProfDataFromInst(
+ *I, IPVK_VTableTarget, MaxNumVTableAnnotations, TotalCount);
+
+ for (const auto &V : ValueDataArray)
+ RefEdges.insert(Index.getOrInsertValueInfo(/* VTableGUID = */
+ V.Value));
+ }
return HasBlockAddress;
}
@@ -292,7 +323,8 @@ static void computeFunctionSummary(
// Add personality function, prefix data and prologue data to function's ref
// list.
- findRefEdges(Index, &F, RefEdges, Visited);
+ bool HasLocalIFuncCallOrRef = false;
+ findRefEdges(Index, &F, RefEdges, Visited, HasLocalIFuncCallOrRef);
std::vector<const Instruction *> NonVolatileLoads;
std::vector<const Instruction *> NonVolatileStores;
@@ -305,7 +337,6 @@ static void computeFunctionSummary(
bool HasInlineAsmMaybeReferencingInternal = false;
bool HasIndirBranchToBlockAddress = false;
- bool HasIFuncCall = false;
bool HasUnknownCall = false;
bool MayThrow = false;
for (const BasicBlock &BB : F) {
@@ -351,11 +382,11 @@ static void computeFunctionSummary(
// of calling it we should add GV to RefEdges directly.
RefEdges.insert(Index.getOrInsertValueInfo(GV));
else if (auto *U = dyn_cast<User>(Stored))
- findRefEdges(Index, U, RefEdges, Visited);
+ findRefEdges(Index, U, RefEdges, Visited, HasLocalIFuncCallOrRef);
continue;
}
}
- findRefEdges(Index, &I, RefEdges, Visited);
+ findRefEdges(Index, &I, RefEdges, Visited, HasLocalIFuncCallOrRef);
const auto *CB = dyn_cast<CallBase>(&I);
if (!CB) {
if (I.mayThrow())
@@ -429,7 +460,7 @@ static void computeFunctionSummary(
// Non-local ifunc is not cloned and does not have the issue.
if (auto *GI = dyn_cast_if_present<GlobalIFunc>(CalledValue))
if (GI->hasLocalLinkage())
- HasIFuncCall = true;
+ HasLocalIFuncCallOrRef = true;
// Skip inline assembly calls.
if (CI && CI->isInlineAsm())
continue;
@@ -449,11 +480,11 @@ static void computeFunctionSummary(
}
}
- uint32_t NumVals, NumCandidates;
+ uint32_t NumCandidates;
uint64_t TotalCount;
auto CandidateProfileData =
- ICallAnalysis.getPromotionCandidatesForInstruction(
- &I, NumVals, TotalCount, NumCandidates);
+ ICallAnalysis.getPromotionCandidatesForInstruction(&I, TotalCount,
+ NumCandidates);
for (const auto &Candidate : CandidateProfileData)
CallGraphEdges[Index.getOrInsertValueInfo(Candidate.Value)]
.updateHotness(getHotness(Candidate.Count, PSI));
@@ -488,6 +519,7 @@ static void computeFunctionSummary(
auto *MemProfMD = I.getMetadata(LLVMContext::MD_memprof);
if (MemProfMD) {
std::vector<MIBInfo> MIBs;
+ std::vector<uint64_t> TotalSizes;
for (auto &MDOp : MemProfMD->operands()) {
auto *MIBMD = cast<const MDNode>(MDOp);
MDNode *StackNode = getMIBStackNode(MIBMD);
@@ -507,8 +539,17 @@ static void computeFunctionSummary(
}
MIBs.push_back(
MIBInfo(getMIBAllocType(MIBMD), std::move(StackIdIndices)));
+ if (MemProfReportHintedSizes) {
+ auto TotalSize = getMIBTotalSize(MIBMD);
+ assert(TotalSize);
+ TotalSizes.push_back(TotalSize);
+ }
}
Allocs.push_back(AllocInfo(std::move(MIBs)));
+ if (MemProfReportHintedSizes) {
+ assert(Allocs.back().MIBs.size() == TotalSizes.size());
+ Allocs.back().TotalSizes = std::move(TotalSizes);
+ }
} else if (!InstCallsite.empty()) {
SmallVector<unsigned> StackIdIndices;
for (auto StackId : InstCallsite)
@@ -534,7 +575,7 @@ static void computeFunctionSummary(
SmallPtrSet<const User *, 8> &Cache) {
for (const auto *I : Instrs) {
Cache.erase(I);
- findRefEdges(Index, I, Edges, Cache);
+ findRefEdges(Index, I, Edges, Cache, HasLocalIFuncCallOrRef);
}
};
@@ -610,12 +651,13 @@ static void computeFunctionSummary(
#endif
bool NonRenamableLocal = isNonRenamableLocal(F);
- bool NotEligibleForImport = NonRenamableLocal ||
- HasInlineAsmMaybeReferencingInternal ||
- HasIndirBranchToBlockAddress || HasIFuncCall;
+ bool NotEligibleForImport =
+ NonRenamableLocal || HasInlineAsmMaybeReferencingInternal ||
+ HasIndirBranchToBlockAddress || HasLocalIFuncCallOrRef;
GlobalValueSummary::GVFlags Flags(
F.getLinkage(), F.getVisibility(), NotEligibleForImport,
- /* Live = */ false, F.isDSOLocal(), F.canBeOmittedFromSymbolTable());
+ /* Live = */ false, F.isDSOLocal(), F.canBeOmittedFromSymbolTable(),
+ GlobalValueSummary::ImportKind::Definition);
FunctionSummary::FFlags FunFlags{
F.doesNotAccessMemory(), F.onlyReadsMemory() && !F.doesNotAccessMemory(),
F.hasFnAttribute(Attribute::NoRecurse), F.returnDoesNotAlias(),
@@ -647,7 +689,8 @@ static void computeFunctionSummary(
/// within the initializer.
static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
const Module &M, ModuleSummaryIndex &Index,
- VTableFuncList &VTableFuncs) {
+ VTableFuncList &VTableFuncs,
+ const GlobalVariable &OrigGV) {
// First check if this is a function pointer.
if (I->getType()->isPointerTy()) {
auto C = I->stripPointerCasts();
@@ -675,7 +718,7 @@ static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
auto Offset = SL->getElementOffset(EI.index());
unsigned Op = SL->getElementContainingOffset(Offset);
findFuncPointers(cast<Constant>(I->getOperand(Op)),
- StartingOffset + Offset, M, Index, VTableFuncs);
+ StartingOffset + Offset, M, Index, VTableFuncs, OrigGV);
}
} else if (auto *C = dyn_cast<ConstantArray>(I)) {
ArrayType *ATy = C->getType();
@@ -683,7 +726,34 @@ static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
uint64_t EltSize = DL.getTypeAllocSize(EltTy);
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
findFuncPointers(cast<Constant>(I->getOperand(i)),
- StartingOffset + i * EltSize, M, Index, VTableFuncs);
+ StartingOffset + i * EltSize, M, Index, VTableFuncs,
+ OrigGV);
+ }
+ } else if (const auto *CE = dyn_cast<ConstantExpr>(I)) {
+ // For relative vtables, the next sub-component should be a trunc.
+ if (CE->getOpcode() != Instruction::Trunc ||
+ !(CE = dyn_cast<ConstantExpr>(CE->getOperand(0))))
+ return;
+
+ // If this constant can be reduced to the offset between a function and a
+ // global, then we know this is a valid virtual function if the RHS is the
+ // original vtable we're scanning through.
+ if (CE->getOpcode() == Instruction::Sub) {
+ GlobalValue *LHS, *RHS;
+ APSInt LHSOffset, RHSOffset;
+ if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHS, LHSOffset, DL) &&
+ IsConstantOffsetFromGlobal(CE->getOperand(1), RHS, RHSOffset, DL) &&
+ RHS == &OrigGV &&
+
+ // For relative vtables, this component should point to the callable
+ // function without any offsets.
+ LHSOffset == 0 &&
+
+ // Also, the RHS should always point to somewhere within the vtable.
+ RHSOffset <=
+ static_cast<uint64_t>(DL.getTypeAllocSize(OrigGV.getInitializer()->getType()))) {
+ findFuncPointers(LHS, StartingOffset, M, Index, VTableFuncs, OrigGV);
+ }
}
}
}
@@ -696,7 +766,7 @@ static void computeVTableFuncs(ModuleSummaryIndex &Index,
return;
findFuncPointers(V.getInitializer(), /*StartingOffset=*/0, M, Index,
- VTableFuncs);
+ VTableFuncs, V);
#ifndef NDEBUG
// Validate that the VTableFuncs list is ordered by offset.
@@ -737,11 +807,15 @@ static void computeVariableSummary(ModuleSummaryIndex &Index,
SmallVectorImpl<MDNode *> &Types) {
SetVector<ValueInfo, std::vector<ValueInfo>> RefEdges;
SmallPtrSet<const User *, 8> Visited;
- bool HasBlockAddress = findRefEdges(Index, &V, RefEdges, Visited);
+ bool RefLocalIFunc = false;
+ bool HasBlockAddress =
+ findRefEdges(Index, &V, RefEdges, Visited, RefLocalIFunc);
+ const bool NotEligibleForImport = (HasBlockAddress || RefLocalIFunc);
bool NonRenamableLocal = isNonRenamableLocal(V);
GlobalValueSummary::GVFlags Flags(
V.getLinkage(), V.getVisibility(), NonRenamableLocal,
- /* Live = */ false, V.isDSOLocal(), V.canBeOmittedFromSymbolTable());
+ /* Live = */ false, V.isDSOLocal(), V.canBeOmittedFromSymbolTable(),
+ GlobalValueSummary::Definition);
VTableFuncList VTableFuncs;
// If splitting is not enabled, then we compute the summary information
@@ -770,7 +844,7 @@ static void computeVariableSummary(ModuleSummaryIndex &Index,
RefEdges.takeVector());
if (NonRenamableLocal)
CantBePromoted.insert(V.getGUID());
- if (HasBlockAddress)
+ if (NotEligibleForImport)
GVarSummary->setNotEligibleToImport();
if (!VTableFuncs.empty())
GVarSummary->setVTableFuncs(VTableFuncs);
@@ -787,7 +861,8 @@ static void computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A,
bool NonRenamableLocal = isNonRenamableLocal(A);
GlobalValueSummary::GVFlags Flags(
A.getLinkage(), A.getVisibility(), NonRenamableLocal,
- /* Live = */ false, A.isDSOLocal(), A.canBeOmittedFromSymbolTable());
+ /* Live = */ false, A.isDSOLocal(), A.canBeOmittedFromSymbolTable(),
+ GlobalValueSummary::Definition);
auto AS = std::make_unique<AliasSummary>(Flags);
auto AliaseeVI = Index.getValueInfo(Aliasee->getGUID());
assert(AliaseeVI && "Alias expects aliasee summary to be available");
@@ -867,7 +942,8 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
GlobalValue::InternalLinkage, GlobalValue::DefaultVisibility,
/* NotEligibleToImport = */ true,
/* Live = */ true,
- /* Local */ GV->isDSOLocal(), GV->canBeOmittedFromSymbolTable());
+ /* Local */ GV->isDSOLocal(), GV->canBeOmittedFromSymbolTable(),
+ GlobalValueSummary::Definition);
CantBePromoted.insert(GV->getGUID());
// Create the appropriate summary type.
if (Function *F = dyn_cast<Function>(GV)) {
@@ -1006,7 +1082,7 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
if (!ModuleSummaryDotFile.empty()) {
std::error_code EC;
- raw_fd_ostream OSDot(ModuleSummaryDotFile, EC, sys::fs::OpenFlags::OF_None);
+ raw_fd_ostream OSDot(ModuleSummaryDotFile, EC, sys::fs::OpenFlags::OF_Text);
if (EC)
report_fatal_error(Twine("Failed to open dot file ") +
ModuleSummaryDotFile + ": " + EC.message() + "\n");