//==-SummaryBasedOptimizations.cpp - Optimizations based on ThinLTO summary-==// // // 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 optimizations that are based on the module summaries. // These optimizations are performed during the thinlink phase of the // compilation. // //===----------------------------------------------------------------------===// #include "llvm/LTO/SummaryBasedOptimizations.h" #include "llvm/Analysis/SyntheticCountsUtils.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/Support/CommandLine.h" using namespace llvm; static cl::opt ThinLTOSynthesizeEntryCounts( "thinlto-synthesize-entry-counts", cl::init(false), cl::Hidden, cl::desc("Synthesize entry counts based on the summary")); namespace llvm { extern cl::opt InitialSyntheticCount; } static void initializeCounts(ModuleSummaryIndex &Index) { auto Root = Index.calculateCallGraphRoot(); // Root is a fake node. All its successors are the actual roots of the // callgraph. // FIXME: This initializes the entry counts of only the root nodes. This makes // sense when compiling a binary with ThinLTO, but for libraries any of the // non-root nodes could be called from outside. for (auto &C : Root.calls()) { auto &V = C.first; for (auto &GVS : V.getSummaryList()) { auto S = GVS.get()->getBaseObject(); auto *F = cast(S); F->setEntryCount(InitialSyntheticCount); } } } void llvm::computeSyntheticCounts(ModuleSummaryIndex &Index) { if (!ThinLTOSynthesizeEntryCounts) return; using Scaled64 = ScaledNumber; initializeCounts(Index); auto GetCallSiteRelFreq = [](FunctionSummary::EdgeTy &Edge) { return Scaled64(Edge.second.RelBlockFreq, -CalleeInfo::ScaleShift); }; auto GetEntryCount = [](ValueInfo V) { if (V.getSummaryList().size()) { auto S = V.getSummaryList().front()->getBaseObject(); auto *F = cast(S); return F->entryCount(); } else { return UINT64_C(0); } }; auto AddToEntryCount = [](ValueInfo V, Scaled64 New) { if (!V.getSummaryList().size()) return; for (auto &GVS : V.getSummaryList()) { auto S = GVS.get()->getBaseObject(); auto *F = cast(S); F->setEntryCount( SaturatingAdd(F->entryCount(), New.template toInt())); } }; auto GetProfileCount = [&](ValueInfo V, FunctionSummary::EdgeTy &Edge) { auto RelFreq = GetCallSiteRelFreq(Edge); Scaled64 EC(GetEntryCount(V), 0); return RelFreq * EC; }; // After initializing the counts in initializeCounts above, the counts have to // be propagated across the combined callgraph. // SyntheticCountsUtils::propagate takes care of this propagation on any // callgraph that specialized GraphTraits. SyntheticCountsUtils::propagate(&Index, GetProfileCount, AddToEntryCount); Index.setHasSyntheticEntryCounts(); }