[llvm] r178130 - Improve performance of LinkModules when linking with modules with large numbers of functions which link lazily. Instead of creating and destroying function prototypes irrespective of if they are used, only create them if they are used.

James Molloy james.molloy at arm.com
Wed Mar 27 03:23:32 PDT 2013


Author: jamesm
Date: Wed Mar 27 05:23:32 2013
New Revision: 178130

URL: http://llvm.org/viewvc/llvm-project?rev=178130&view=rev
Log:
Improve performance of LinkModules when linking with modules with large numbers of functions which link lazily. Instead of creating and destroying function prototypes irrespective of if they are used, only create them if they are used.

Modified:
    llvm/trunk/lib/Linker/LinkModules.cpp

Modified: llvm/trunk/lib/Linker/LinkModules.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Linker/LinkModules.cpp?rev=178130&r1=178129&r2=178130&view=diff
==============================================================================
--- llvm/trunk/lib/Linker/LinkModules.cpp (original)
+++ llvm/trunk/lib/Linker/LinkModules.cpp Wed Mar 27 05:23:32 2013
@@ -370,11 +370,16 @@ namespace {
     
     unsigned Mode; // Mode to treat source module.
     
+    struct LazyLinkEntry {
+      Function *Fn;
+      llvm::SmallPtrSet<User*, 4> Uses;
+    };
+
     // Set of items not to link in from source.
     SmallPtrSet<const Value*, 16> DoNotLinkFromSource;
     
     // Vector of functions to lazily link in.
-    std::vector<Function*> LazilyLinkFunctions;
+    std::vector<LazyLinkEntry> LazilyLinkFunctions;
     
   public:
     std::string ErrorMsg;
@@ -801,6 +806,18 @@ bool ModuleLinker::linkFunctionProto(Fun
     }
   }
   
+  // If the function is to be lazily linked, don't create it just yet.
+  // Instead, remember its current set of uses to diff against later.
+  if (!DGV && (SF->hasLocalLinkage() || SF->hasLinkOnceLinkage() ||
+               SF->hasAvailableExternallyLinkage())) {
+    LazyLinkEntry LLE;
+    LLE.Fn = SF;
+    LLE.Uses.insert(SF->use_begin(), SF->use_end());
+    LazilyLinkFunctions.push_back(LLE);
+    DoNotLinkFromSource.insert(SF);
+    return false;
+  }
+
   // If there is no linkage to be performed or we are linking from the source,
   // bring SF over.
   Function *NewDF = Function::Create(TypeMap.get(SF->getFunctionType()),
@@ -813,13 +830,6 @@ bool ModuleLinker::linkFunctionProto(Fun
     // Any uses of DF need to change to NewDF, with cast.
     DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewDF, DGV->getType()));
     DGV->eraseFromParent();
-  } else {
-    // Internal, LO_ODR, or LO linkage - stick in set to ignore and lazily link.
-    if (SF->hasLocalLinkage() || SF->hasLinkOnceLinkage() ||
-        SF->hasAvailableExternallyLinkage()) {
-      DoNotLinkFromSource.insert(SF);
-      LazilyLinkFunctions.push_back(SF);
-    }
   }
   
   ValueMap[SF] = NewDF;
@@ -1236,16 +1246,33 @@ bool ModuleLinker::run() {
   do {
     LinkedInAnyFunctions = false;
     
-    for(std::vector<Function*>::iterator I = LazilyLinkFunctions.begin(),
-        E = LazilyLinkFunctions.end(); I != E; ++I) {
-      if (!*I)
+    for(std::vector<LazyLinkEntry>::iterator I = LazilyLinkFunctions.begin(),
+        E = LazilyLinkFunctions.end(); I != E; ++I) {      
+      Function *SF = I->Fn;
+      if (!SF)
         continue;
       
-      Function *SF = *I;
-      Function *DF = cast<Function>(ValueMap[SF]);
-      
-      if (!DF->use_empty()) {
-        
+      // If the number of uses of this function is the same as it was at the
+      // start of the link, it is not used in this link.
+      if (SF->getNumUses() != I->Uses.size()) {
+        Function *DF = Function::Create(TypeMap.get(SF->getFunctionType()),
+                                        SF->getLinkage(), SF->getName(), DstM);
+        copyGVAttributes(DF, SF);
+
+        // Now, copy over any uses of SF that were from DstM to DF.
+        for (Function::use_iterator UI = SF->use_begin(), UE = SF->use_end();
+             UI != UE;) {
+          if (I->Uses.count(*UI) == 0) {
+            Use &U = UI.getUse();
+            // Increment UI before performing the set to ensure the iterator
+            // remains valid.
+            ++UI;
+            U.set(DF);
+          } else {
+            ++UI;
+          }
+        }
+
         // Materialize if necessary.
         if (SF->isDeclaration()) {
           if (!SF->isMaterializable())
@@ -1259,7 +1286,7 @@ bool ModuleLinker::run() {
         SF->Dematerialize();
 
         // "Remove" from vector by setting the element to 0.
-        *I = 0;
+        I->Fn = 0;
         
         // Set flag to indicate we may have more functions to lazily link in
         // since we linked in a function.
@@ -1268,18 +1295,6 @@ bool ModuleLinker::run() {
     }
   } while (LinkedInAnyFunctions);
   
-  // Remove any prototypes of functions that were not actually linked in.
-  for(std::vector<Function*>::iterator I = LazilyLinkFunctions.begin(),
-      E = LazilyLinkFunctions.end(); I != E; ++I) {
-    if (!*I)
-      continue;
-    
-    Function *SF = *I;
-    Function *DF = cast<Function>(ValueMap[SF]);
-    if (DF->use_empty())
-      DF->eraseFromParent();
-  }
-  
   // Now that all of the types from the source are used, resolve any structs
   // copied over to the dest that didn't exist there.
   TypeMap.linkDefinedTypeBodies();





More information about the llvm-commits mailing list