Refactor inline costs analysis by removing the InlineCostAnalysis class

InlineCostAnalysis is an analysis pass without any need for it to be one.
Once it stops being an analysis pass, it doesn't maintain any useful state
and the member functions inside can be made free functions. NFC.

Differential Revision: http://reviews.llvm.org/D15701

llvm-svn: 256521
This commit is contained in:
Easwaran Raman 2015-12-28 20:28:19 +00:00
parent 9db5b93ffc
commit b9f7120e7a
6 changed files with 68 additions and 114 deletions

View File

@ -23,7 +23,7 @@ class AssumptionCacheTracker;
class CallSite; class CallSite;
class DataLayout; class DataLayout;
class Function; class Function;
class TargetTransformInfoWrapperPass; class TargetTransformInfo;
namespace InlineConstants { namespace InlineConstants {
// Various magic constants used to adjust heuristics. // Various magic constants used to adjust heuristics.
@ -98,46 +98,31 @@ public:
int getCostDelta() const { return Threshold - getCost(); } int getCostDelta() const { return Threshold - getCost(); }
}; };
/// \brief Cost analyzer used by inliner. /// \brief Get an InlineCost object representing the cost of inlining this
class InlineCostAnalysis : public CallGraphSCCPass { /// callsite.
TargetTransformInfoWrapperPass *TTIWP; ///
AssumptionCacheTracker *ACT; /// Note that threshold is passed into this function. Only costs below the
/// threshold are computed with any accuracy. The threshold can be used to
/// bound the computation necessary to determine whether the cost is
/// sufficiently low to warrant inlining.
///
/// Also note that calling this function *dynamically* computes the cost of
/// inlining the callsite. It is an expensive, heavyweight call.
InlineCost getInlineCost(CallSite CS, int Threshold,
TargetTransformInfo &CalleeTTI,
AssumptionCacheTracker *ACT);
public: /// \brief Get an InlineCost with the callee explicitly specified.
static char ID; /// This allows you to calculate the cost of inlining a function via a
/// pointer. This behaves exactly as the version with no explicit callee
InlineCostAnalysis(); /// parameter in all other respects.
~InlineCostAnalysis() override; //
InlineCost getInlineCost(CallSite CS, Function *Callee, int Threshold,
// Pass interface implementation. TargetTransformInfo &CalleeTTI,
void getAnalysisUsage(AnalysisUsage &AU) const override; AssumptionCacheTracker *ACT);
bool runOnSCC(CallGraphSCC &SCC) override;
/// \brief Get an InlineCost object representing the cost of inlining this
/// callsite.
///
/// Note that threshold is passed into this function. Only costs below the
/// threshold are computed with any accuracy. The threshold can be used to
/// bound the computation necessary to determine whether the cost is
/// sufficiently low to warrant inlining.
///
/// Also note that calling this function *dynamically* computes the cost of
/// inlining the callsite. It is an expensive, heavyweight call.
InlineCost getInlineCost(CallSite CS, int Threshold);
/// \brief Get an InlineCost with the callee explicitly specified.
/// This allows you to calculate the cost of inlining a function via a
/// pointer. This behaves exactly as the version with no explicit callee
/// parameter in all other respects.
//
// Note: This is used by out-of-tree passes, please do not remove without
// adding a replacement API.
InlineCost getInlineCost(CallSite CS, Function *Callee, int Threshold);
/// \brief Minimal filter to detect invalid constructs for inlining.
bool isInlineViable(Function &Callee);
};
/// \brief Minimal filter to detect invalid constructs for inlining.
bool isInlineViable(Function &Callee);
} }
#endif #endif

View File

@ -20,11 +20,11 @@
#include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/CallGraphSCCPass.h"
namespace llvm { namespace llvm {
class CallSite; class AssumptionCacheTracker;
class DataLayout; class CallSite;
class InlineCost; class DataLayout;
template<class PtrType, unsigned SmallSize> class InlineCost;
class SmallPtrSet; template <class PtrType, unsigned SmallSize> class SmallPtrSet;
/// Inliner - This class contains all of the helper code which is used to /// Inliner - This class contains all of the helper code which is used to
/// perform the inlining operations that do not depend on the policy. /// perform the inlining operations that do not depend on the policy.
@ -84,6 +84,9 @@ private:
/// shouldInline - Return true if the inliner should attempt to /// shouldInline - Return true if the inliner should attempt to
/// inline at the given CallSite. /// inline at the given CallSite.
bool shouldInline(CallSite CS); bool shouldInline(CallSite CS);
protected:
AssumptionCacheTracker *ACT;
}; };
} // End llvm namespace } // End llvm namespace

View File

@ -1319,36 +1319,6 @@ void CallAnalyzer::dump() {
} }
#endif #endif
INITIALIZE_PASS_BEGIN(InlineCostAnalysis, "inline-cost", "Inline Cost Analysis",
true, true)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_END(InlineCostAnalysis, "inline-cost", "Inline Cost Analysis",
true, true)
char InlineCostAnalysis::ID = 0;
InlineCostAnalysis::InlineCostAnalysis() : CallGraphSCCPass(ID) {}
InlineCostAnalysis::~InlineCostAnalysis() {}
void InlineCostAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<TargetTransformInfoWrapperPass>();
CallGraphSCCPass::getAnalysisUsage(AU);
}
bool InlineCostAnalysis::runOnSCC(CallGraphSCC &SCC) {
TTIWP = &getAnalysis<TargetTransformInfoWrapperPass>();
ACT = &getAnalysis<AssumptionCacheTracker>();
return false;
}
InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, int Threshold) {
return getInlineCost(CS, CS.getCalledFunction(), Threshold);
}
/// \brief Test that two functions either have or have not the given attribute /// \brief Test that two functions either have or have not the given attribute
/// at the same time. /// at the same time.
template<typename AttrKind> template<typename AttrKind>
@ -1365,8 +1335,15 @@ static bool functionsHaveCompatibleAttributes(Function *Caller,
AttributeFuncs::areInlineCompatible(*Caller, *Callee); AttributeFuncs::areInlineCompatible(*Caller, *Callee);
} }
InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee, InlineCost llvm::getInlineCost(CallSite CS, int Threshold,
int Threshold) { TargetTransformInfo &CalleeTTI,
AssumptionCacheTracker *ACT) {
return getInlineCost(CS, CS.getCalledFunction(), Threshold, CalleeTTI, ACT);
}
InlineCost llvm::getInlineCost(CallSite CS, Function *Callee, int Threshold,
TargetTransformInfo &CalleeTTI,
AssumptionCacheTracker *ACT) {
// Cannot inline indirect calls. // Cannot inline indirect calls.
if (!Callee) if (!Callee)
return llvm::InlineCost::getNever(); return llvm::InlineCost::getNever();
@ -1381,8 +1358,7 @@ InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee,
// Never inline functions with conflicting attributes (unless callee has // Never inline functions with conflicting attributes (unless callee has
// always-inline attribute). // always-inline attribute).
if (!functionsHaveCompatibleAttributes(CS.getCaller(), Callee, if (!functionsHaveCompatibleAttributes(CS.getCaller(), Callee, CalleeTTI))
TTIWP->getTTI(*Callee)))
return llvm::InlineCost::getNever(); return llvm::InlineCost::getNever();
// Don't inline this call if the caller has the optnone attribute. // Don't inline this call if the caller has the optnone attribute.
@ -1399,7 +1375,7 @@ InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee,
DEBUG(llvm::dbgs() << " Analyzing call of " << Callee->getName() DEBUG(llvm::dbgs() << " Analyzing call of " << Callee->getName()
<< "...\n"); << "...\n");
CallAnalyzer CA(TTIWP->getTTI(*Callee), ACT, *Callee, Threshold, CS); CallAnalyzer CA(CalleeTTI, ACT, *Callee, Threshold, CS);
bool ShouldInline = CA.analyzeCall(CS); bool ShouldInline = CA.analyzeCall(CS);
DEBUG(CA.dump()); DEBUG(CA.dump());
@ -1413,7 +1389,7 @@ InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee,
return llvm::InlineCost::get(CA.getCost(), CA.getThreshold()); return llvm::InlineCost::get(CA.getCost(), CA.getThreshold());
} }
bool InlineCostAnalysis::isInlineViable(Function &F) { bool llvm::isInlineViable(Function &F) {
bool ReturnsTwice = F.hasFnAttribute(Attribute::ReturnsTwice); bool ReturnsTwice = F.hasFnAttribute(Attribute::ReturnsTwice);
for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) { for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) {
// Disallow inlining of functions which contain indirect branches or // Disallow inlining of functions which contain indirect branches or

View File

@ -35,17 +35,15 @@ namespace {
/// \brief Inliner pass which only handles "always inline" functions. /// \brief Inliner pass which only handles "always inline" functions.
class AlwaysInliner : public Inliner { class AlwaysInliner : public Inliner {
InlineCostAnalysis *ICA;
public: public:
// Use extremely low threshold. // Use extremely low threshold.
AlwaysInliner() : Inliner(ID, -2000000000, /*InsertLifetime*/ true), AlwaysInliner() : Inliner(ID, -2000000000, /*InsertLifetime*/ true) {
ICA(nullptr) {
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry()); initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
} }
AlwaysInliner(bool InsertLifetime) AlwaysInliner(bool InsertLifetime)
: Inliner(ID, -2000000000, InsertLifetime), ICA(nullptr) { : Inliner(ID, -2000000000, InsertLifetime) {
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry()); initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
} }
@ -53,9 +51,6 @@ public:
InlineCost getInlineCost(CallSite CS) override; InlineCost getInlineCost(CallSite CS) override;
void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnSCC(CallGraphSCC &SCC) override;
using llvm::Pass::doFinalization; using llvm::Pass::doFinalization;
bool doFinalization(CallGraph &CG) override { bool doFinalization(CallGraph &CG) override {
return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/ true); return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/ true);
@ -69,7 +64,6 @@ INITIALIZE_PASS_BEGIN(AlwaysInliner, "always-inline",
"Inliner for always_inline functions", false, false) "Inliner for always_inline functions", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
INITIALIZE_PASS_DEPENDENCY(InlineCostAnalysis)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(AlwaysInliner, "always-inline", INITIALIZE_PASS_END(AlwaysInliner, "always-inline",
"Inliner for always_inline functions", false, false) "Inliner for always_inline functions", false, false)
@ -99,19 +93,8 @@ InlineCost AlwaysInliner::getInlineCost(CallSite CS) {
// that are viable for inlining. FIXME: We shouldn't even get here for // that are viable for inlining. FIXME: We shouldn't even get here for
// declarations. // declarations.
if (Callee && !Callee->isDeclaration() && if (Callee && !Callee->isDeclaration() &&
CS.hasFnAttr(Attribute::AlwaysInline) && CS.hasFnAttr(Attribute::AlwaysInline) && isInlineViable(*Callee))
ICA->isInlineViable(*Callee))
return InlineCost::getAlways(); return InlineCost::getAlways();
return InlineCost::getNever(); return InlineCost::getNever();
} }
bool AlwaysInliner::runOnSCC(CallGraphSCC &SCC) {
ICA = &getAnalysis<InlineCostAnalysis>();
return Inliner::runOnSCC(SCC);
}
void AlwaysInliner::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<InlineCostAnalysis>();
Inliner::getAnalysisUsage(AU);
}

View File

@ -11,11 +11,11 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/Transforms/IPO.h"
#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/InlineCost.h" #include "llvm/Analysis/InlineCost.h"
#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/CallSite.h" #include "llvm/IR/CallSite.h"
#include "llvm/IR/CallingConv.h" #include "llvm/IR/CallingConv.h"
#include "llvm/IR/DataLayout.h" #include "llvm/IR/DataLayout.h"
@ -23,6 +23,7 @@
#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/IR/Type.h" #include "llvm/IR/Type.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/InlinerPass.h" #include "llvm/Transforms/IPO/InlinerPass.h"
using namespace llvm; using namespace llvm;
@ -37,26 +38,30 @@ namespace {
/// inliner pass and the always inliner pass. The two passes use different cost /// inliner pass and the always inliner pass. The two passes use different cost
/// analyses to determine when to inline. /// analyses to determine when to inline.
class SimpleInliner : public Inliner { class SimpleInliner : public Inliner {
InlineCostAnalysis *ICA;
public: public:
SimpleInliner() : Inliner(ID), ICA(nullptr) { SimpleInliner() : Inliner(ID) {
initializeSimpleInlinerPass(*PassRegistry::getPassRegistry()); initializeSimpleInlinerPass(*PassRegistry::getPassRegistry());
} }
SimpleInliner(int Threshold) SimpleInliner(int Threshold)
: Inliner(ID, Threshold, /*InsertLifetime*/ true), ICA(nullptr) { : Inliner(ID, Threshold, /*InsertLifetime*/ true) {
initializeSimpleInlinerPass(*PassRegistry::getPassRegistry()); initializeSimpleInlinerPass(*PassRegistry::getPassRegistry());
} }
static char ID; // Pass identification, replacement for typeid static char ID; // Pass identification, replacement for typeid
InlineCost getInlineCost(CallSite CS) override { InlineCost getInlineCost(CallSite CS) override {
return ICA->getInlineCost(CS, getInlineThreshold(CS)); Function *Callee = CS.getCalledFunction();
TargetTransformInfo &TTI = TTIWP->getTTI(*Callee);
return llvm::getInlineCost(CS, getInlineThreshold(CS), TTI, ACT);
} }
bool runOnSCC(CallGraphSCC &SCC) override; bool runOnSCC(CallGraphSCC &SCC) override;
void getAnalysisUsage(AnalysisUsage &AU) const override; void getAnalysisUsage(AnalysisUsage &AU) const override;
private:
TargetTransformInfoWrapperPass *TTIWP;
}; };
static int computeThresholdFromOptLevels(unsigned OptLevel, static int computeThresholdFromOptLevels(unsigned OptLevel,
@ -77,7 +82,7 @@ INITIALIZE_PASS_BEGIN(SimpleInliner, "inline",
"Function Integration/Inlining", false, false) "Function Integration/Inlining", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
INITIALIZE_PASS_DEPENDENCY(InlineCostAnalysis) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(SimpleInliner, "inline", INITIALIZE_PASS_END(SimpleInliner, "inline",
"Function Integration/Inlining", false, false) "Function Integration/Inlining", false, false)
@ -95,11 +100,11 @@ Pass *llvm::createFunctionInliningPass(unsigned OptLevel,
} }
bool SimpleInliner::runOnSCC(CallGraphSCC &SCC) { bool SimpleInliner::runOnSCC(CallGraphSCC &SCC) {
ICA = &getAnalysis<InlineCostAnalysis>(); TTIWP = &getAnalysis<TargetTransformInfoWrapperPass>();
return Inliner::runOnSCC(SCC); return Inliner::runOnSCC(SCC);
} }
void SimpleInliner::getAnalysisUsage(AnalysisUsage &AU) const { void SimpleInliner::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<InlineCostAnalysis>(); AU.addRequired<TargetTransformInfoWrapperPass>();
Inliner::getAnalysisUsage(AU); Inliner::getAnalysisUsage(AU);
} }

View File

@ -65,13 +65,15 @@ ColdThreshold("inlinecold-threshold", cl::Hidden, cl::init(225),
// Threshold to use when optsize is specified (and there is no -inline-limit). // Threshold to use when optsize is specified (and there is no -inline-limit).
const int OptSizeThreshold = 75; const int OptSizeThreshold = 75;
Inliner::Inliner(char &ID) Inliner::Inliner(char &ID)
: CallGraphSCCPass(ID), InlineThreshold(InlineLimit), InsertLifetime(true) {} : CallGraphSCCPass(ID), InlineThreshold(InlineLimit), InsertLifetime(true) {
}
Inliner::Inliner(char &ID, int Threshold, bool InsertLifetime) Inliner::Inliner(char &ID, int Threshold, bool InsertLifetime)
: CallGraphSCCPass(ID), InlineThreshold(InlineLimit.getNumOccurrences() > 0 ? : CallGraphSCCPass(ID),
InlineLimit : Threshold), InlineThreshold(InlineLimit.getNumOccurrences() > 0 ? InlineLimit
InsertLifetime(InsertLifetime) {} : Threshold),
InsertLifetime(InsertLifetime) {}
/// For this class, we declare that we require and preserve the call graph. /// For this class, we declare that we require and preserve the call graph.
/// If the derived class implements this method, it should /// If the derived class implements this method, it should
@ -439,7 +441,7 @@ static bool InlineHistoryIncludes(Function *F, int InlineHistoryID,
bool Inliner::runOnSCC(CallGraphSCC &SCC) { bool Inliner::runOnSCC(CallGraphSCC &SCC) {
CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
AssumptionCacheTracker *ACT = &getAnalysis<AssumptionCacheTracker>(); ACT = &getAnalysis<AssumptionCacheTracker>();
auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
SmallPtrSet<Function*, 8> SCCFunctions; SmallPtrSet<Function*, 8> SCCFunctions;