xref: /netbsd-src/external/apache2/llvm/dist/llvm/tools/llvm-profgen/CSPreInliner.h (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 //===-- CSPreInliner.h - Profile guided preinliner ---------------- C++ -*-===//
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 #ifndef LLVM_TOOLS_LLVM_PROFGEN_PGOINLINEADVISOR_H
10 #define LLVM_TOOLS_LLVM_PROFGEN_PGOINLINEADVISOR_H
11 
12 #include "llvm/ADT/PriorityQueue.h"
13 #include "llvm/ProfileData/ProfileCommon.h"
14 #include "llvm/ProfileData/SampleProf.h"
15 #include "llvm/Transforms/IPO/ProfiledCallGraph.h"
16 #include "llvm/Transforms/IPO/SampleContextTracker.h"
17 
18 using namespace llvm;
19 using namespace sampleprof;
20 
21 namespace llvm {
22 namespace sampleprof {
23 
24 // Inline candidate seen from profile
25 struct ProfiledInlineCandidate {
ProfiledInlineCandidateProfiledInlineCandidate26   ProfiledInlineCandidate(const FunctionSamples *Samples, uint64_t Count)
27       : CalleeSamples(Samples), CallsiteCount(Count),
28         SizeCost(Samples->getBodySamples().size()) {}
29   // Context-sensitive function profile for inline candidate
30   const FunctionSamples *CalleeSamples;
31   // Call site count for an inline candidate
32   // TODO: make sure entry count for context profile and call site
33   // target count for corresponding call are consistent.
34   uint64_t CallsiteCount;
35   // Size proxy for function under particular call context.
36   // TODO: use post-inline callee size from debug info.
37   uint64_t SizeCost;
38 };
39 
40 // Inline candidate comparer using call site weight
41 struct ProfiledCandidateComparer {
operatorProfiledCandidateComparer42   bool operator()(const ProfiledInlineCandidate &LHS,
43                   const ProfiledInlineCandidate &RHS) {
44     if (LHS.CallsiteCount != RHS.CallsiteCount)
45       return LHS.CallsiteCount < RHS.CallsiteCount;
46 
47     if (LHS.SizeCost != RHS.SizeCost)
48       return LHS.SizeCost > RHS.SizeCost;
49 
50     // Tie breaker using GUID so we have stable/deterministic inlining order
51     assert(LHS.CalleeSamples && RHS.CalleeSamples &&
52            "Expect non-null FunctionSamples");
53     return LHS.CalleeSamples->getGUID(LHS.CalleeSamples->getName()) <
54            RHS.CalleeSamples->getGUID(RHS.CalleeSamples->getName());
55   }
56 };
57 
58 using ProfiledCandidateQueue =
59     PriorityQueue<ProfiledInlineCandidate, std::vector<ProfiledInlineCandidate>,
60                   ProfiledCandidateComparer>;
61 
62 // Pre-compilation inliner based on context-sensitive profile.
63 // The PreInliner estimates inline decision using hotness from profile
64 // and cost estimation from machine code size. It helps merges context
65 // profile globally and achieves better post-inine profile quality, which
66 // otherwise won't be possible for ThinLTO. It also reduce context profile
67 // size by only keep context that is estimated to be inlined.
68 class CSPreInliner {
69 public:
70   CSPreInliner(StringMap<FunctionSamples> &Profiles, uint64_t HotThreshold,
71                uint64_t ColdThreshold);
72   void run();
73 
74 private:
75   bool getInlineCandidates(ProfiledCandidateQueue &CQueue,
76                            const FunctionSamples *FCallerContextSamples);
77   std::vector<StringRef> buildTopDownOrder();
78   void processFunction(StringRef Name);
79   bool shouldInline(ProfiledInlineCandidate &Candidate);
80   SampleContextTracker ContextTracker;
81   StringMap<FunctionSamples> &ProfileMap;
82 
83   // Count thresholds to answer isHotCount and isColdCount queries.
84   // Mirrors the threshold in ProfileSummaryInfo.
85   uint64_t HotCountThreshold;
86   uint64_t ColdCountThreshold;
87 };
88 
89 } // end namespace sampleprof
90 } // end namespace llvm
91 
92 #endif
93