Path: blob/main/contrib/llvm-project/llvm/lib/Analysis/InlineOrder.cpp
35234 views
//===- InlineOrder.cpp - Inlining order abstraction -*- C++ ---*-----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/Analysis/InlineOrder.h"9#include "llvm/Analysis/AssumptionCache.h"10#include "llvm/Analysis/BlockFrequencyInfo.h"11#include "llvm/Analysis/GlobalsModRef.h"12#include "llvm/Analysis/InlineAdvisor.h"13#include "llvm/Analysis/InlineCost.h"14#include "llvm/Analysis/OptimizationRemarkEmitter.h"15#include "llvm/Analysis/ProfileSummaryInfo.h"16#include "llvm/Analysis/TargetLibraryInfo.h"17#include "llvm/Analysis/TargetTransformInfo.h"18#include "llvm/Support/CommandLine.h"1920using namespace llvm;2122#define DEBUG_TYPE "inline-order"2324enum class InlinePriorityMode : int { Size, Cost, CostBenefit, ML };2526static cl::opt<InlinePriorityMode> UseInlinePriority(27"inline-priority-mode", cl::init(InlinePriorityMode::Size), cl::Hidden,28cl::desc("Choose the priority mode to use in module inline"),29cl::values(clEnumValN(InlinePriorityMode::Size, "size",30"Use callee size priority."),31clEnumValN(InlinePriorityMode::Cost, "cost",32"Use inline cost priority."),33clEnumValN(InlinePriorityMode::CostBenefit, "cost-benefit",34"Use cost-benefit ratio."),35clEnumValN(InlinePriorityMode::ML, "ml", "Use ML.")));3637static cl::opt<int> ModuleInlinerTopPriorityThreshold(38"module-inliner-top-priority-threshold", cl::Hidden, cl::init(0),39cl::desc("The cost threshold for call sites that get inlined without the "40"cost-benefit analysis"));4142namespace {4344llvm::InlineCost getInlineCostWrapper(CallBase &CB,45FunctionAnalysisManager &FAM,46const InlineParams &Params) {47Function &Caller = *CB.getCaller();48ProfileSummaryInfo *PSI =49FAM.getResult<ModuleAnalysisManagerFunctionProxy>(Caller)50.getCachedResult<ProfileSummaryAnalysis>(51*CB.getParent()->getParent()->getParent());5253auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(Caller);54auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {55return FAM.getResult<AssumptionAnalysis>(F);56};57auto GetBFI = [&](Function &F) -> BlockFrequencyInfo & {58return FAM.getResult<BlockFrequencyAnalysis>(F);59};60auto GetTLI = [&](Function &F) -> const TargetLibraryInfo & {61return FAM.getResult<TargetLibraryAnalysis>(F);62};6364Function &Callee = *CB.getCalledFunction();65auto &CalleeTTI = FAM.getResult<TargetIRAnalysis>(Callee);66bool RemarksEnabled =67Callee.getContext().getDiagHandlerPtr()->isMissedOptRemarkEnabled(68DEBUG_TYPE);69return getInlineCost(CB, Params, CalleeTTI, GetAssumptionCache, GetTLI,70GetBFI, PSI, RemarksEnabled ? &ORE : nullptr);71}7273class SizePriority {74public:75SizePriority() = default;76SizePriority(const CallBase *CB, FunctionAnalysisManager &,77const InlineParams &) {78Function *Callee = CB->getCalledFunction();79Size = Callee->getInstructionCount();80}8182static bool isMoreDesirable(const SizePriority &P1, const SizePriority &P2) {83return P1.Size < P2.Size;84}8586private:87unsigned Size = UINT_MAX;88};8990class CostPriority {91public:92CostPriority() = default;93CostPriority(const CallBase *CB, FunctionAnalysisManager &FAM,94const InlineParams &Params) {95auto IC = getInlineCostWrapper(const_cast<CallBase &>(*CB), FAM, Params);96if (IC.isVariable())97Cost = IC.getCost();98else99Cost = IC.isNever() ? INT_MAX : INT_MIN;100}101102static bool isMoreDesirable(const CostPriority &P1, const CostPriority &P2) {103return P1.Cost < P2.Cost;104}105106private:107int Cost = INT_MAX;108};109110class CostBenefitPriority {111public:112CostBenefitPriority() = default;113CostBenefitPriority(const CallBase *CB, FunctionAnalysisManager &FAM,114const InlineParams &Params) {115auto IC = getInlineCostWrapper(const_cast<CallBase &>(*CB), FAM, Params);116if (IC.isVariable())117Cost = IC.getCost();118else119Cost = IC.isNever() ? INT_MAX : INT_MIN;120StaticBonusApplied = IC.getStaticBonusApplied();121CostBenefit = IC.getCostBenefit();122}123124static bool isMoreDesirable(const CostBenefitPriority &P1,125const CostBenefitPriority &P2) {126// We prioritize call sites in the dictionary order of the following127// priorities:128//129// 1. Those call sites that are expected to reduce the caller size when130// inlined. Within them, we prioritize those call sites with bigger131// reduction.132//133// 2. Those call sites that have gone through the cost-benefit analysis.134// Currently, they are limited to hot call sites. Within them, we135// prioritize those call sites with higher benefit-to-cost ratios.136//137// 3. Remaining call sites are prioritized according to their costs.138139// We add back StaticBonusApplied to determine whether we expect the caller140// to shrink (even if we don't delete the callee).141bool P1ReducesCallerSize =142P1.Cost + P1.StaticBonusApplied < ModuleInlinerTopPriorityThreshold;143bool P2ReducesCallerSize =144P2.Cost + P2.StaticBonusApplied < ModuleInlinerTopPriorityThreshold;145if (P1ReducesCallerSize || P2ReducesCallerSize) {146// If one reduces the caller size while the other doesn't, then return147// true iff P1 reduces the caller size.148if (P1ReducesCallerSize != P2ReducesCallerSize)149return P1ReducesCallerSize;150151// If they both reduce the caller size, pick the one with the smaller152// cost.153return P1.Cost < P2.Cost;154}155156bool P1HasCB = P1.CostBenefit.has_value();157bool P2HasCB = P2.CostBenefit.has_value();158if (P1HasCB || P2HasCB) {159// If one has undergone the cost-benefit analysis while the other hasn't,160// then return true iff P1 has.161if (P1HasCB != P2HasCB)162return P1HasCB;163164// If they have undergone the cost-benefit analysis, then pick the one165// with a higher benefit-to-cost ratio.166APInt LHS = P1.CostBenefit->getBenefit() * P2.CostBenefit->getCost();167APInt RHS = P2.CostBenefit->getBenefit() * P1.CostBenefit->getCost();168return LHS.ugt(RHS);169}170171// Remaining call sites are ordered according to their costs.172return P1.Cost < P2.Cost;173}174175private:176int Cost = INT_MAX;177int StaticBonusApplied = 0;178std::optional<CostBenefitPair> CostBenefit;179};180181class MLPriority {182public:183MLPriority() = default;184MLPriority(const CallBase *CB, FunctionAnalysisManager &FAM,185const InlineParams &Params) {186auto IC = getInlineCostWrapper(const_cast<CallBase &>(*CB), FAM, Params);187if (IC.isVariable())188Cost = IC.getCost();189else190Cost = IC.isNever() ? INT_MAX : INT_MIN;191}192193static bool isMoreDesirable(const MLPriority &P1, const MLPriority &P2) {194return P1.Cost < P2.Cost;195}196197private:198int Cost = INT_MAX;199};200201template <typename PriorityT>202class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {203using T = std::pair<CallBase *, int>;204205bool hasLowerPriority(const CallBase *L, const CallBase *R) const {206const auto I1 = Priorities.find(L);207const auto I2 = Priorities.find(R);208assert(I1 != Priorities.end() && I2 != Priorities.end());209return PriorityT::isMoreDesirable(I2->second, I1->second);210}211212bool updateAndCheckDecreased(const CallBase *CB) {213auto It = Priorities.find(CB);214const auto OldPriority = It->second;215It->second = PriorityT(CB, FAM, Params);216const auto NewPriority = It->second;217return PriorityT::isMoreDesirable(OldPriority, NewPriority);218}219220// A call site could become less desirable for inlining because of the size221// growth from prior inlining into the callee. This method is used to lazily222// update the desirability of a call site if it's decreasing. It is only223// called on pop(), not every time the desirability changes. When the224// desirability of the front call site decreases, an updated one would be225// pushed right back into the heap. For simplicity, those cases where the226// desirability of a call site increases are ignored here.227void pop_heap_adjust() {228std::pop_heap(Heap.begin(), Heap.end(), isLess);229while (updateAndCheckDecreased(Heap.back())) {230std::push_heap(Heap.begin(), Heap.end(), isLess);231std::pop_heap(Heap.begin(), Heap.end(), isLess);232}233}234235public:236PriorityInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params)237: FAM(FAM), Params(Params) {238isLess = [&](const CallBase *L, const CallBase *R) {239return hasLowerPriority(L, R);240};241}242243size_t size() override { return Heap.size(); }244245void push(const T &Elt) override {246CallBase *CB = Elt.first;247const int InlineHistoryID = Elt.second;248249Heap.push_back(CB);250Priorities[CB] = PriorityT(CB, FAM, Params);251std::push_heap(Heap.begin(), Heap.end(), isLess);252InlineHistoryMap[CB] = InlineHistoryID;253}254255T pop() override {256assert(size() > 0);257pop_heap_adjust();258259CallBase *CB = Heap.pop_back_val();260T Result = std::make_pair(CB, InlineHistoryMap[CB]);261InlineHistoryMap.erase(CB);262return Result;263}264265void erase_if(function_ref<bool(T)> Pred) override {266auto PredWrapper = [=](CallBase *CB) -> bool {267return Pred(std::make_pair(CB, InlineHistoryMap[CB]));268};269llvm::erase_if(Heap, PredWrapper);270std::make_heap(Heap.begin(), Heap.end(), isLess);271}272273private:274SmallVector<CallBase *, 16> Heap;275std::function<bool(const CallBase *L, const CallBase *R)> isLess;276DenseMap<CallBase *, int> InlineHistoryMap;277DenseMap<const CallBase *, PriorityT> Priorities;278FunctionAnalysisManager &FAM;279const InlineParams &Params;280};281282} // namespace283284AnalysisKey llvm::PluginInlineOrderAnalysis::Key;285bool llvm::PluginInlineOrderAnalysis::HasBeenRegistered;286287std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>288llvm::getDefaultInlineOrder(FunctionAnalysisManager &FAM,289const InlineParams &Params,290ModuleAnalysisManager &MAM, Module &M) {291switch (UseInlinePriority) {292case InlinePriorityMode::Size:293LLVM_DEBUG(dbgs() << " Current used priority: Size priority ---- \n");294return std::make_unique<PriorityInlineOrder<SizePriority>>(FAM, Params);295296case InlinePriorityMode::Cost:297LLVM_DEBUG(dbgs() << " Current used priority: Cost priority ---- \n");298return std::make_unique<PriorityInlineOrder<CostPriority>>(FAM, Params);299300case InlinePriorityMode::CostBenefit:301LLVM_DEBUG(302dbgs() << " Current used priority: cost-benefit priority ---- \n");303return std::make_unique<PriorityInlineOrder<CostBenefitPriority>>(FAM,304Params);305case InlinePriorityMode::ML:306LLVM_DEBUG(dbgs() << " Current used priority: ML priority ---- \n");307return std::make_unique<PriorityInlineOrder<MLPriority>>(FAM, Params);308}309return nullptr;310}311312std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>313llvm::getInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params,314ModuleAnalysisManager &MAM, Module &M) {315if (llvm::PluginInlineOrderAnalysis::isRegistered()) {316LLVM_DEBUG(dbgs() << " Current used priority: plugin ---- \n");317return MAM.getResult<PluginInlineOrderAnalysis>(M).Factory(FAM, Params, MAM,318M);319}320return getDefaultInlineOrder(FAM, Params, MAM, M);321}322323324