Adjustments to last patch based on review.
[oota-llvm.git] / lib / Transforms / IPO / Inliner.cpp
index 845ffd864e3f05813f2d4460d872c69c26c66d18..639f3a84cb5f21b92f6db2fc983ecdb1fae70e1a 100644 (file)
@@ -34,11 +34,11 @@ static cl::opt<int>
 InlineLimit("inline-threshold", cl::Hidden, cl::init(200),
         cl::desc("Control the amount of inlining to perform (default = 200)"));
 
-Inliner::Inliner(const void *ID) 
-  : CallGraphSCCPass((intptr_t)ID), InlineThreshold(InlineLimit) {}
+Inliner::Inliner(void *ID) 
+  : CallGraphSCCPass(ID), InlineThreshold(InlineLimit) {}
 
-Inliner::Inliner(const void *ID, int Threshold) 
-  : CallGraphSCCPass((intptr_t)ID), InlineThreshold(Threshold) {}
+Inliner::Inliner(void *ID, int Threshold) 
+  : CallGraphSCCPass(ID), InlineThreshold(Threshold) {}
 
 /// getAnalysisUsage - For this class, we declare that we require and preserve
 /// the call graph.  If the derived class implements this method, it should
@@ -54,18 +54,27 @@ static bool InlineCallIfPossible(CallSite CS, CallGraph &CG,
                                  const std::set<Function*> &SCCFunctions,
                                  const TargetData &TD) {
   Function *Callee = CS.getCalledFunction();
+  Function *Caller = CS.getCaller();
+
   if (!InlineFunction(CS, &CG, &TD)) return false;
 
+  // If the inlined function had a higher stack protection level than the
+  // calling function, then bump up the caller's stack protection level.
+  if (Callee->hasFnAttr(Attribute::StackProtectReq))
+    Caller->addFnAttr(Attribute::StackProtectReq);
+  else if (Callee->hasFnAttr(Attribute::StackProtect) &&
+           !Caller->hasFnAttr(Attribute::StackProtectReq))
+    Caller->addFnAttr(Attribute::StackProtect);
+
   // If we inlined the last possible call site to the function, delete the
   // function body now.
   if (Callee->use_empty() && Callee->hasInternalLinkage() &&
       !SCCFunctions.count(Callee)) {
     DOUT << "    -> Deleting dead function: " << Callee->getName() << "\n";
+    CallGraphNode *CalleeNode = CG[Callee];
 
     // Remove any call graph edges from the callee to its callees.
-    CallGraphNode *CalleeNode = CG[Callee];
-    while (!CalleeNode->empty())
-      CalleeNode->removeCallEdgeTo((CalleeNode->end()-1)->second);
+    CalleeNode->removeAllCalledFunctions();
 
     // Removing the node for callee from the call graph and delete it.
     delete CG.removeFunctionFromModule(CalleeNode);
@@ -73,6 +82,44 @@ static bool InlineCallIfPossible(CallSite CS, CallGraph &CG,
   }
   return true;
 }
+        
+/// shouldInline - Return true if the inliner should attempt to inline
+/// at the given CallSite.
+bool Inliner::shouldInline(CallSite CS) {
+  InlineCost IC = getInlineCost(CS);
+  float FudgeFactor = getInlineFudgeFactor(CS);
+  
+  if (IC.isAlways()) {
+    DOUT << "    Inlining: cost=always"
+         << ", Call: " << *CS.getInstruction();
+    return true;
+  }
+  
+  if (IC.isNever()) {
+    DOUT << "    NOT Inlining: cost=never"
+         << ", Call: " << *CS.getInstruction();
+    return false;
+  }
+  
+  int Cost = IC.getValue();
+  int CurrentThreshold = InlineThreshold;
+  Function *Fn = CS.getCaller();
+  if (Fn && !Fn->isDeclaration() 
+      && Fn->hasFnAttr(Attribute::OptimizeForSize)
+      && InlineThreshold != 50) {
+    CurrentThreshold = 50;
+  }
+  
+  if (Cost >= (int)(CurrentThreshold * FudgeFactor)) {
+    DOUT << "    NOT Inlining: cost=" << Cost
+         << ", Call: " << *CS.getInstruction();
+    return false;
+  } else {
+    DOUT << "    Inlining: cost=" << Cost
+         << ", Call: " << *CS.getInstruction();
+    return true;
+  }
+}
 
 bool Inliner::runOnSCC(const std::vector<CallGraphNode*> &SCC) {
   CallGraph &CG = getAnalysis<CallGraph>();
@@ -137,26 +184,15 @@ bool Inliner::runOnSCC(const std::vector<CallGraphNode*> &SCC) {
         // If the policy determines that we should inline this function,
         // try to do so.
         CallSite CS = CallSites[CSi];
-        int InlineCost = getInlineCost(CS);
-        float FudgeFactor = getInlineFudgeFactor(CS);
-
-        Function *Fn = CS.getCalledFunction();
-        bool AlwaysInline = false;
-        if (Fn && (Fn->getNotes() & FN_NOTE_AlwaysInline))
-          AlwaysInline = true;
-        if (Fn && (Fn->getNotes() & FN_NOTE_NoInline))
-          DOUT << "NOT Inlining: inline=never is set" << *CS.getInstruction();
-        else if (!AlwaysInline 
-                 && InlineCost >= (int)(InlineThreshold * FudgeFactor)) {
-          DOUT << "    NOT Inlining: cost=" << InlineCost
-               << ", Call: " << *CS.getInstruction();
-        } else {
-          DOUT << "    Inlining: cost=" << InlineCost
-               << ", Call: " << *CS.getInstruction();
-
+        if (shouldInline(CS)) {
+          Function *Caller = CS.getCaller();
           // Attempt to inline the function...
           if (InlineCallIfPossible(CS, CG, SCCFunctions, 
                                    getAnalysis<TargetData>())) {
+            // Remove any cached cost info for this caller, as inlining the callee
+            // has increased the size of the caller.
+            resetCachedCostInfo(Caller);
+
             // Remove this call site from the list.  If possible, use 
             // swap/pop_back for efficiency, but do not use it if doing so would
             // move a call site to a function in this SCC before the
@@ -183,6 +219,13 @@ bool Inliner::runOnSCC(const std::vector<CallGraphNode*> &SCC) {
 // doFinalization - Remove now-dead linkonce functions at the end of
 // processing to avoid breaking the SCC traversal.
 bool Inliner::doFinalization(CallGraph &CG) {
+  return removeDeadFunctions(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) {
   std::set<CallGraphNode*> FunctionsToRemove;
 
   // Scan for all of the functions, looking for ones that should now be removed
@@ -194,12 +237,14 @@ bool Inliner::doFinalization(CallGraph &CG) {
       // them.
       F->removeDeadConstantUsers();
 
+      if (DNR && DNR->count(F))
+        continue;
+
       if ((F->hasLinkOnceLinkage() || F->hasInternalLinkage()) &&
           F->use_empty()) {
 
         // Remove any call graph edges from the function to its callees.
-        while (!CGN->empty())
-          CGN->removeCallEdgeTo((CGN->end()-1)->second);
+        CGN->removeAllCalledFunctions();
 
         // Remove any edges from the external node to the function's call graph
         // node.  These edges might have been made irrelegant due to