//===- ModuleSummaryAnalysis.cpp - Module summary index builder -----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This pass builds a ModuleSummaryIndex object for the module, to be written // to bitcode or LLVM assembly. // //===----------------------------------------------------------------------===// #include "llvm/Analysis/ModuleSummaryAnalysis.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/BlockFrequencyInfoImpl.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/IndirectCallPromotionAnalysis.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" // 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). static void findRefEdges(const User *CurUser, DenseSet &RefEdges, SmallPtrSet &Visited) { SmallVector 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(OI); if (!Operand) continue; if (isa(Operand)) continue; if (isa(Operand)) { // 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 (!(CS && CS.isCallee(&OI))) RefEdges.insert(Operand); continue; } Worklist.push_back(Operand); } } } void ModuleSummaryIndexBuilder::computeFunctionSummary( const Function &F, BlockFrequencyInfo *BFI) { // Summary not currently supported for anonymous functions, they must // be renamed. if (!F.hasName()) return; unsigned NumInsts = 0; // Map from callee ValueId to profile count. Used to accumulate profile // counts for all static calls to a given callee. DenseMap CallGraphEdges; DenseMap IndirectCallEdges; DenseSet RefEdges; ICallPromotionAnalysis ICallAnalysis; SmallPtrSet Visited; for (const BasicBlock &BB : F) for (const Instruction &I : BB) { if (!isa(I)) ++NumInsts; if (auto CS = ImmutableCallSite(&I)) { auto *CalledFunction = CS.getCalledFunction(); // Check if this is a direct call to a known function. if (CalledFunction) { if (CalledFunction->hasName() && !CalledFunction->isIntrinsic()) { auto ScaledCount = BFI ? BFI->getBlockProfileCount(&BB) : None; auto *CalleeId = M->getValueSymbolTable().lookup(CalledFunction->getName()); CallGraphEdges[CalleeId] += (ScaledCount ? ScaledCount.getValue() : 0); } } else { // Otherwise, check for an indirect call (call to a non-const value // that isn't an inline assembly call). const CallInst *CI = dyn_cast(&I); if (CS.getCalledValue() && !isa(CS.getCalledValue()) && !(CI && CI->isInlineAsm())) { uint32_t NumVals, NumCandidates; uint64_t TotalCount; auto CandidateProfileData = ICallAnalysis.getPromotionCandidatesForInstruction( &I, NumVals, TotalCount, NumCandidates); for (auto &Candidate : CandidateProfileData) IndirectCallEdges[Candidate.Value] += Candidate.Count; } } } findRefEdges(&I, RefEdges, Visited); } GlobalValueSummary::GVFlags Flags(F); std::unique_ptr FuncSummary = llvm::make_unique(Flags, NumInsts); FuncSummary->addCallGraphEdges(CallGraphEdges); FuncSummary->addCallGraphEdges(IndirectCallEdges); FuncSummary->addRefEdges(RefEdges); Index->addGlobalValueSummary(F.getName(), std::move(FuncSummary)); } void ModuleSummaryIndexBuilder::computeVariableSummary( const GlobalVariable &V) { DenseSet RefEdges; SmallPtrSet Visited; findRefEdges(&V, RefEdges, Visited); GlobalValueSummary::GVFlags Flags(V); std::unique_ptr GVarSummary = llvm::make_unique(Flags); GVarSummary->addRefEdges(RefEdges); Index->addGlobalValueSummary(V.getName(), std::move(GVarSummary)); } ModuleSummaryIndexBuilder::ModuleSummaryIndexBuilder( const Module *M, std::function Ftor) : Index(llvm::make_unique()), M(M) { // Check if the module can be promoted, otherwise just disable importing from // it by not emitting any summary. // FIXME: we could still import *into* it most of the time. if (!moduleCanBeRenamedForThinLTO(*M)) return; // Compute summaries for all functions defined in module, and save in the // index. for (auto &F : *M) { if (F.isDeclaration()) continue; BlockFrequencyInfo *BFI = nullptr; std::unique_ptr BFIPtr; if (Ftor) BFI = Ftor(F); else if (F.getEntryCount().hasValue()) { LoopInfo LI{DominatorTree(const_cast(F))}; BranchProbabilityInfo BPI{F, LI}; BFIPtr = llvm::make_unique(F, BPI, LI); BFI = BFIPtr.get(); } computeFunctionSummary(F, BFI); } // Compute summaries for all variables defined in module, and save in the // index. 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( &M, [this](const Function &F) { return &(this->getAnalysis( *const_cast(&F)) .getBFI()); }); return false; } bool ModuleSummaryIndexWrapperPass::doFinalization(Module &M) { IndexBuilder.reset(); return false; } void ModuleSummaryIndexWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); } bool llvm::moduleCanBeRenamedForThinLTO(const Module &M) { // We cannot currently promote or rename anything used in inline assembly, // which are not visible to the compiler. Detect a possible case by looking // for a llvm.used local value, in conjunction with an inline assembly call // in the module. Prevent importing of any modules containing these uses by // suppressing generation of the index. This also prevents importing // into this module, which is also necessary to avoid needing to rename // in case of a name clash between a local in this module and an imported // global. // FIXME: If we find we need a finer-grained approach of preventing promotion // and renaming of just the functions using inline assembly we will need to: // - Add flag in the function summaries to identify those with inline asm. // - Prevent importing of any functions with flag set. // - Prevent importing of any global function with the same name as a // function in current module that has the flag set. // - For any llvm.used value that is exported and promoted, add a private // alias to the original name in the current module (even if we don't // export the function using those values in inline asm, another function // with a reference could be exported). SmallPtrSet Used; collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); bool LocalIsUsed = llvm::any_of(Used, [](GlobalValue *V) { return V->hasLocalLinkage(); }); if (!LocalIsUsed) return true; // Walk all the instructions in the module and find if one is inline ASM auto HasInlineAsm = llvm::any_of(M, [](const Function &F) { return llvm::any_of(instructions(F), [](const Instruction &I) { const CallInst *CallI = dyn_cast(&I); if (!CallI) return false; return CallI->isInlineAsm(); }); }); return !HasInlineAsm; }