//===-- CSPreInliner.h - Profile guided preinliner ---------------- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_TOOLS_LLVM_PROFGEN_PGOINLINEADVISOR_H #define LLVM_TOOLS_LLVM_PROFGEN_PGOINLINEADVISOR_H #include "llvm/ADT/PriorityQueue.h" #include "llvm/ProfileData/ProfileCommon.h" #include "llvm/ProfileData/SampleProf.h" #include "llvm/Transforms/IPO/ProfiledCallGraph.h" #include "llvm/Transforms/IPO/SampleContextTracker.h" using namespace llvm; using namespace sampleprof; namespace llvm { namespace sampleprof { // Inline candidate seen from profile struct ProfiledInlineCandidate { ProfiledInlineCandidate(const FunctionSamples *Samples, uint64_t Count) : CalleeSamples(Samples), CallsiteCount(Count), SizeCost(Samples->getBodySamples().size()) {} // Context-sensitive function profile for inline candidate const FunctionSamples *CalleeSamples; // Call site count for an inline candidate // TODO: make sure entry count for context profile and call site // target count for corresponding call are consistent. uint64_t CallsiteCount; // Size proxy for function under particular call context. // TODO: use post-inline callee size from debug info. uint64_t SizeCost; }; // Inline candidate comparer using call site weight struct ProfiledCandidateComparer { bool operator()(const ProfiledInlineCandidate &LHS, const ProfiledInlineCandidate &RHS) { if (LHS.CallsiteCount != RHS.CallsiteCount) return LHS.CallsiteCount < RHS.CallsiteCount; if (LHS.SizeCost != RHS.SizeCost) return LHS.SizeCost > RHS.SizeCost; // Tie breaker using GUID so we have stable/deterministic inlining order assert(LHS.CalleeSamples && RHS.CalleeSamples && "Expect non-null FunctionSamples"); return LHS.CalleeSamples->getGUID(LHS.CalleeSamples->getName()) < RHS.CalleeSamples->getGUID(RHS.CalleeSamples->getName()); } }; using ProfiledCandidateQueue = PriorityQueue, ProfiledCandidateComparer>; // Pre-compilation inliner based on context-sensitive profile. // The PreInliner estimates inline decision using hotness from profile // and cost estimation from machine code size. It helps merges context // profile globally and achieves better post-inine profile quality, which // otherwise won't be possible for ThinLTO. It also reduce context profile // size by only keep context that is estimated to be inlined. class CSPreInliner { public: CSPreInliner(StringMap &Profiles, uint64_t HotThreshold, uint64_t ColdThreshold); void run(); private: bool getInlineCandidates(ProfiledCandidateQueue &CQueue, const FunctionSamples *FCallerContextSamples); std::vector buildTopDownOrder(); void processFunction(StringRef Name); bool shouldInline(ProfiledInlineCandidate &Candidate); SampleContextTracker ContextTracker; StringMap &ProfileMap; // Count thresholds to answer isHotCount and isColdCount queries. // Mirrors the threshold in ProfileSummaryInfo. uint64_t HotCountThreshold; uint64_t ColdCountThreshold; }; } // end namespace sampleprof } // end namespace llvm #endif