diff --git a/llvm/include/llvm/Analysis/InlineOrder.h b/llvm/include/llvm/Analysis/InlineOrder.h --- a/llvm/include/llvm/Analysis/InlineOrder.h +++ b/llvm/include/llvm/Analysis/InlineOrder.h @@ -12,6 +12,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Analysis/InlineCost.h" #include "llvm/IR/InstrTypes.h" #include #include @@ -20,6 +21,8 @@ class CallBase; class Function; +enum class InlinePriorityMode : int { NoPriority, Size, Cost, OptRatio }; + template class InlineOrder { public: using reference = T &; @@ -40,6 +43,10 @@ bool empty() { return !size(); } }; +std::unique_ptr>> +getInlineOrder(InlinePriorityMode UseInlinePriority, + FunctionAnalysisManager &FAM, const InlineParams &Params); + template > class DefaultInlineOrder : public InlineOrder { using reference = T &; @@ -82,15 +89,16 @@ using PriorityT = unsigned; DenseMap Priorities; - static PriorityT evaluate(const CallBase *CB) { + PriorityT evaluate(const CallBase *CB) { Function *Callee = CB->getCalledFunction(); return Callee->getInstructionCount(); } - static bool isMoreDesirable(const PriorityT &P1, const PriorityT &P2) { + bool isMoreDesirable(const PriorityT &P1, const PriorityT &P2) const { return P1 < P2; } +public: bool hasLowerPriority(const CallBase *L, const CallBase *R) const override { const auto I1 = Priorities.find(L); const auto I2 = Priorities.find(R); @@ -98,7 +106,49 @@ return isMoreDesirable(I2->second, I1->second); } + // Update the priority associated with CB. + void update(const CallBase *CB) override { Priorities[CB] = evaluate(CB); }; + + bool updateAndCheckDecreased(const CallBase *CB) override { + auto It = Priorities.find(CB); + const auto OldPriority = It->second; + It->second = evaluate(CB); + const auto NewPriority = It->second; + return isMoreDesirable(OldPriority, NewPriority); + } +}; + +class CostPriority : public InlinePriority { + using PriorityT = int; + DenseMap Priorities; + std::function getInlineCost; + + PriorityT evaluate(const CallBase *CB) { + auto IC = getInlineCost(CB); + int cost = 0; + if (IC.isVariable()) + cost = IC.getCost(); + else + cost = IC.isNever() ? INT_MAX : INT_MIN; + return cost; + } + + bool isMoreDesirable(const PriorityT &P1, const PriorityT &P2) const { + return P1 < P2; + } + public: + CostPriority() = delete; + CostPriority(std::function getInlineCost) + : getInlineCost(getInlineCost){}; + + bool hasLowerPriority(const CallBase *L, const CallBase *R) const override { + const auto I1 = Priorities.find(L); + const auto I2 = Priorities.find(R); + assert(I1 != Priorities.end() && I2 != Priorities.end()); + return isMoreDesirable(I2->second, I1->second); + } + // Update the priority associated with CB. void update(const CallBase *CB) override { Priorities[CB] = evaluate(CB); }; @@ -184,5 +234,6 @@ DenseMap InlineHistoryMap; std::unique_ptr PriorityPtr; }; + } // namespace llvm #endif // LLVM_ANALYSIS_INLINEORDER_H diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -72,6 +72,7 @@ IndirectCallPromotionAnalysis.cpp InlineCost.cpp InlineAdvisor.cpp + InlineOrder.cpp InlineSizeEstimatorAnalysis.cpp InstCount.cpp InstructionPrecedenceTracking.cpp diff --git a/llvm/lib/Analysis/InlineOrder.cpp b/llvm/lib/Analysis/InlineOrder.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Analysis/InlineOrder.cpp @@ -0,0 +1,77 @@ +//===- InlineOrder.cpp - Inlining order abstraction -*- 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/InlineOrder.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/InlineAdvisor.h" +#include "llvm/Analysis/InlineCost.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Analysis/ProfileSummaryInfo.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "inline-order" + +static llvm::InlineCost getInlineCostWrapper(CallBase &CB, + FunctionAnalysisManager &FAM, + const InlineParams &Params) { + Function &Caller = *CB.getCaller(); + ProfileSummaryInfo *PSI = + FAM.getResult(Caller) + .getCachedResult( + *CB.getParent()->getParent()->getParent()); + + auto &ORE = FAM.getResult(Caller); + auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & { + return FAM.getResult(F); + }; + auto GetBFI = [&](Function &F) -> BlockFrequencyInfo & { + return FAM.getResult(F); + }; + auto GetTLI = [&](Function &F) -> const TargetLibraryInfo & { + return FAM.getResult(F); + }; + + Function &Callee = *CB.getCalledFunction(); + auto &CalleeTTI = FAM.getResult(Callee); + bool RemarksEnabled = + Callee.getContext().getDiagHandlerPtr()->isMissedOptRemarkEnabled( + DEBUG_TYPE); + return getInlineCost(CB, Params, CalleeTTI, GetAssumptionCache, GetTLI, + GetBFI, PSI, RemarksEnabled ? &ORE : nullptr); +} + +std::unique_ptr>> +llvm::getInlineOrder(InlinePriorityMode UseInlinePriority, + FunctionAnalysisManager &FAM, const InlineParams &Params) { + switch (UseInlinePriority) { + case InlinePriorityMode::NoPriority: + return std::make_unique>>(); + + case InlinePriorityMode::Size: + LLVM_DEBUG(dbgs() << " Current used priority: Size priority ---- \n"); + return std::make_unique( + std::make_unique()); + + case InlinePriorityMode::Cost: + LLVM_DEBUG(dbgs() << " Current used priority: Cost priority ---- \n"); + return std::make_unique( + std::make_unique([&](const CallBase *CB) -> InlineCost { + return getInlineCostWrapper(const_cast(*CB), FAM, Params); + })); + + default: + assert("Unsupported Inline Priority Mode"); + break; + } + return nullptr; +} diff --git a/llvm/lib/Transforms/IPO/ModuleInliner.cpp b/llvm/lib/Transforms/IPO/ModuleInliner.cpp --- a/llvm/lib/Transforms/IPO/ModuleInliner.cpp +++ b/llvm/lib/Transforms/IPO/ModuleInliner.cpp @@ -49,9 +49,15 @@ STATISTIC(NumInlined, "Number of functions inlined"); STATISTIC(NumDeleted, "Number of functions deleted because all callers found"); -static cl::opt InlineEnablePriorityOrder( - "module-inline-enable-priority-order", cl::Hidden, cl::init(true), - cl::desc("Enable the priority inline order for the module inliner")); +static cl::opt UseInlinePriority( + "inline-priority-mode", cl::init(InlinePriorityMode::Size), cl::Hidden, + cl::desc("Choose the priority mode to use in module inline"), + cl::values(clEnumValN(InlinePriorityMode::NoPriority, "no priority", + "Use no priority, visit callsites in bottom-up."), + clEnumValN(InlinePriorityMode::Size, "size", + "Use callee size priority."), + clEnumValN(InlinePriorityMode::Cost, "cost", + "Use inline cost priority."))); /// Return true if the specified inline history ID /// indicates an inline history that includes the specified function. @@ -145,12 +151,7 @@ // // TODO: Here is a huge amount duplicate code between the module inliner and // the SCC inliner, which need some refactoring. - std::unique_ptr>> Calls; - if (InlineEnablePriorityOrder) - Calls = std::make_unique( - std::make_unique()); - else - Calls = std::make_unique>>(); + auto Calls = getInlineOrder(UseInlinePriority, FAM, Params); assert(Calls != nullptr && "Expected an initialized InlineOrder"); // Populate the initial list of calls in this module.