From: Argyrios Kyrtzidis Date: Thu, 29 Jul 2010 18:15:58 +0000 (+0000) Subject: Merge PCHWriterDecl.cpp's isRequiredDecl and CodeGenModule::MayDeferGeneration into... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=90e99a84ddd020e8fda79643748243725a2ed071;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109784 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 56b20e6262..3744473228 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1339,6 +1339,17 @@ public: /// 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 //===--------------------------------------------------------------------===// diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h index de0de348d3..035b4fc7a7 100644 --- a/include/clang/Basic/Linkage.h +++ b/include/clang/Basic/Linkage.h @@ -41,6 +41,17 @@ enum Linkage { 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) { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4fd8f66108..af19e89fd9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5445,3 +5445,163 @@ ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { } 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()) { + // 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(D)) { + if (!VD->isFileVarDecl()) + return false; + } else if (!isa(D)) + return false; + + // Aliases and used decls are required. + if (D->hasAttr() || D->hasAttr()) + return true; + + if (const FunctionDecl *FD = dyn_cast(D)) { + // Forward declarations aren't required. + if (!FD->isThisDeclarationADefinition()) + return false; + + // Constructors and destructors are required. + if (FD->hasAttr() || FD->hasAttr()) + return true; + + // The key function for a class is required. + if (const CXXMethodDecl *MD = dyn_cast(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(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()) { + if (const CXXRecordDecl *RD = dyn_cast(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; +} diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 720d24a54f..06c6f5da21 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -322,68 +322,9 @@ void CodeGenModule::EmitAnnotations() { 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()) { - // 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 @@ llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, 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()) - return false; - - if (const FunctionDecl *FD = dyn_cast(Global)) { - // Constructors and destructors should never be deferred. - if (FD->hasAttr() || - FD->hasAttr()) - return false; - - // The key function for a class must never be deferred. - if (const CXXMethodDecl *MD = dyn_cast(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; + // Never defer when EmitAllDecls is specified. + if (Features.EmitAllDecls) return false; - } - - const VarDecl *VD = cast(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()) { - if (const CXXRecordDecl *RD = dyn_cast(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 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { 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()) diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 5b7503861d..2cb345a8a2 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -504,15 +504,6 @@ public: 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); diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 75045eb32a..5d66c218bb 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -1081,63 +1081,12 @@ void PCHWriter::WriteDeclsBlockAbbrevs() { /// 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(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(D)) { - if (!VD->isFileVarDecl()) - return false; - } else if (!isa(D)) - return false; - - // Aliases and used decls must be seen. - if (D->hasAttr() || D->hasAttr()) - return true; - - if (const FunctionDecl *FD = dyn_cast(D)) { - // Forward declarations don't need to be seen. - if (!FD->isThisDeclarationADefinition()) - return false; - - // Constructors and destructors must be seen. - if (FD->hasAttr() || FD->hasAttr()) - return true; - - // Otherwise, this is required unless it is static. - // - // FIXME: Inlines. - return FD->getStorageClass() != FunctionDecl::Static; - } else { - const VarDecl *VD = cast(D); - - // Structs that have non-trivial constructors or destructors must be seen. - if (const RecordType *RT = VD->getType()->getAs()) { - if (const CXXRecordDecl *RD = dyn_cast(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) { diff --git a/test/PCH/cxx-required-decls.cpp b/test/PCH/cxx-required-decls.cpp index 0e39ce36fe..818958ea1e 100644 --- a/test/PCH/cxx-required-decls.cpp +++ b/test/PCH/cxx-required-decls.cpp @@ -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 diff --git a/test/PCH/cxx-required-decls.h b/test/PCH/cxx-required-decls.h index f4fa79e4ee..df28ad6c2f 100644 --- a/test/PCH/cxx-required-decls.h +++ b/test/PCH/cxx-required-decls.h @@ -5,3 +5,6 @@ struct S { }; static S globS; + +extern int ext_foo; +static int bar = ++ext_foo;