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 "ProfiledBinary.h"
13#include "llvm/ADT/PriorityQueue.h"
14#include "llvm/ProfileData/ProfileCommon.h"
15#include "llvm/ProfileData/SampleProf.h"
16#include "llvm/Transforms/IPO/ProfiledCallGraph.h"
17#include "llvm/Transforms/IPO/SampleContextTracker.h"
18
19using namespace llvm;
20using namespace sampleprof;
21
22namespace llvm {
23namespace sampleprof {
24
25// Inline candidate seen from profile
26struct ProfiledInlineCandidate {
27 ProfiledInlineCandidate(const FunctionSamples *Samples, uint64_t Count,
28 uint32_t Size)
29 : CalleeSamples(Samples), CallsiteCount(Count), SizeCost(Size) {}
30 // Context-sensitive function profile for inline candidate
31 const FunctionSamples *CalleeSamples;
32 // Call site count for an inline candidate
33 // TODO: make sure entry count for context profile and call site
34 // target count for corresponding call are consistent.
35 uint64_t CallsiteCount;
36 // Size proxy for function under particular call context.
37 uint64_t SizeCost;
38};
39
40// Inline candidate comparer using call site weight
41struct ProfiledCandidateComparer {
42 bool operator()(const ProfiledInlineCandidate &LHS,
43 const ProfiledInlineCandidate &RHS) {
44 // Always prioritize inlining zero-sized functions as they do not affect the
45 // size budget. This could happen when all of the callee's code is gone and
46 // only pseudo probes are left.
47 if ((LHS.SizeCost == 0 || RHS.SizeCost == 0) &&
48 (LHS.SizeCost != RHS.SizeCost))
49 return RHS.SizeCost == 0;
50
51 if (LHS.CallsiteCount != RHS.CallsiteCount)
52 return LHS.CallsiteCount < RHS.CallsiteCount;
53
54 if (LHS.SizeCost != RHS.SizeCost)
55 return LHS.SizeCost > RHS.SizeCost;
56
57 // Tie breaker using GUID so we have stable/deterministic inlining order
58 assert(LHS.CalleeSamples && RHS.CalleeSamples &&
59 "Expect non-null FunctionSamples");
60 return LHS.CalleeSamples->getGUID() < RHS.CalleeSamples->getGUID();
61 }
62};
63
64using ProfiledCandidateQueue =
65 PriorityQueue<ProfiledInlineCandidate, std::vector<ProfiledInlineCandidate>,
66 ProfiledCandidateComparer>;
67
68// Pre-compilation inliner based on context-sensitive profile.
69// The PreInliner estimates inline decision using hotness from profile
70// and cost estimation from machine code size. It helps merges context
71// profile globally and achieves better post-inine profile quality, which
72// otherwise won't be possible for ThinLTO. It also reduce context profile
73// size by only keep context that is estimated to be inlined.
74class CSPreInliner {
75public:
76 CSPreInliner(SampleContextTracker &Tracker, ProfiledBinary &Binary,
77 ProfileSummary *Summary);
78 void run();
79
80private:
81 bool getInlineCandidates(ProfiledCandidateQueue &CQueue,
82 const FunctionSamples *FCallerContextSamples);
83 std::vector<FunctionId> buildTopDownOrder();
84 void processFunction(FunctionId Name);
85 bool shouldInline(ProfiledInlineCandidate &Candidate);
86 uint32_t getFuncSize(const ContextTrieNode *ContextNode);
87 bool UseContextCost;
88 SampleContextTracker &ContextTracker;
89 ProfiledBinary &Binary;
90 ProfileSummary *Summary;
91};
92
93} // end namespace sampleprof
94} // end namespace llvm
95
96#endif
97