[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