[cfe-commits] r67447 - in /cfe/trunk/lib/CodeGen: CodeGenModule.cpp CodeGenModule.h

Chris Lattner sabre at nondot.org
Sat Mar 21 02:45:02 PDT 2009


Author: lattner
Date: Sat Mar 21 04:44:56 2009
New Revision: 67447

URL: http://llvm.org/viewvc/llvm-project?rev=67447&view=rev
Log:
now that all the decl reference and creation stuff is going through two
very simple places, reimplement the deferred decl emission logic to not be O(N^2),
fixing PR3810.

Modified:
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.h

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=67447&r1=67446&r2=67447&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Mar 21 04:44:56 2009
@@ -441,38 +441,26 @@
 }
 
 void CodeGenModule::EmitDeferred() {
-  // Emit code for any deferred decl which was used.  Since a
-  // previously unused static decl may become used during the
-  // generation of code for a static function, iterate until no
-  // changes are made.
-  bool Changed;
-  do {
-    Changed = false;
-    
-    for (std::list<const ValueDecl*>::iterator i = DeferredDecls.begin(),
-         e = DeferredDecls.end(); i != e; ) {
-      const ValueDecl *D = *i;
-      
-      // Check if we have used a decl with the same name
-      // FIXME: The AST should have some sort of aggregate decls or
-      // global symbol map.
-      // FIXME: This is missing some important cases. For example, we
-      // need to check for uses in an alias.
-      if (!GlobalDeclMap.count(getMangledName(D))) {
-        ++i;
-        continue;
-      }
-      
-      // Emit the definition.
-      EmitGlobalDefinition(D);
-
-      // Erase the used decl from the list.
-      i = DeferredDecls.erase(i);
-
-      // Remember that we made a change.
-      Changed = true;
-    }
-  } while (Changed);
+  // Emit code for any potentially referenced deferred decls.  Since a
+  // previously unused static decl may become used during the generation of code
+  // for a static function, iterate until no  changes are made.
+  while (!DeferredDeclsToEmit.empty()) {
+    const ValueDecl *D = DeferredDeclsToEmit.back();
+    DeferredDeclsToEmit.pop_back();
+
+    // The mangled name for the decl must have been emitted in GlobalDeclMap.
+    // Look it up to see if it was defined with a stronger definition (e.g. an
+    // extern inline function with a strong function redefinition).  If so,
+    // just ignore the deferred decl.
+    llvm::GlobalValue *CGRef = GlobalDeclMap[getMangledName(D)];
+    assert(CGRef && "Deferred decl wasn't referenced?");
+    
+    if (!CGRef->isDeclaration())
+      continue;
+    
+    // Otherwise, emit the definition and move on to the next one.
+    EmitGlobalDefinition(D);
+  }
 }
 
 /// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the 
@@ -552,6 +540,7 @@
     return;
   }
 
+  // Ignore declarations, they will be emitted on their first use.
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
     // Forward declarations are emitted lazily on first use.
     if (!FD->isThisDeclarationADefinition())
@@ -565,9 +554,20 @@
       return;
   }
 
-  // Defer code generation when possible.
+  // Defer code generation when possible if this is a static definition, inline
+  // function etc.  These we only want to emit if they are used.
   if (MayDeferGeneration(Global)) {
-    DeferredDecls.push_back(Global);
+    // If the value has already been used, add it directly to the
+    // DeferredDeclsToEmit list.
+    const char *MangledName = getMangledName(Global);
+    if (GlobalDeclMap.count(MangledName))
+      DeferredDeclsToEmit.push_back(Global);
+    else {
+      // Otherwise, remember that we saw a deferred decl with this name.  The
+      // first use of the mangled name will cause it to move into
+      // DeferredDeclsToEmit.
+      DeferredDecls[MangledName] = Global;
+    }
     return;
   }
 
@@ -606,6 +606,19 @@
     return llvm::ConstantExpr::getBitCast(Entry, PTy);
   }
   
+  // This is the first use or definition of a mangled name.  If there is a
+  // deferred decl with this name, remember that we need to emit it at the end
+  // of the file.
+  llvm::DenseMap<const char*, const ValueDecl*>::iterator DDI = 
+    DeferredDecls.find(MangledName);
+  if (DDI != DeferredDecls.end()) {
+    // Move the potentially referenced deferred decl to the DeferredDeclsToEmit
+    // list, and remove it from DeferredDecls (since we don't need it anymore).
+    DeferredDeclsToEmit.push_back(DDI->second);
+    DeferredDecls.erase(DDI);
+  }
+  
+  
   // This function doesn't have a complete type (for example, the return
   // type is an incomplete struct). Use a fake type instead, and make
   // sure not to try to set attributes.
@@ -648,7 +661,19 @@
     const llvm::Type *PTy = llvm::PointerType::get(Ty, ASTTy.getAddressSpace());
     return llvm::ConstantExpr::getBitCast(Entry, PTy);
   }
-   
+  
+  // This is the first use or definition of a mangled name.  If there is a
+  // deferred decl with this name, remember that we need to emit it at the end
+  // of the file.
+  llvm::DenseMap<const char*, const ValueDecl*>::iterator DDI = 
+    DeferredDecls.find(MangledName);
+  if (DDI != DeferredDecls.end()) {
+    // Move the potentially referenced deferred decl to the DeferredDeclsToEmit
+    // list, and remove it from DeferredDecls (since we don't need it anymore).
+    DeferredDeclsToEmit.push_back(DDI->second);
+    DeferredDecls.erase(DDI);
+  }
+  
   llvm::GlobalVariable *GV = 
     new llvm::GlobalVariable(Ty, false, 
                              llvm::GlobalValue::ExternalLinkage,

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=67447&r1=67446&r2=67447&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Sat Mar 21 04:44:56 2009
@@ -95,8 +95,12 @@
   /// globals and therefore may not be of the same type as the decl,
   /// they should be bitcasted on retrieval. Also note that the
   /// globals are keyed on their source mangled name, not the global name
-  /// (which may change with attributes such as asm-labels).  This key
+  /// (which may change with attributes such as asm-labels).  The key
   /// to this map should be generated using getMangledName().
+  ///
+  /// Note that this map always lines up exactly with the contents of the LLVM
+  /// IR symbol table, but this is quicker to query since it is doing uniqued
+  /// pointer lookups instead of full string lookups.
   llvm::DenseMap<const char*, llvm::GlobalValue*> GlobalDeclMap;
 
   /// \brief Contains the strings used for mangled names.
@@ -111,13 +115,17 @@
   /// and may reference forward.
   std::vector<const ValueDecl*> Aliases;
 
-  /// DeferredDecls - List of decls for which code generation has been
-  /// deferred. When the translation unit has been fully processed we
-  /// will lazily emit definitions for only the decls that were
-  /// actually used.  This should contain only Function and Var decls,
-  /// and only those which actually define something.
-  std::list<const ValueDecl*> DeferredDecls;
-
+  /// DeferredDecls - This contains all the decls which have definitions but
+  /// which are deferred for emission and therefore should only be output if
+  /// they are actually used.  If a decl is in this, then it is known to have
+  /// not been referenced yet.  The key to this map is a uniqued mangled name.
+  llvm::DenseMap<const char*, const ValueDecl*> DeferredDecls;
+
+  /// DeferredDeclsToEmit - This is a list of deferred decls which we have seen
+  /// that *are* actually referenced.  These get code generated when the module
+  /// is done.
+  std::vector<const ValueDecl*> DeferredDeclsToEmit;
+  
   /// LLVMUsed - List of global values which are required to be
   /// present in the object file; bitcast to i8*. This is used for
   /// forcing visibility of symbols which may otherwise be optimized





More information about the cfe-commits mailing list