Make the inline cost a proper analysis pass. This remains essentially

a dynamic analysis done on each call to the routine. However, now it can
use the standard pass infrastructure to reference other analyses,
instead of a silly setter method. This will become more interesting as
I teach it about more analysis passes.

This updates the two inliner passes to use the inline cost analysis.
Doing so highlights how utterly redundant these two passes are. Either
we should find a cheaper way to do always inlining, or we should merge
the two and just fiddle with the thresholds to get the desired behavior.
I'm leaning increasingly toward the latter as it would also remove the
Inliner sub-class split.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@173030 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chandler Carruth
2013-01-21 11:39:18 +00:00
parent 0378e3916a
commit 86953b5795
5 changed files with 70 additions and 30 deletions

View File

@@ -15,6 +15,7 @@
#define LLVM_ANALYSIS_INLINECOST_H #define LLVM_ANALYSIS_INLINECOST_H
#include "llvm/Analysis/CodeMetrics.h" #include "llvm/Analysis/CodeMetrics.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include <cassert> #include <cassert>
#include <climits> #include <climits>
@@ -97,14 +98,18 @@ public:
}; };
/// \brief Cost analyzer used by inliner. /// \brief Cost analyzer used by inliner.
class InlineCostAnalyzer { class InlineCostAnalysis : public CallGraphSCCPass {
// DataLayout if available, or null.
const DataLayout *TD; const DataLayout *TD;
public: public:
InlineCostAnalyzer() : TD(0) {} static char ID;
void setDataLayout(const DataLayout *TData) { TD = TData; } InlineCostAnalysis();
~InlineCostAnalysis();
// Pass interface implementation.
void getAnalysisUsage(AnalysisUsage &AU) const;
bool runOnSCC(CallGraphSCC &SCC);
/// \brief Get an InlineCost object representing the cost of inlining this /// \brief Get an InlineCost object representing the cost of inlining this
/// callsite. /// callsite.
@@ -113,6 +118,9 @@ public:
/// threshold are computed with any accuracy. The threshold can be used to /// threshold are computed with any accuracy. The threshold can be used to
/// bound the computation necessary to determine whether the cost is /// bound the computation necessary to determine whether the cost is
/// sufficiently low to warrant inlining. /// 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); InlineCost getInlineCost(CallSite CS, int Threshold);
/// \brief Get an InlineCost with the callee explicitly specified. /// \brief Get an InlineCost with the callee explicitly specified.

View File

@@ -132,6 +132,7 @@ void initializeIPSCCPPass(PassRegistry&);
void initializeIVUsersPass(PassRegistry&); void initializeIVUsersPass(PassRegistry&);
void initializeIfConverterPass(PassRegistry&); void initializeIfConverterPass(PassRegistry&);
void initializeIndVarSimplifyPass(PassRegistry&); void initializeIndVarSimplifyPass(PassRegistry&);
void initializeInlineCostAnalysisPass(PassRegistry&);
void initializeInstCombinerPass(PassRegistry&); void initializeInstCombinerPass(PassRegistry&);
void initializeInstCountPass(PassRegistry&); void initializeInstCountPass(PassRegistry&);
void initializeInstNamerPass(PassRegistry&); void initializeInstNamerPass(PassRegistry&);

View File

@@ -1132,11 +1132,32 @@ void CallAnalyzer::dump() {
} }
#endif #endif
InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, int Threshold) { INITIALIZE_PASS_BEGIN(InlineCostAnalysis, "inline-cost", "Inline Cost Analysis",
true, true)
INITIALIZE_PASS_END(InlineCostAnalysis, "inline-cost", "Inline Cost Analysis",
true, true)
char InlineCostAnalysis::ID = 0;
InlineCostAnalysis::InlineCostAnalysis() : CallGraphSCCPass(ID), TD(0) {}
InlineCostAnalysis::~InlineCostAnalysis() {}
void InlineCostAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
CallGraphSCCPass::getAnalysisUsage(AU);
}
bool InlineCostAnalysis::runOnSCC(CallGraphSCC &SCC) {
TD = getAnalysisIfAvailable<DataLayout>();
return false;
}
InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, int Threshold) {
return getInlineCost(CS, CS.getCalledFunction(), Threshold); return getInlineCost(CS, CS.getCalledFunction(), Threshold);
} }
InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, Function *Callee, InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee,
int Threshold) { int Threshold) {
// Cannot inline indirect calls. // Cannot inline indirect calls.
if (!Callee) if (!Callee)
@@ -1177,9 +1198,10 @@ InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, Function *Callee,
return llvm::InlineCost::get(CA.getCost(), CA.getThreshold()); return llvm::InlineCost::get(CA.getCost(), CA.getThreshold());
} }
bool InlineCostAnalyzer::isInlineViable(Function &F) { bool InlineCostAnalysis::isInlineViable(Function &F) {
bool ReturnsTwice =F.getAttributes().hasAttribute(AttributeSet::FunctionIndex, bool ReturnsTwice =
Attribute::ReturnsTwice); F.getAttributes().hasAttribute(AttributeSet::FunctionIndex,
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 an indirect branch. // Disallow inlining of functions which contain an indirect branch.
if (isa<IndirectBrInst>(BI->getTerminator())) if (isa<IndirectBrInst>(BI->getTerminator()))

View File

@@ -32,16 +32,16 @@ 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 {
InlineCostAnalyzer CA; 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(0) {
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry()); initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
} }
AlwaysInliner(bool InsertLifetime) AlwaysInliner(bool InsertLifetime)
: Inliner(ID, -2000000000, InsertLifetime) { : Inliner(ID, -2000000000, InsertLifetime), ICA(0) {
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry()); initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
} }
@@ -49,13 +49,13 @@ public:
virtual InlineCost getInlineCost(CallSite CS); virtual InlineCost getInlineCost(CallSite CS);
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
virtual bool runOnSCC(CallGraphSCC &SCC);
using llvm::Pass::doFinalization; using llvm::Pass::doFinalization;
virtual bool doFinalization(CallGraph &CG) { virtual bool doFinalization(CallGraph &CG) {
return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/ true); return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/ true);
} }
using llvm::Pass::doInitialization;
virtual bool doInitialization(CallGraph &CG);
}; };
} }
@@ -64,6 +64,7 @@ char AlwaysInliner::ID = 0;
INITIALIZE_PASS_BEGIN(AlwaysInliner, "always-inline", INITIALIZE_PASS_BEGIN(AlwaysInliner, "always-inline",
"Inliner for always_inline functions", false, false) "Inliner for always_inline functions", false, false)
INITIALIZE_AG_DEPENDENCY(CallGraph) INITIALIZE_AG_DEPENDENCY(CallGraph)
INITIALIZE_PASS_DEPENDENCY(InlineCostAnalysis)
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)
@@ -94,13 +95,18 @@ InlineCost AlwaysInliner::getInlineCost(CallSite CS) {
if (Callee && !Callee->isDeclaration() && if (Callee && !Callee->isDeclaration() &&
Callee->getAttributes().hasAttribute(AttributeSet::FunctionIndex, Callee->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::AlwaysInline) && Attribute::AlwaysInline) &&
CA.isInlineViable(*Callee)) ICA->isInlineViable(*Callee))
return InlineCost::getAlways(); return InlineCost::getAlways();
return InlineCost::getNever(); return InlineCost::getNever();
} }
bool AlwaysInliner::doInitialization(CallGraph &CG) { bool AlwaysInliner::runOnSCC(CallGraphSCC &SCC) {
CA.setDataLayout(getAnalysisIfAvailable<DataLayout>()); ICA = &getAnalysis<InlineCostAnalysis>();
return false; return Inliner::runOnSCC(SCC);
}
void AlwaysInliner::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<InlineCostAnalysis>();
Inliner::getAnalysisUsage(AU);
} }

View File

@@ -34,26 +34,26 @@ 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 {
InlineCostAnalyzer CA; InlineCostAnalysis *ICA;
public: public:
SimpleInliner() : Inliner(ID) { SimpleInliner() : Inliner(ID), ICA(0) {
initializeSimpleInlinerPass(*PassRegistry::getPassRegistry()); initializeSimpleInlinerPass(*PassRegistry::getPassRegistry());
} }
SimpleInliner(int Threshold) SimpleInliner(int Threshold)
: Inliner(ID, Threshold, /*InsertLifetime*/ true) { : Inliner(ID, Threshold, /*InsertLifetime*/ true), ICA(0) {
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) { InlineCost getInlineCost(CallSite CS) {
return CA.getInlineCost(CS, getInlineThreshold(CS)); return ICA->getInlineCost(CS, getInlineThreshold(CS));
} }
using llvm::Pass::doInitialization; virtual bool runOnSCC(CallGraphSCC &SCC);
virtual bool doInitialization(CallGraph &CG); virtual void getAnalysisUsage(AnalysisUsage &AU) const;
}; };
} // end anonymous namespace } // end anonymous namespace
@@ -62,6 +62,7 @@ char SimpleInliner::ID = 0;
INITIALIZE_PASS_BEGIN(SimpleInliner, "inline", INITIALIZE_PASS_BEGIN(SimpleInliner, "inline",
"Function Integration/Inlining", false, false) "Function Integration/Inlining", false, false)
INITIALIZE_AG_DEPENDENCY(CallGraph) INITIALIZE_AG_DEPENDENCY(CallGraph)
INITIALIZE_PASS_DEPENDENCY(InlineCostAnalysis)
INITIALIZE_PASS_END(SimpleInliner, "inline", INITIALIZE_PASS_END(SimpleInliner, "inline",
"Function Integration/Inlining", false, false) "Function Integration/Inlining", false, false)
@@ -71,10 +72,12 @@ Pass *llvm::createFunctionInliningPass(int Threshold) {
return new SimpleInliner(Threshold); return new SimpleInliner(Threshold);
} }
// doInitialization - Initializes the vector of functions that have been bool SimpleInliner::runOnSCC(CallGraphSCC &SCC) {
// annotated with the noinline attribute. ICA = &getAnalysis<InlineCostAnalysis>();
bool SimpleInliner::doInitialization(CallGraph &CG) { return Inliner::runOnSCC(SCC);
CA.setDataLayout(getAnalysisIfAvailable<DataLayout>());
return false;
} }
void SimpleInliner::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<InlineCostAnalysis>();
Inliner::getAnalysisUsage(AU);
}