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