|  | //=- SyntheticCountsPropagation.cpp - Propagate function counts --*- C++ -*-=// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file implements a transformation that synthesizes entry counts for | 
|  | // functions and attaches !prof metadata to functions with the synthesized | 
|  | // counts. The presence of !prof metadata with counter name set to | 
|  | // 'synthesized_function_entry_count' indicate that the value of the counter is | 
|  | // an estimation of the likely execution count of the function. This transform | 
|  | // is applied only in non PGO mode as functions get 'real' profile-based | 
|  | // function entry counts in the PGO mode. | 
|  | // | 
|  | // The transformation works by first assigning some initial values to the entry | 
|  | // counts of all functions and then doing a top-down traversal of the | 
|  | // callgraph-scc to propagate the counts. For each function the set of callsites | 
|  | // and their relative block frequency is gathered. The relative block frequency | 
|  | // multiplied by the entry count of the caller and added to the callee's entry | 
|  | // count. For non-trivial SCCs, the new counts are computed from the previous | 
|  | // counts and updated in one shot. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Transforms/IPO/SyntheticCountsPropagation.h" | 
|  | #include "llvm/ADT/DenseSet.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/Analysis/BlockFrequencyInfo.h" | 
|  | #include "llvm/Analysis/CallGraph.h" | 
|  | #include "llvm/Analysis/ProfileSummaryInfo.h" | 
|  | #include "llvm/Analysis/SyntheticCountsUtils.h" | 
|  | #include "llvm/IR/CallSite.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/Instructions.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | using namespace llvm; | 
|  | using Scaled64 = ScaledNumber<uint64_t>; | 
|  | using ProfileCount = Function::ProfileCount; | 
|  |  | 
|  | #define DEBUG_TYPE "synthetic-counts-propagation" | 
|  |  | 
|  | /// Initial synthetic count assigned to functions. | 
|  | cl::opt<int> | 
|  | InitialSyntheticCount("initial-synthetic-count", cl::Hidden, cl::init(10), | 
|  | cl::ZeroOrMore, | 
|  | cl::desc("Initial value of synthetic entry count.")); | 
|  |  | 
|  | /// Initial synthetic count assigned to inline functions. | 
|  | static cl::opt<int> InlineSyntheticCount( | 
|  | "inline-synthetic-count", cl::Hidden, cl::init(15), cl::ZeroOrMore, | 
|  | cl::desc("Initial synthetic entry count for inline functions.")); | 
|  |  | 
|  | /// Initial synthetic count assigned to cold functions. | 
|  | static cl::opt<int> ColdSyntheticCount( | 
|  | "cold-synthetic-count", cl::Hidden, cl::init(5), cl::ZeroOrMore, | 
|  | cl::desc("Initial synthetic entry count for cold functions.")); | 
|  |  | 
|  | // Assign initial synthetic entry counts to functions. | 
|  | static void | 
|  | initializeCounts(Module &M, function_ref<void(Function *, uint64_t)> SetCount) { | 
|  | auto MayHaveIndirectCalls = [](Function &F) { | 
|  | for (auto *U : F.users()) { | 
|  | if (!isa<CallInst>(U) && !isa<InvokeInst>(U)) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | for (Function &F : M) { | 
|  | uint64_t InitialCount = InitialSyntheticCount; | 
|  | if (F.isDeclaration()) | 
|  | continue; | 
|  | if (F.hasFnAttribute(Attribute::AlwaysInline) || | 
|  | F.hasFnAttribute(Attribute::InlineHint)) { | 
|  | // Use a higher value for inline functions to account for the fact that | 
|  | // these are usually beneficial to inline. | 
|  | InitialCount = InlineSyntheticCount; | 
|  | } else if (F.hasLocalLinkage() && !MayHaveIndirectCalls(F)) { | 
|  | // Local functions without inline hints get counts only through | 
|  | // propagation. | 
|  | InitialCount = 0; | 
|  | } else if (F.hasFnAttribute(Attribute::Cold) || | 
|  | F.hasFnAttribute(Attribute::NoInline)) { | 
|  | // Use a lower value for noinline and cold functions. | 
|  | InitialCount = ColdSyntheticCount; | 
|  | } | 
|  | SetCount(&F, InitialCount); | 
|  | } | 
|  | } | 
|  |  | 
|  | PreservedAnalyses SyntheticCountsPropagation::run(Module &M, | 
|  | ModuleAnalysisManager &MAM) { | 
|  | FunctionAnalysisManager &FAM = | 
|  | MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); | 
|  | DenseMap<Function *, Scaled64> Counts; | 
|  | // Set initial entry counts. | 
|  | initializeCounts( | 
|  | M, [&](Function *F, uint64_t Count) { Counts[F] = Scaled64(Count, 0); }); | 
|  |  | 
|  | // Edge includes information about the source. Hence ignore the first | 
|  | // parameter. | 
|  | auto GetCallSiteProfCount = [&](const CallGraphNode *, | 
|  | const CallGraphNode::CallRecord &Edge) { | 
|  | Optional<Scaled64> Res = None; | 
|  | if (!Edge.first) | 
|  | return Res; | 
|  | assert(isa<Instruction>(Edge.first)); | 
|  | CallSite CS(cast<Instruction>(Edge.first)); | 
|  | Function *Caller = CS.getCaller(); | 
|  | auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(*Caller); | 
|  |  | 
|  | // Now compute the callsite count from relative frequency and | 
|  | // entry count: | 
|  | BasicBlock *CSBB = CS.getInstruction()->getParent(); | 
|  | Scaled64 EntryFreq(BFI.getEntryFreq(), 0); | 
|  | Scaled64 BBCount(BFI.getBlockFreq(CSBB).getFrequency(), 0); | 
|  | BBCount /= EntryFreq; | 
|  | BBCount *= Counts[Caller]; | 
|  | return Optional<Scaled64>(BBCount); | 
|  | }; | 
|  |  | 
|  | CallGraph CG(M); | 
|  | // Propgate the entry counts on the callgraph. | 
|  | SyntheticCountsUtils<const CallGraph *>::propagate( | 
|  | &CG, GetCallSiteProfCount, [&](const CallGraphNode *N, Scaled64 New) { | 
|  | auto F = N->getFunction(); | 
|  | if (!F || F->isDeclaration()) | 
|  | return; | 
|  |  | 
|  | Counts[F] += New; | 
|  | }); | 
|  |  | 
|  | // Set the counts as metadata. | 
|  | for (auto Entry : Counts) { | 
|  | Entry.first->setEntryCount(ProfileCount( | 
|  | Entry.second.template toInt<uint64_t>(), Function::PCT_Synthetic)); | 
|  | } | 
|  |  | 
|  | return PreservedAnalyses::all(); | 
|  | } |