[cfe-commits] r109784 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/Basic/Linkage.h lib/AST/ASTContext.cpp lib/CodeGen/CodeGenModule.cpp lib/CodeGen/CodeGenModule.h lib/Frontend/PCHWriterDecl.cpp test/PCH/cxx-required-decls.cpp test/PCH/cxx-required-decls.h

Argyrios Kyrtzidis akyrtzi at gmail.com
Thu Jul 29 11:15:58 PDT 2010


Author: akirtzidis
Date: Thu Jul 29 13:15:58 2010
New Revision: 109784

URL: http://llvm.org/viewvc/llvm-project?rev=109784&view=rev
Log:
Merge PCHWriterDecl.cpp's isRequiredDecl and CodeGenModule::MayDeferGeneration into a new function,
DeclIsRequiredFunctionOrFileScopedVar.

This is essentially a CodeGen predicate that is also needed by the PCH mechanism to determine whether a decl
needs to be deserialized during PCH loading for codegen purposes.
Since this logic is shared by CodeGen and the PCH mechanism, move it to the ASTContext,
thus CodeGenModule's GetLinkageForFunction/GetLinkageForVariable and the GVALinkage enum is moved out of CodeGen.

This fixes current (and avoids future) codegen-from-PCH bugs.

Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/Basic/Linkage.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.h
    cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
    cfe/trunk/test/PCH/cxx-required-decls.cpp
    cfe/trunk/test/PCH/cxx-required-decls.h

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=109784&r1=109783&r2=109784&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Jul 29 13:15:58 2010
@@ -1339,6 +1339,17 @@
   /// when it is called.
   void AddDeallocation(void (*Callback)(void*), void *Data);
 
+  GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD);
+  GVALinkage GetGVALinkageForVariable(const VarDecl *VD);
+
+  /// \brief Determines if the decl can be CodeGen'ed or deserialized from PCH
+  /// lazily, only when used; this is only relevant for function or file scoped
+  /// var definitions.
+  ///
+  /// \returns true if the function/var must be CodeGen'ed/deserialized even if
+  /// it is not used.
+  bool DeclIsRequiredFunctionOrFileScopedVar(const Decl *D);
+
   //===--------------------------------------------------------------------===//
   //                    Statistics
   //===--------------------------------------------------------------------===//

Modified: cfe/trunk/include/clang/Basic/Linkage.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Linkage.h?rev=109784&r1=109783&r2=109784&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Linkage.h (original)
+++ cfe/trunk/include/clang/Basic/Linkage.h Thu Jul 29 13:15:58 2010
@@ -41,6 +41,17 @@
   ExternalLinkage
 };
 
+/// \brief A more specific kind of linkage. This is relevant to CodeGen and
+/// PCH reading.
+enum GVALinkage {
+  GVA_Internal,
+  GVA_C99Inline,
+  GVA_CXXInline,
+  GVA_StrongExternal,
+  GVA_TemplateInstantiation,
+  GVA_ExplicitTemplateInstantiation
+};
+
 /// \brief Determine whether the given linkage is semantically
 /// external.
 inline bool isExternalLinkage(Linkage L) {

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=109784&r1=109783&r2=109784&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jul 29 13:15:58 2010
@@ -5445,3 +5445,163 @@
   }
   return destType;
 }
+
+GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
+  GVALinkage External = GVA_StrongExternal;
+
+  Linkage L = FD->getLinkage();
+  if (L == ExternalLinkage && getLangOptions().CPlusPlus &&
+      FD->getType()->getLinkage() == UniqueExternalLinkage)
+    L = UniqueExternalLinkage;
+  
+  switch (L) {
+  case NoLinkage:
+  case InternalLinkage:
+  case UniqueExternalLinkage:
+    return GVA_Internal;
+    
+  case ExternalLinkage:
+    switch (FD->getTemplateSpecializationKind()) {
+    case TSK_Undeclared:
+    case TSK_ExplicitSpecialization:
+      External = GVA_StrongExternal;
+      break;
+
+    case TSK_ExplicitInstantiationDefinition:
+      return GVA_ExplicitTemplateInstantiation;
+
+    case TSK_ExplicitInstantiationDeclaration:
+    case TSK_ImplicitInstantiation:
+      External = GVA_TemplateInstantiation;
+      break;
+    }
+  }
+
+  if (!FD->isInlined())
+    return External;
+    
+  if (!getLangOptions().CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
+    // GNU or C99 inline semantics. Determine whether this symbol should be
+    // externally visible.
+    if (FD->isInlineDefinitionExternallyVisible())
+      return External;
+
+    // C99 inline semantics, where the symbol is not externally visible.
+    return GVA_C99Inline;
+  }
+
+  // C++0x [temp.explicit]p9:
+  //   [ Note: The intent is that an inline function that is the subject of 
+  //   an explicit instantiation declaration will still be implicitly 
+  //   instantiated when used so that the body can be considered for 
+  //   inlining, but that no out-of-line copy of the inline function would be
+  //   generated in the translation unit. -- end note ]
+  if (FD->getTemplateSpecializationKind() 
+                                       == TSK_ExplicitInstantiationDeclaration)
+    return GVA_C99Inline;
+
+  return GVA_CXXInline;
+}
+
+GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
+  // If this is a static data member, compute the kind of template
+  // specialization. Otherwise, this variable is not part of a
+  // template.
+  TemplateSpecializationKind TSK = TSK_Undeclared;
+  if (VD->isStaticDataMember())
+    TSK = VD->getTemplateSpecializationKind();
+
+  Linkage L = VD->getLinkage();
+  if (L == ExternalLinkage && getLangOptions().CPlusPlus &&
+      VD->getType()->getLinkage() == UniqueExternalLinkage)
+    L = UniqueExternalLinkage;
+
+  switch (L) {
+  case NoLinkage:
+  case InternalLinkage:
+  case UniqueExternalLinkage:
+    return GVA_Internal;
+
+  case ExternalLinkage:
+    switch (TSK) {
+    case TSK_Undeclared:
+    case TSK_ExplicitSpecialization:
+      return GVA_StrongExternal;
+
+    case TSK_ExplicitInstantiationDeclaration:
+      llvm_unreachable("Variable should not be instantiated");
+      // Fall through to treat this like any other instantiation.
+        
+    case TSK_ExplicitInstantiationDefinition:
+      return GVA_ExplicitTemplateInstantiation;
+
+    case TSK_ImplicitInstantiation:
+      return GVA_TemplateInstantiation;      
+    }
+  }
+
+  return GVA_StrongExternal;
+}
+
+bool ASTContext::DeclIsRequiredFunctionOrFileScopedVar(const Decl *D) {
+  if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+    if (!VD->isFileVarDecl())
+      return false;
+  } else if (!isa<FunctionDecl>(D))
+    return false;
+
+  // Aliases and used decls are required.
+  if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
+    return true;
+
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    // Forward declarations aren't required.
+    if (!FD->isThisDeclarationADefinition())
+      return false;
+
+    // Constructors and destructors are required.
+    if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
+      return true;
+    
+    // The key function for a class is required.
+    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+      const CXXRecordDecl *RD = MD->getParent();
+      if (MD->isOutOfLine() && RD->isDynamicClass()) {
+        const CXXMethodDecl *KeyFunc = getKeyFunction(RD);
+        if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
+          return true;
+      }
+    }
+
+    GVALinkage Linkage = GetGVALinkageForFunction(FD);
+
+    // static, static inline, always_inline, and extern inline functions can
+    // always be deferred.  Normal inline functions can be deferred in C99/C++.
+    // Implicit template instantiations can also be deferred in C++.
+    if (Linkage == GVA_Internal  || Linkage == GVA_C99Inline ||
+        Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
+      return false;
+    return true;
+  }
+
+  const VarDecl *VD = cast<VarDecl>(D);
+  assert(VD->isFileVarDecl() && "Expected file scoped var");
+
+  // Structs that have non-trivial constructors or destructors are required.
+
+  // FIXME: Handle references.
+  if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
+    if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+      if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor())
+        return true;
+    }
+  }
+
+  GVALinkage L = GetGVALinkageForVariable(VD);
+  if (L == GVA_Internal || L == GVA_TemplateInstantiation) {
+    if (!(VD->getInit() && VD->getInit()->HasSideEffects(*this)))
+      return false;
+  }
+
+  return true;
+}

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=109784&r1=109783&r2=109784&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Thu Jul 29 13:15:58 2010
@@ -322,68 +322,9 @@
   gv->setSection("llvm.metadata");
 }
 
-static CodeGenModule::GVALinkage
-GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
-                      const LangOptions &Features) {
-  CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
-
-  Linkage L = FD->getLinkage();
-  if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus &&
-      FD->getType()->getLinkage() == UniqueExternalLinkage)
-    L = UniqueExternalLinkage;
-  
-  switch (L) {
-  case NoLinkage:
-  case InternalLinkage:
-  case UniqueExternalLinkage:
-    return CodeGenModule::GVA_Internal;
-    
-  case ExternalLinkage:
-    switch (FD->getTemplateSpecializationKind()) {
-    case TSK_Undeclared:
-    case TSK_ExplicitSpecialization:
-      External = CodeGenModule::GVA_StrongExternal;
-      break;
-
-    case TSK_ExplicitInstantiationDefinition:
-      return CodeGenModule::GVA_ExplicitTemplateInstantiation;
-
-    case TSK_ExplicitInstantiationDeclaration:
-    case TSK_ImplicitInstantiation:
-      External = CodeGenModule::GVA_TemplateInstantiation;
-      break;
-    }
-  }
-
-  if (!FD->isInlined())
-    return External;
-    
-  if (!Features.CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
-    // GNU or C99 inline semantics. Determine whether this symbol should be
-    // externally visible.
-    if (FD->isInlineDefinitionExternallyVisible())
-      return External;
-
-    // C99 inline semantics, where the symbol is not externally visible.
-    return CodeGenModule::GVA_C99Inline;
-  }
-
-  // C++0x [temp.explicit]p9:
-  //   [ Note: The intent is that an inline function that is the subject of 
-  //   an explicit instantiation declaration will still be implicitly 
-  //   instantiated when used so that the body can be considered for 
-  //   inlining, but that no out-of-line copy of the inline function would be
-  //   generated in the translation unit. -- end note ]
-  if (FD->getTemplateSpecializationKind() 
-                                       == TSK_ExplicitInstantiationDeclaration)
-    return CodeGenModule::GVA_C99Inline;
-
-  return CodeGenModule::GVA_CXXInline;
-}
-
 llvm::GlobalValue::LinkageTypes
 CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
-  GVALinkage Linkage = GetLinkageForFunction(getContext(), D, Features);
+  GVALinkage Linkage = getContext().GetGVALinkageForFunction(D);
 
   if (Linkage == GVA_Internal)
     return llvm::Function::InternalLinkage;
@@ -641,102 +582,12 @@
   return llvm::ConstantStruct::get(VMContext, Fields, 4, false);
 }
 
-static CodeGenModule::GVALinkage
-GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
-  // If this is a static data member, compute the kind of template
-  // specialization. Otherwise, this variable is not part of a
-  // template.
-  TemplateSpecializationKind TSK = TSK_Undeclared;
-  if (VD->isStaticDataMember())
-    TSK = VD->getTemplateSpecializationKind();
-
-  Linkage L = VD->getLinkage();
-  if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus &&
-      VD->getType()->getLinkage() == UniqueExternalLinkage)
-    L = UniqueExternalLinkage;
-
-  switch (L) {
-  case NoLinkage:
-  case InternalLinkage:
-  case UniqueExternalLinkage:
-    return CodeGenModule::GVA_Internal;
-
-  case ExternalLinkage:
-    switch (TSK) {
-    case TSK_Undeclared:
-    case TSK_ExplicitSpecialization:
-      return CodeGenModule::GVA_StrongExternal;
-
-    case TSK_ExplicitInstantiationDeclaration:
-      llvm_unreachable("Variable should not be instantiated");
-      // Fall through to treat this like any other instantiation.
-        
-    case TSK_ExplicitInstantiationDefinition:
-      return CodeGenModule::GVA_ExplicitTemplateInstantiation;
-
-    case TSK_ImplicitInstantiation:
-      return CodeGenModule::GVA_TemplateInstantiation;      
-    }
-  }
-
-  return CodeGenModule::GVA_StrongExternal;
-}
-
 bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
-  // Never defer when EmitAllDecls is specified or the decl has
-  // attribute used.
-  if (Features.EmitAllDecls || Global->hasAttr<UsedAttr>())
+  // Never defer when EmitAllDecls is specified.
+  if (Features.EmitAllDecls)
     return false;
 
-  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
-    // Constructors and destructors should never be deferred.
-    if (FD->hasAttr<ConstructorAttr>() ||
-        FD->hasAttr<DestructorAttr>())
-      return false;
-
-    // The key function for a class must never be deferred.
-    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Global)) {
-      const CXXRecordDecl *RD = MD->getParent();
-      if (MD->isOutOfLine() && RD->isDynamicClass()) {
-        const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD);
-        if (KeyFunction && 
-            KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
-          return false;
-      }
-    }
-
-    GVALinkage Linkage = GetLinkageForFunction(getContext(), FD, Features);
-
-    // static, static inline, always_inline, and extern inline functions can
-    // always be deferred.  Normal inline functions can be deferred in C99/C++.
-    // Implicit template instantiations can also be deferred in C++.
-    if (Linkage == GVA_Internal || Linkage == GVA_C99Inline ||
-        Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
-      return true;
-    return false;
-  }
-
-  const VarDecl *VD = cast<VarDecl>(Global);
-  assert(VD->isFileVarDecl() && "Invalid decl");
-
-  // We never want to defer structs that have non-trivial constructors or 
-  // destructors.
-  
-  // FIXME: Handle references.
-  if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
-    if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
-      if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor())
-        return false;
-    }
-  }
-      
-  GVALinkage L = GetLinkageForVariable(getContext(), VD);
-  if (L == GVA_Internal || L == GVA_TemplateInstantiation) {
-    if (!(VD->getInit() && VD->getInit()->HasSideEffects(Context)))
-      return true;
-  }
-
-  return false;
+  return !getContext().DeclIsRequiredFunctionOrFileScopedVar(Global);
 }
 
 llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
@@ -1271,7 +1122,7 @@
   GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
 
   // Set the llvm linkage type as appropriate.
-  GVALinkage Linkage = GetLinkageForVariable(getContext(), D);
+  GVALinkage Linkage = getContext().GetGVALinkageForVariable(D);
   if (Linkage == GVA_Internal)
     GV->setLinkage(llvm::Function::InternalLinkage);
   else if (D->hasAttr<DLLImportAttr>())

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=109784&r1=109783&r2=109784&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Thu Jul 29 13:15:58 2010
@@ -504,15 +504,6 @@
 
   void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired);
 
-  enum GVALinkage {
-    GVA_Internal,
-    GVA_C99Inline,
-    GVA_CXXInline,
-    GVA_StrongExternal,
-    GVA_TemplateInstantiation,
-    GVA_ExplicitTemplateInstantiation
-  };
-
   llvm::GlobalVariable::LinkageTypes
   getFunctionLinkage(const FunctionDecl *FD);
 

Modified: cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterDecl.cpp?rev=109784&r1=109783&r2=109784&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterDecl.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterDecl.cpp Thu Jul 29 13:15:58 2010
@@ -1081,63 +1081,12 @@
 /// clients to use a separate API call to "realize" the decl. This should be
 /// relatively painless since they would presumably only do it for top-level
 /// decls.
-//
-// FIXME: This predicate is essentially IRgen's predicate to determine whether a
-// declaration can be deferred. Merge them somehow.
 static bool isRequiredDecl(const Decl *D, ASTContext &Context) {
   // File scoped assembly must be seen.
   if (isa<FileScopeAsmDecl>(D))
     return true;
 
-  // Otherwise if this isn't a function or a file scoped variable it doesn't
-  // need to be seen.
-  if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
-    if (!VD->isFileVarDecl())
-      return false;
-  } else if (!isa<FunctionDecl>(D))
-    return false;
-
-  // Aliases and used decls must be seen.
-  if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
-    return true;
-
-  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
-    // Forward declarations don't need to be seen.
-    if (!FD->isThisDeclarationADefinition())
-      return false;
-
-    // Constructors and destructors must be seen.
-    if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
-      return true;
-
-    // Otherwise, this is required unless it is static.
-    //
-    // FIXME: Inlines.
-    return FD->getStorageClass() != FunctionDecl::Static;
-  } else {
-    const VarDecl *VD = cast<VarDecl>(D);
-
-    // Structs that have non-trivial constructors or destructors must be seen.
-    if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
-      if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
-        if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor())
-          return true;
-      }
-    }
-
-    // In C++, this doesn't need to be seen if it is marked "extern".
-    if (Context.getLangOptions().CPlusPlus && !VD->getInit() &&
-        (VD->getStorageClass() == VarDecl::Extern ||
-         VD->isExternC()))
-      return false;
-
-    // In C, this doesn't need to be seen unless it is a definition.
-    if (!Context.getLangOptions().CPlusPlus && !VD->getInit())
-      return false;
-
-    // Otherwise, this is required unless it is static.
-    return VD->getStorageClass() != VarDecl::Static;
-  }
+  return Context.DeclIsRequiredFunctionOrFileScopedVar(D);
 }
 
 void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) {

Modified: cfe/trunk/test/PCH/cxx-required-decls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-required-decls.cpp?rev=109784&r1=109783&r2=109784&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx-required-decls.cpp (original)
+++ cfe/trunk/test/PCH/cxx-required-decls.cpp Thu Jul 29 13:15:58 2010
@@ -6,3 +6,4 @@
 // RUN: %clang_cc1 -include-pch %t %s -emit-llvm -o - | FileCheck %s
 
 // CHECK: @_ZL5globS = internal global %struct.S zeroinitializer
+// CHECK: @_ZL3bar = internal global i32 0, align 4

Modified: cfe/trunk/test/PCH/cxx-required-decls.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-required-decls.h?rev=109784&r1=109783&r2=109784&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx-required-decls.h (original)
+++ cfe/trunk/test/PCH/cxx-required-decls.h Thu Jul 29 13:15:58 2010
@@ -5,3 +5,6 @@
 };
 
 static S globS;
+
+extern int ext_foo;
+static int bar = ++ext_foo;





More information about the cfe-commits mailing list