What the loop unroller cares about, rather than just not unrolling loops with calls, is
authorOwen Anderson <resistor@mac.com>
Thu, 9 Sep 2010 20:32:23 +0000 (20:32 +0000)
committerOwen Anderson <resistor@mac.com>
Thu, 9 Sep 2010 20:32:23 +0000 (20:32 +0000)
not unrolling loops that contain calls that would be better off getting inlined.  This mostly
comes up when an interleaved devirtualization pass has devirtualized a call which the inliner
will inline on a future pass.  Thus, rather than blocking all loops containing calls, add
a metric for "inline candidate calls" and block loops containing those instead.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@113535 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/CodeMetrics.h
lib/Analysis/InlineCost.cpp
lib/Transforms/Scalar/LoopUnrollPass.cpp

index 6ae68f36d7b962cb74aa2dfb4dad4200a2fde956..1a67409ad176cd8d491a381c5bda36f22be56194 100644 (file)
@@ -45,6 +45,11 @@ namespace llvm {
 
     /// NumCalls - Keep track of the number of calls to 'big' functions.
     unsigned NumCalls;
+    
+    /// NumInlineCandidates - Keep track of the number of calls to internal
+    /// functions with only a single caller.  These are likely targets for
+    /// future inlining, likely exposed by interleaved devirtualization.
+    unsigned NumInlineCandidates;
 
     /// NumVectorInsts - Keep track of how many instructions produce vector
     /// values.  The inliner is being more aggressive with inlining vector
@@ -56,7 +61,8 @@ namespace llvm {
 
     CodeMetrics() : callsSetJmp(false), isRecursive(false),
                     containsIndirectBr(false), usesDynamicAlloca(false), 
-                    NumInsts(0), NumBlocks(0), NumCalls(0), NumVectorInsts(0), 
+                    NumInsts(0), NumBlocks(0), NumCalls(0),
+                    NumInlineCandidates(0), NumVectorInsts(0), 
                     NumRets(0) {}
 
     /// analyzeBasicBlock - Add information about the specified basic block
index ee2657c58e5dfb90e3f5beb9f9db51f659abc183..afdf474c616ae4eba55e3234a1b708e6c486b132 100644 (file)
@@ -70,6 +70,12 @@ void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) {
       // variables as volatile if they are live across a setjmp call, and they
       // probably won't do this in callers.
       if (const Function *F = CS.getCalledFunction()) {
+        // If a function is both internal and has a single use, then it is 
+        // extremely likely to get inlined in the future (it was probably 
+        // exposed by an interleaved devirtualization pass).
+        if (F->hasInternalLinkage() && F->hasOneUse())
+          ++NumInlineCandidates;
+        
         if (F->isDeclaration() && 
             (F->getName() == "setjmp" || F->getName() == "_setjmp"))
           callsSetJmp = true;
index 7968939f11d5ba0ba9799ff61644771e2e56d391..806f63d1043b0bd43398ee0b7fa0a25a4141b13d 100644 (file)
@@ -89,7 +89,7 @@ static unsigned ApproximateLoopSize(const Loop *L, unsigned &NumCalls) {
   for (Loop::block_iterator I = L->block_begin(), E = L->block_end();
        I != E; ++I)
     Metrics.analyzeBasicBlock(*I);
-  NumCalls = Metrics.NumCalls;
+  NumCalls = Metrics.NumInlineCandidates;
   
   unsigned LoopSize = Metrics.NumInsts;
   
@@ -151,11 +151,11 @@ bool LoopUnroll::runOnLoop(Loop *L, LPPassManager &LPM) {
 
   // Enforce the threshold.
   if (CurrentThreshold != NoThreshold) {
-    unsigned NumCalls;
-    unsigned LoopSize = ApproximateLoopSize(L, NumCalls);
+    unsigned NumInlineCandidates;
+    unsigned LoopSize = ApproximateLoopSize(L, NumInlineCandidates);
     DEBUG(dbgs() << "  Loop Size = " << LoopSize << "\n");
-    if (NumCalls != 0) {
-      DEBUG(dbgs() << "  Not unrolling loop with function calls.\n");
+    if (NumInlineCandidates != 0) {
+      DEBUG(dbgs() << "  Not unrolling loop with inlinable calls.\n");
       return false;
     }
     uint64_t Size = (uint64_t)LoopSize*Count;