ModuleSummaryAnalysis.cpp [plain text]
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BlockFrequencyInfoImpl.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/ValueSymbolTable.h"
#include "llvm/Pass.h"
using namespace llvm;
#define DEBUG_TYPE "module-summary-analysis"
static void findRefEdges(const User *CurUser, DenseSet<const Value *> &RefEdges,
SmallPtrSet<const User *, 8> &Visited) {
SmallVector<const User *, 32> Worklist;
Worklist.push_back(CurUser);
while (!Worklist.empty()) {
const User *U = Worklist.pop_back_val();
if (!Visited.insert(U).second)
continue;
ImmutableCallSite CS(U);
for (const auto &OI : U->operands()) {
const User *Operand = dyn_cast<User>(OI);
if (!Operand)
continue;
if (isa<BlockAddress>(Operand))
continue;
if (isa<GlobalValue>(Operand)) {
if (!(CS && CS.isCallee(&OI)))
RefEdges.insert(Operand);
continue;
}
Worklist.push_back(Operand);
}
}
}
static uint64_t getBlockProfileCount(uint64_t BlockFreq, uint64_t EntryFreq,
uint64_t EntryCount) {
APInt ScaledCount(128, EntryCount);
APInt BlockFreqAPInt(128, BlockFreq);
APInt EntryFreqAPInt(128, EntryFreq);
ScaledCount *= BlockFreqAPInt;
ScaledCount = ScaledCount.udiv(EntryFreqAPInt);
return ScaledCount.getLimitedValue();
}
void ModuleSummaryIndexBuilder::computeFunctionSummary(
const Function &F, BlockFrequencyInfo *BFI) {
if (!F.hasName())
return;
unsigned NumInsts = 0;
DenseMap<const Value *, CalleeInfo> CallGraphEdges;
DenseSet<const Value *> RefEdges;
bool HasProfileData = F.getEntryCount().hasValue();
SmallPtrSet<const User *, 8> Visited;
for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E;
++I) {
if (!isa<DbgInfoIntrinsic>(I))
++NumInsts;
if (auto CS = ImmutableCallSite(&*I)) {
auto *CalledFunction = CS.getCalledFunction();
if (CalledFunction && CalledFunction->hasName() &&
!CalledFunction->isIntrinsic()) {
uint64_t ScaledCount = 0;
if (HasProfileData && BFI)
ScaledCount = getBlockProfileCount(
BFI->getBlockFreq(&(*BB)).getFrequency(), BFI->getEntryFreq(),
F.getEntryCount().getValue());
auto *CalleeId =
M->getValueSymbolTable().lookup(CalledFunction->getName());
CallGraphEdges[CalleeId] += ScaledCount;
}
}
findRefEdges(&*I, RefEdges, Visited);
}
GlobalValueSummary::GVFlags Flags(F);
std::unique_ptr<FunctionSummary> FuncSummary =
llvm::make_unique<FunctionSummary>(Flags, NumInsts);
FuncSummary->addCallGraphEdges(CallGraphEdges);
FuncSummary->addRefEdges(RefEdges);
Index->addGlobalValueSummary(F.getName(), std::move(FuncSummary));
}
void ModuleSummaryIndexBuilder::computeVariableSummary(
const GlobalVariable &V) {
DenseSet<const Value *> RefEdges;
SmallPtrSet<const User *, 8> Visited;
findRefEdges(&V, RefEdges, Visited);
GlobalValueSummary::GVFlags Flags(V);
std::unique_ptr<GlobalVarSummary> GVarSummary =
llvm::make_unique<GlobalVarSummary>(Flags);
GVarSummary->addRefEdges(RefEdges);
Index->addGlobalValueSummary(V.getName(), std::move(GVarSummary));
}
ModuleSummaryIndexBuilder::ModuleSummaryIndexBuilder(
const Module *M,
std::function<BlockFrequencyInfo *(const Function &F)> Ftor)
: Index(llvm::make_unique<ModuleSummaryIndex>()), M(M) {
if (!moduleCanBeRenamedForThinLTO(*M))
return;
for (auto &F : *M) {
if (F.isDeclaration())
continue;
BlockFrequencyInfo *BFI = nullptr;
std::unique_ptr<BlockFrequencyInfo> BFIPtr;
if (Ftor)
BFI = Ftor(F);
else if (F.getEntryCount().hasValue()) {
LoopInfo LI{DominatorTree(const_cast<Function &>(F))};
BranchProbabilityInfo BPI{F, LI};
BFIPtr = llvm::make_unique<BlockFrequencyInfo>(F, BPI, LI);
BFI = BFIPtr.get();
}
computeFunctionSummary(F, BFI);
}
for (const GlobalVariable &G : M->globals()) {
if (G.isDeclaration())
continue;
computeVariableSummary(G);
}
}
char ModuleSummaryIndexWrapperPass::ID = 0;
INITIALIZE_PASS_BEGIN(ModuleSummaryIndexWrapperPass, "module-summary-analysis",
"Module Summary Analysis", false, true)
INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
INITIALIZE_PASS_END(ModuleSummaryIndexWrapperPass, "module-summary-analysis",
"Module Summary Analysis", false, true)
ModulePass *llvm::createModuleSummaryIndexWrapperPass() {
return new ModuleSummaryIndexWrapperPass();
}
ModuleSummaryIndexWrapperPass::ModuleSummaryIndexWrapperPass()
: ModulePass(ID) {
initializeModuleSummaryIndexWrapperPassPass(*PassRegistry::getPassRegistry());
}
bool ModuleSummaryIndexWrapperPass::runOnModule(Module &M) {
IndexBuilder = llvm::make_unique<ModuleSummaryIndexBuilder>(
&M, [this](const Function &F) {
return &(this->getAnalysis<BlockFrequencyInfoWrapperPass>(
*const_cast<Function *>(&F))
.getBFI());
});
return false;
}
bool ModuleSummaryIndexWrapperPass::doFinalization(Module &M) {
IndexBuilder.reset();
return false;
}
void ModuleSummaryIndexWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<BlockFrequencyInfoWrapperPass>();
}
bool llvm::moduleCanBeRenamedForThinLTO(const Module &M) {
SmallPtrSet<GlobalValue *, 8> Used;
collectUsedGlobalVariables(M, Used, false);
bool LocalIsUsed =
llvm::any_of(Used, [](GlobalValue *V) { return V->hasLocalLinkage(); });
if (!LocalIsUsed)
return true;
auto HasInlineAsm = llvm::any_of(M, [](const Function &F) {
return llvm::any_of(instructions(F), [](const Instruction &I) {
const CallInst *CallI = dyn_cast<CallInst>(&I);
if (!CallI)
return false;
return CallI->isInlineAsm();
});
});
return !HasInlineAsm;
}