diff --git a/include/llvm/Analysis/InlineCost.h b/include/llvm/Analysis/InlineCost.h index 19a9c8192bc..c804c465286 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 &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 &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 1feaaa475b4..f59479d7382 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 *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 e08ff926183..dedbfebea70 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 &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 &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 749a3fa23de..3c7fac6cc10 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 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()); - - 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 b3421ebd648..a7aeed8afc3 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 49042f2493f..9975333976d 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 *DNR) { - SmallPtrSet FunctionsToRemove; +bool Inliner::removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly) { + SmallVector 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::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::iterator I = FunctionsToRemove.begin(), + E = FunctionsToRemove.end(); + I != E; ++I) { resetCachedCostInfo((*I)->getFunction()); delete CG.removeFunctionFromModule(*I); ++NumDeleted; - Changed = true; } - - return Changed; + return true; }