summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Analysis/InlineCost.h7
-rw-r--r--include/llvm/Transforms/IPO/InlinerPass.h12
-rw-r--r--lib/Analysis/InlineCost.cpp12
-rw-r--r--lib/Transforms/IPO/InlineAlways.cpp28
-rw-r--r--lib/Transforms/IPO/InlineSimple.cpp16
-rw-r--r--lib/Transforms/IPO/Inliner.cpp40
6 files changed, 64 insertions, 51 deletions
diff --git a/include/llvm/Analysis/InlineCost.h b/include/llvm/Analysis/InlineCost.h
index 19a9c8192b..c804c46528 100644
--- a/include/llvm/Analysis/InlineCost.h
+++ b/include/llvm/Analysis/InlineCost.h
@@ -166,16 +166,13 @@ namespace llvm {
/// getInlineCost - The heuristic used to determine if we should inline the
/// function call or not.
///
- InlineCost getInlineCost(CallSite CS,
- SmallPtrSet<const Function *, 16> &NeverInline);
+ InlineCost getInlineCost(CallSite CS);
/// getCalledFunction - The heuristic used to determine if we should inline
/// the function call or not. The callee is explicitly specified, to allow
/// you to calculate the cost of inlining a function via a pointer. The
/// result assumes that the inlined version will always be used. You should
/// weight it yourself in cases where this callee will not always be called.
- InlineCost getInlineCost(CallSite CS,
- Function *Callee,
- SmallPtrSet<const Function *, 16> &NeverInline);
+ InlineCost getInlineCost(CallSite CS, Function *Callee);
/// getInlineFudgeFactor - Return a > 1.0 factor if the inliner should use a
/// higher threshold to determine if the function call should be inlined.
diff --git a/include/llvm/Transforms/IPO/InlinerPass.h b/include/llvm/Transforms/IPO/InlinerPass.h
index 1feaaa475b..f59479d738 100644
--- a/include/llvm/Transforms/IPO/InlinerPass.h
+++ b/include/llvm/Transforms/IPO/InlinerPass.h
@@ -79,10 +79,14 @@ struct Inliner : public CallGraphSCCPass {
/// has been inlined.
virtual void growCachedCostInfo(Function *Caller, Function *Callee) = 0;
- /// removeDeadFunctions - Remove dead functions that are not included in
- /// DNR (Do Not Remove) list.
- bool removeDeadFunctions(CallGraph &CG,
- SmallPtrSet<const Function *, 16> *DNR = NULL);
+ /// removeDeadFunctions - Remove dead functions.
+ ///
+ /// This also includes a hack in the form of the 'AlwaysInlineOnly' flag
+ /// which restricts it to deleting functions with an 'AlwaysInline'
+ /// attribute. This is useful for the InlineAlways pass that only wants to
+ /// deal with that subset of the functions.
+ bool removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly = false);
+
private:
// InlineThreshold - Cache the value here for easy access.
unsigned InlineThreshold;
diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp
index e08ff92618..dedbfebea7 100644
--- a/lib/Analysis/InlineCost.cpp
+++ b/lib/Analysis/InlineCost.cpp
@@ -520,22 +520,18 @@ int InlineCostAnalyzer::getInlineBonuses(CallSite CS, Function *Callee) {
// getInlineCost - The heuristic used to determine if we should inline the
// function call or not.
//
-InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS,
- SmallPtrSet<const Function*, 16> &NeverInline) {
- return getInlineCost(CS, CS.getCalledFunction(), NeverInline);
+InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS) {
+ return getInlineCost(CS, CS.getCalledFunction());
}
-InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS,
- Function *Callee,
- SmallPtrSet<const Function*, 16> &NeverInline) {
+InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, Function *Callee) {
Instruction *TheCall = CS.getInstruction();
Function *Caller = TheCall->getParent()->getParent();
// Don't inline functions which can be redefined at link-time to mean
// something else. Don't inline functions marked noinline or call sites
// marked noinline.
- if (Callee->mayBeOverridden() ||
- Callee->hasFnAttr(Attribute::NoInline) || NeverInline.count(Callee) ||
+ if (Callee->mayBeOverridden() || Callee->hasFnAttr(Attribute::NoInline) ||
CS.isNoInline())
return llvm::InlineCost::getNever();
diff --git a/lib/Transforms/IPO/InlineAlways.cpp b/lib/Transforms/IPO/InlineAlways.cpp
index 749a3fa23d..3c7fac6cc1 100644
--- a/lib/Transforms/IPO/InlineAlways.cpp
+++ b/lib/Transforms/IPO/InlineAlways.cpp
@@ -32,8 +32,6 @@ namespace {
// AlwaysInliner only inlines functions that are mark as "always inline".
class AlwaysInliner : public Inliner {
- // Functions that are never inlined
- SmallPtrSet<const Function*, 16> NeverInline;
InlineCostAnalyzer CA;
public:
// Use extremely low threshold.
@@ -46,7 +44,22 @@ namespace {
}
static char ID; // Pass identification, replacement for typeid
InlineCost getInlineCost(CallSite CS) {
- return CA.getInlineCost(CS, NeverInline);
+ Function *Callee = CS.getCalledFunction();
+ // We assume indirect calls aren't calling an always-inline function.
+ if (!Callee) return InlineCost::getNever();
+
+ // We can't inline calls to external functions.
+ // FIXME: We shouldn't even get here.
+ if (Callee->isDeclaration()) return InlineCost::getNever();
+
+ // Return never for anything not marked as always inline.
+ if (!Callee->hasFnAttr(Attribute::AlwaysInline))
+ return InlineCost::getNever();
+
+ // We still have to check the inline cost in case there are reasons to
+ // not inline which trump the always-inline attribute such as setjmp and
+ // indirectbr.
+ return CA.getInlineCost(CS);
}
float getInlineFudgeFactor(CallSite CS) {
return CA.getInlineFudgeFactor(CS);
@@ -58,7 +71,7 @@ namespace {
CA.growCachedCostInfo(Caller, Callee);
}
virtual bool doFinalization(CallGraph &CG) {
- return removeDeadFunctions(CG, &NeverInline);
+ return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/true);
}
virtual bool doInitialization(CallGraph &CG);
void releaseMemory() {
@@ -84,12 +97,5 @@ Pass *llvm::createAlwaysInlinerPass(bool InsertLifetime) {
// been annotated with the "always inline" attribute.
bool AlwaysInliner::doInitialization(CallGraph &CG) {
CA.setTargetData(getAnalysisIfAvailable<TargetData>());
-
- Module &M = CG.getModule();
-
- for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
- if (!I->isDeclaration() && !I->hasFnAttr(Attribute::AlwaysInline))
- NeverInline.insert(I);
-
return false;
}
diff --git a/lib/Transforms/IPO/InlineSimple.cpp b/lib/Transforms/IPO/InlineSimple.cpp
index b3421ebd64..a7aeed8afc 100644
--- a/lib/Transforms/IPO/InlineSimple.cpp
+++ b/lib/Transforms/IPO/InlineSimple.cpp
@@ -43,7 +43,16 @@ namespace {
}
static char ID; // Pass identification, replacement for typeid
InlineCost getInlineCost(CallSite CS) {
- return CA.getInlineCost(CS, NeverInline);
+ // Filter out functions which should never be inlined due to the global
+ // 'llvm.noinline'.
+ // FIXME: I'm 99% certain that this is an ancient bit of legacy that we
+ // no longer need to support, but I don't want to blindly nuke it just
+ // yet.
+ if (Function *Callee = CS.getCalledFunction())
+ if (NeverInline.count(Callee))
+ return InlineCost::getNever();
+
+ return CA.getInlineCost(CS);
}
float getInlineFudgeFactor(CallSite CS) {
return CA.getInlineFudgeFactor(CS);
@@ -81,11 +90,6 @@ bool SimpleInliner::doInitialization(CallGraph &CG) {
Module &M = CG.getModule();
- for (Module::iterator I = M.begin(), E = M.end();
- I != E; ++I)
- if (!I->isDeclaration() && I->hasFnAttr(Attribute::NoInline))
- NeverInline.insert(I);
-
// Get llvm.noinline
GlobalVariable *GV = M.getNamedGlobal("llvm.noinline");
diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp
index 49042f2493..9975333976 100644
--- a/lib/Transforms/IPO/Inliner.cpp
+++ b/lib/Transforms/IPO/Inliner.cpp
@@ -556,25 +556,27 @@ bool Inliner::doFinalization(CallGraph &CG) {
/// removeDeadFunctions - Remove dead functions that are not included in
/// DNR (Do Not Remove) list.
-bool Inliner::removeDeadFunctions(CallGraph &CG,
- SmallPtrSet<const Function *, 16> *DNR) {
- SmallPtrSet<CallGraphNode*, 16> FunctionsToRemove;
+bool Inliner::removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly) {
+ SmallVector<CallGraphNode*, 16> FunctionsToRemove;
// Scan for all of the functions, looking for ones that should now be removed
// from the program. Insert the dead ones in the FunctionsToRemove set.
for (CallGraph::iterator I = CG.begin(), E = CG.end(); I != E; ++I) {
CallGraphNode *CGN = I->second;
- if (CGN->getFunction() == 0)
- continue;
-
Function *F = CGN->getFunction();
-
+ if (!F || F->isDeclaration())
+ continue;
+
+ // Handle the case when this function is called and we only want to care
+ // about always-inline functions. This is a bit of a hack to share code
+ // between here and the InlineAlways pass.
+ if (AlwaysInlineOnly && !F->hasFnAttr(Attribute::AlwaysInline))
+ continue;
+
// If the only remaining users of the function are dead constants, remove
// them.
F->removeDeadConstantUsers();
- if (DNR && DNR->count(F))
- continue;
if (!F->isDefTriviallyDead())
continue;
@@ -587,24 +589,28 @@ bool Inliner::removeDeadFunctions(CallGraph &CG,
CG.getExternalCallingNode()->removeAnyCallEdgeTo(CGN);
// Removing the node for callee from the call graph and delete it.
- FunctionsToRemove.insert(CGN);
+ FunctionsToRemove.push_back(CGN);
}
+ if (FunctionsToRemove.empty())
+ return false;
// Now that we know which functions to delete, do so. We didn't want to do
// this inline, because that would invalidate our CallGraph::iterator
// objects. :(
//
- // Note that it doesn't matter that we are iterating over a non-stable set
+ // Note that it doesn't matter that we are iterating over a non-stable order
// here to do this, it doesn't matter which order the functions are deleted
// in.
- bool Changed = false;
- for (SmallPtrSet<CallGraphNode*, 16>::iterator I = FunctionsToRemove.begin(),
- E = FunctionsToRemove.end(); I != E; ++I) {
+ std::sort(FunctionsToRemove.begin(), FunctionsToRemove.end());
+ FunctionsToRemove.erase(std::unique(FunctionsToRemove.begin(),
+ FunctionsToRemove.end()),
+ FunctionsToRemove.end());
+ for (SmallVectorImpl<CallGraphNode *>::iterator I = FunctionsToRemove.begin(),
+ E = FunctionsToRemove.end();
+ I != E; ++I) {
resetCachedCostInfo((*I)->getFunction());
delete CG.removeFunctionFromModule(*I);
++NumDeleted;
- Changed = true;
}
-
- return Changed;
+ return true;
}