diff options
Diffstat (limited to 'contrib/llvm/lib/Transforms/IPO/InlineAlways.cpp')
| -rw-r--r-- | contrib/llvm/lib/Transforms/IPO/InlineAlways.cpp | 102 | 
1 files changed, 73 insertions, 29 deletions
diff --git a/contrib/llvm/lib/Transforms/IPO/InlineAlways.cpp b/contrib/llvm/lib/Transforms/IPO/InlineAlways.cpp index c0426da2c687..664ddf6f7a2b 100644 --- a/contrib/llvm/lib/Transforms/IPO/InlineAlways.cpp +++ b/contrib/llvm/lib/Transforms/IPO/InlineAlways.cpp @@ -32,34 +32,21 @@ 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. -    AlwaysInliner() : Inliner(ID, -2000000000) { +    AlwaysInliner() : Inliner(ID, -2000000000, /*InsertLifetime*/true) {        initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());      } -    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); -    } -    void resetCachedCostInfo(Function *Caller) { -      CA.resetCachedCostInfo(Caller); -    } -    void growCachedCostInfo(Function* Caller, Function* Callee) { -      CA.growCachedCostInfo(Caller, Callee); +    AlwaysInliner(bool InsertLifetime) : Inliner(ID, -2000000000, +                                                 InsertLifetime) { +      initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());      } +    static char ID; // Pass identification, replacement for typeid +    virtual InlineCost getInlineCost(CallSite CS);      virtual bool doFinalization(CallGraph &CG) { -      return removeDeadFunctions(CG, &NeverInline); +      return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/true);      }      virtual bool doInitialization(CallGraph &CG); -    void releaseMemory() { -      CA.clear(); -    }    };  } @@ -72,17 +59,74 @@ INITIALIZE_PASS_END(AlwaysInliner, "always-inline",  Pass *llvm::createAlwaysInlinerPass() { return new AlwaysInliner(); } -// doInitialization - Initializes the vector of functions that have not -// been annotated with the "always inline" attribute. -bool AlwaysInliner::doInitialization(CallGraph &CG) { -  CA.setTargetData(getAnalysisIfAvailable<TargetData>()); +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.hasFnAttr(Attribute::ReturnsTwice); +  for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) { +    // Disallow inlining of functions which contain an indirect branch. +    if (isa<IndirectBrInst>(BI->getTerminator())) +      return false; -  Module &M = CG.getModule(); +    for (BasicBlock::iterator II = BI->begin(), IE = BI->end(); II != IE; +         ++II) { +      CallSite CS(II); +      if (!CS) +        continue; -  for (Module::iterator I = M.begin(), E = M.end(); -       I != E; ++I) -    if (!I->isDeclaration() && !I->hasFnAttr(Attribute::AlwaysInline)) -      NeverInline.insert(I); +      // 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<CallInst>(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->hasFnAttr(Attribute::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) {    return false;  }  | 
