1 //==-SummaryBasedOptimizations.cpp - Optimizations based on ThinLTO summary-==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements optimizations that are based on the module summaries. 10 // These optimizations are performed during the thinlink phase of the 11 // compilation. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/LTO/SummaryBasedOptimizations.h" 16 #include "llvm/Analysis/SyntheticCountsUtils.h" 17 #include "llvm/IR/ModuleSummaryIndex.h" 18 #include "llvm/Support/CommandLine.h" 19 20 using namespace llvm; 21 22 static cl::opt<bool> ThinLTOSynthesizeEntryCounts( 23 "thinlto-synthesize-entry-counts", cl::init(false), cl::Hidden, 24 cl::desc("Synthesize entry counts based on the summary")); 25 26 namespace llvm { 27 extern cl::opt<int> InitialSyntheticCount; 28 } 29 30 static void initializeCounts(ModuleSummaryIndex &Index) { 31 auto Root = Index.calculateCallGraphRoot(); 32 // Root is a fake node. All its successors are the actual roots of the 33 // callgraph. 34 // FIXME: This initializes the entry counts of only the root nodes. This makes 35 // sense when compiling a binary with ThinLTO, but for libraries any of the 36 // non-root nodes could be called from outside. 37 for (auto &C : Root.calls()) { 38 auto &V = C.first; 39 for (auto &GVS : V.getSummaryList()) { 40 auto S = GVS.get()->getBaseObject(); 41 auto *F = cast<FunctionSummary>(S); 42 F->setEntryCount(InitialSyntheticCount); 43 } 44 } 45 } 46 47 void llvm::computeSyntheticCounts(ModuleSummaryIndex &Index) { 48 if (!ThinLTOSynthesizeEntryCounts) 49 return; 50 51 using Scaled64 = ScaledNumber<uint64_t>; 52 initializeCounts(Index); 53 auto GetCallSiteRelFreq = [](FunctionSummary::EdgeTy &Edge) { 54 return Scaled64(Edge.second.RelBlockFreq, -CalleeInfo::ScaleShift); 55 }; 56 auto GetEntryCount = [](ValueInfo V) { 57 if (V.getSummaryList().size()) { 58 auto S = V.getSummaryList().front().get()->getBaseObject(); 59 auto *F = cast<FunctionSummary>(S); 60 return F->entryCount(); 61 } else { 62 return UINT64_C(0); 63 } 64 }; 65 auto AddToEntryCount = [](ValueInfo V, Scaled64 New) { 66 if (!V.getSummaryList().size()) 67 return; 68 for (auto &GVS : V.getSummaryList()) { 69 auto S = GVS.get()->getBaseObject(); 70 auto *F = cast<FunctionSummary>(S); 71 F->setEntryCount( 72 SaturatingAdd(F->entryCount(), New.template toInt<uint64_t>())); 73 } 74 }; 75 76 auto GetProfileCount = [&](ValueInfo V, FunctionSummary::EdgeTy &Edge) { 77 auto RelFreq = GetCallSiteRelFreq(Edge); 78 Scaled64 EC(GetEntryCount(V), 0); 79 return RelFreq * EC; 80 }; 81 // After initializing the counts in initializeCounts above, the counts have to 82 // be propagated across the combined callgraph. 83 // SyntheticCountsUtils::propagate takes care of this propagation on any 84 // callgraph that specialized GraphTraits. 85 SyntheticCountsUtils<ModuleSummaryIndex *>::propagate(&Index, GetProfileCount, 86 AddToEntryCount); 87 Index.setHasSyntheticEntryCounts(); 88 } 89