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