X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTransforms%2FIPO%2FInlineAlways.cpp;h=b1c36c15db0bcaaaf6d5055256e228228ca22744;hb=6765834754cbb3cb0f15b4b15e98c5e73fa50066;hp=2344403391cf2f16a06d3aadd9a886db29e0483b;hpb=e4aeec003f82a5263ffb168e175e6fca8b6f681d;p=oota-llvm.git diff --git a/lib/Transforms/IPO/InlineAlways.cpp b/lib/Transforms/IPO/InlineAlways.cpp index 2344403391c..b1c36c15db0 100644 --- a/lib/Transforms/IPO/InlineAlways.cpp +++ b/lib/Transforms/IPO/InlineAlways.cpp @@ -21,9 +21,9 @@ #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/InlineCost.h" #include "llvm/Support/CallSite.h" -#include "llvm/Support/Compiler.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/InlinerPass.h" +#include "llvm/DataLayout.h" #include "llvm/ADT/SmallPtrSet.h" using namespace llvm; @@ -31,45 +31,102 @@ using namespace llvm; namespace { // AlwaysInliner only inlines functions that are mark as "always inline". - class VISIBILITY_HIDDEN AlwaysInliner : public Inliner { - // Functions that are never inlined - SmallPtrSet NeverInline; - InlineCostAnalyzer CA; + class AlwaysInliner : public Inliner { public: - // Use extremely low threshold. - AlwaysInliner() : Inliner(&ID, -2000000000) {} - static char ID; // Pass identification, replacement for typeid - InlineCost getInlineCost(CallSite CS) { - return CA.getInlineCost(CS, NeverInline); - } - float getInlineFudgeFactor(CallSite CS) { - return CA.getInlineFudgeFactor(CS); + // Use extremely low threshold. + AlwaysInliner() : Inliner(ID, -2000000000, /*InsertLifetime*/true) { + initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry()); } - void resetCachedCostInfo(Function *Caller) { - return CA.resetCachedCostInfo(Caller); + AlwaysInliner(bool InsertLifetime) : Inliner(ID, -2000000000, + InsertLifetime) { + initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry()); } - virtual bool doFinalization(CallGraph &CG) { - return removeDeadFunctions(CG, &NeverInline); + static char ID; // Pass identification, replacement for typeid + virtual InlineCost getInlineCost(CallSite CS); + virtual bool doFinalization(CallGraph &CG) { + return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/true); } virtual bool doInitialization(CallGraph &CG); }; } char AlwaysInliner::ID = 0; -static RegisterPass -X("always-inline", "Inliner for always_inline functions"); +INITIALIZE_PASS_BEGIN(AlwaysInliner, "always-inline", + "Inliner for always_inline functions", false, false) +INITIALIZE_AG_DEPENDENCY(CallGraph) +INITIALIZE_PASS_END(AlwaysInliner, "always-inline", + "Inliner for always_inline functions", false, false) Pass *llvm::createAlwaysInlinerPass() { return new AlwaysInliner(); } -// doInitialization - Initializes the vector of functions that have not +Pass *llvm::createAlwaysInlinerPass(bool InsertLifetime) { + return new AlwaysInliner(InsertLifetime); +} + +/// \brief Minimal filter to detect invalid constructs for inlining. +static bool isInlineViable(Function &F) { + bool ReturnsTwice =F.getFnAttributes().hasAttribute(Attributes::ReturnsTwice); + for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) { + // Disallow inlining of functions which contain an indirect branch. + if (isa(BI->getTerminator())) + return false; + + for (BasicBlock::iterator II = BI->begin(), IE = BI->end(); II != IE; + ++II) { + CallSite CS(II); + if (!CS) + continue; + + // Disallow recursive calls. + if (&F == CS.getCalledFunction()) + return false; + + // Disallow calls which expose returns-twice to a function not previously + // attributed as such. + if (!ReturnsTwice && CS.isCall() && + cast(CS.getInstruction())->canReturnTwice()) + return false; + } + } + + return true; +} + +/// \brief Get the inline cost for the always-inliner. +/// +/// The always inliner *only* handles functions which are marked with the +/// attribute to force inlining. As such, it is dramatically simpler and avoids +/// using the powerful (but expensive) inline cost analysis. Instead it uses +/// a very simple and boring direct walk of the instructions looking for +/// impossible-to-inline constructs. +/// +/// Note, it would be possible to go to some lengths to cache the information +/// computed here, but as we only expect to do this for relatively few and +/// small functions which have the explicit attribute to force inlining, it is +/// likely not worth it in practice. +InlineCost AlwaysInliner::getInlineCost(CallSite CS) { + 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->getFnAttributes().hasAttribute(Attributes::AlwaysInline)) + return InlineCost::getNever(); + + // Do some minimal analysis to preclude non-viable functions. + if (!isInlineViable(*Callee)) + return InlineCost::getNever(); + + // Otherwise, force inlining. + return InlineCost::getAlways(); +} + +// doInitialization - Initializes the vector of functions that have not // been annotated with the "always inline" attribute. bool AlwaysInliner::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::AlwaysInline)) - NeverInline.insert(I); - return false; }