xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/IPO/SyntheticCountsPropagation.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //=- SyntheticCountsPropagation.cpp - Propagate function counts --*- C++ -*-=//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements a transformation that synthesizes entry counts for
100b57cec5SDimitry Andric // functions and attaches !prof metadata to functions with the synthesized
110b57cec5SDimitry Andric // counts. The presence of !prof metadata with counter name set to
120b57cec5SDimitry Andric // 'synthesized_function_entry_count' indicate that the value of the counter is
130b57cec5SDimitry Andric // an estimation of the likely execution count of the function. This transform
140b57cec5SDimitry Andric // is applied only in non PGO mode as functions get 'real' profile-based
150b57cec5SDimitry Andric // function entry counts in the PGO mode.
160b57cec5SDimitry Andric //
170b57cec5SDimitry Andric // The transformation works by first assigning some initial values to the entry
180b57cec5SDimitry Andric // counts of all functions and then doing a top-down traversal of the
190b57cec5SDimitry Andric // callgraph-scc to propagate the counts. For each function the set of callsites
200b57cec5SDimitry Andric // and their relative block frequency is gathered. The relative block frequency
210b57cec5SDimitry Andric // multiplied by the entry count of the caller and added to the callee's entry
220b57cec5SDimitry Andric // count. For non-trivial SCCs, the new counts are computed from the previous
230b57cec5SDimitry Andric // counts and updated in one shot.
240b57cec5SDimitry Andric //
250b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #include "llvm/Transforms/IPO/SyntheticCountsPropagation.h"
280b57cec5SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h"
290b57cec5SDimitry Andric #include "llvm/Analysis/CallGraph.h"
300b57cec5SDimitry Andric #include "llvm/Analysis/SyntheticCountsUtils.h"
310b57cec5SDimitry Andric #include "llvm/IR/Function.h"
320b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
330b57cec5SDimitry Andric #include "llvm/IR/Module.h"
340b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric using namespace llvm;
370b57cec5SDimitry Andric using Scaled64 = ScaledNumber<uint64_t>;
380b57cec5SDimitry Andric using ProfileCount = Function::ProfileCount;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric #define DEBUG_TYPE "synthetic-counts-propagation"
410b57cec5SDimitry Andric 
42fe6060f1SDimitry Andric namespace llvm {
430b57cec5SDimitry Andric cl::opt<int>
440b57cec5SDimitry Andric     InitialSyntheticCount("initial-synthetic-count", cl::Hidden, cl::init(10),
45fe6060f1SDimitry Andric                           cl::desc("Initial value of synthetic entry count"));
46fe6060f1SDimitry Andric } // namespace llvm
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric /// Initial synthetic count assigned to inline functions.
490b57cec5SDimitry Andric static cl::opt<int> InlineSyntheticCount(
5081ad6265SDimitry Andric     "inline-synthetic-count", cl::Hidden, cl::init(15),
510b57cec5SDimitry Andric     cl::desc("Initial synthetic entry count for inline functions."));
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric /// Initial synthetic count assigned to cold functions.
540b57cec5SDimitry Andric static cl::opt<int> ColdSyntheticCount(
5581ad6265SDimitry Andric     "cold-synthetic-count", cl::Hidden, cl::init(5),
560b57cec5SDimitry Andric     cl::desc("Initial synthetic entry count for cold functions."));
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric // Assign initial synthetic entry counts to functions.
590b57cec5SDimitry Andric static void
initializeCounts(Module & M,function_ref<void (Function *,uint64_t)> SetCount)600b57cec5SDimitry Andric initializeCounts(Module &M, function_ref<void(Function *, uint64_t)> SetCount) {
610b57cec5SDimitry Andric   auto MayHaveIndirectCalls = [](Function &F) {
620b57cec5SDimitry Andric     for (auto *U : F.users()) {
630b57cec5SDimitry Andric       if (!isa<CallInst>(U) && !isa<InvokeInst>(U))
640b57cec5SDimitry Andric         return true;
650b57cec5SDimitry Andric     }
660b57cec5SDimitry Andric     return false;
670b57cec5SDimitry Andric   };
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   for (Function &F : M) {
700b57cec5SDimitry Andric     uint64_t InitialCount = InitialSyntheticCount;
710b57cec5SDimitry Andric     if (F.isDeclaration())
720b57cec5SDimitry Andric       continue;
730b57cec5SDimitry Andric     if (F.hasFnAttribute(Attribute::AlwaysInline) ||
740b57cec5SDimitry Andric         F.hasFnAttribute(Attribute::InlineHint)) {
750b57cec5SDimitry Andric       // Use a higher value for inline functions to account for the fact that
760b57cec5SDimitry Andric       // these are usually beneficial to inline.
770b57cec5SDimitry Andric       InitialCount = InlineSyntheticCount;
780b57cec5SDimitry Andric     } else if (F.hasLocalLinkage() && !MayHaveIndirectCalls(F)) {
790b57cec5SDimitry Andric       // Local functions without inline hints get counts only through
800b57cec5SDimitry Andric       // propagation.
810b57cec5SDimitry Andric       InitialCount = 0;
820b57cec5SDimitry Andric     } else if (F.hasFnAttribute(Attribute::Cold) ||
830b57cec5SDimitry Andric                F.hasFnAttribute(Attribute::NoInline)) {
840b57cec5SDimitry Andric       // Use a lower value for noinline and cold functions.
850b57cec5SDimitry Andric       InitialCount = ColdSyntheticCount;
860b57cec5SDimitry Andric     }
870b57cec5SDimitry Andric     SetCount(&F, InitialCount);
880b57cec5SDimitry Andric   }
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
run(Module & M,ModuleAnalysisManager & MAM)910b57cec5SDimitry Andric PreservedAnalyses SyntheticCountsPropagation::run(Module &M,
920b57cec5SDimitry Andric                                                   ModuleAnalysisManager &MAM) {
930b57cec5SDimitry Andric   FunctionAnalysisManager &FAM =
940b57cec5SDimitry Andric       MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
950b57cec5SDimitry Andric   DenseMap<Function *, Scaled64> Counts;
960b57cec5SDimitry Andric   // Set initial entry counts.
970b57cec5SDimitry Andric   initializeCounts(
980b57cec5SDimitry Andric       M, [&](Function *F, uint64_t Count) { Counts[F] = Scaled64(Count, 0); });
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   // Edge includes information about the source. Hence ignore the first
1010b57cec5SDimitry Andric   // parameter.
1020b57cec5SDimitry Andric   auto GetCallSiteProfCount = [&](const CallGraphNode *,
1030b57cec5SDimitry Andric                                   const CallGraphNode::CallRecord &Edge) {
104bdd1243dSDimitry Andric     std::optional<Scaled64> Res;
1050b57cec5SDimitry Andric     if (!Edge.first)
1060b57cec5SDimitry Andric       return Res;
1075ffd83dbSDimitry Andric     CallBase &CB = *cast<CallBase>(*Edge.first);
1085ffd83dbSDimitry Andric     Function *Caller = CB.getCaller();
1090b57cec5SDimitry Andric     auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(*Caller);
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric     // Now compute the callsite count from relative frequency and
1120b57cec5SDimitry Andric     // entry count:
1135ffd83dbSDimitry Andric     BasicBlock *CSBB = CB.getParent();
114*5f757f3fSDimitry Andric     Scaled64 EntryFreq(BFI.getEntryFreq().getFrequency(), 0);
1150b57cec5SDimitry Andric     Scaled64 BBCount(BFI.getBlockFreq(CSBB).getFrequency(), 0);
1160b57cec5SDimitry Andric     BBCount /= EntryFreq;
1170b57cec5SDimitry Andric     BBCount *= Counts[Caller];
118bdd1243dSDimitry Andric     return std::optional<Scaled64>(BBCount);
1190b57cec5SDimitry Andric   };
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   CallGraph CG(M);
1220b57cec5SDimitry Andric   // Propgate the entry counts on the callgraph.
1230b57cec5SDimitry Andric   SyntheticCountsUtils<const CallGraph *>::propagate(
1240b57cec5SDimitry Andric       &CG, GetCallSiteProfCount, [&](const CallGraphNode *N, Scaled64 New) {
1250b57cec5SDimitry Andric         auto F = N->getFunction();
1260b57cec5SDimitry Andric         if (!F || F->isDeclaration())
1270b57cec5SDimitry Andric           return;
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric         Counts[F] += New;
1300b57cec5SDimitry Andric       });
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   // Set the counts as metadata.
1330b57cec5SDimitry Andric   for (auto Entry : Counts) {
1340b57cec5SDimitry Andric     Entry.first->setEntryCount(ProfileCount(
1350b57cec5SDimitry Andric         Entry.second.template toInt<uint64_t>(), Function::PCT_Synthetic));
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   return PreservedAnalyses::all();
1390b57cec5SDimitry Andric }
140