forked from OSchip/llvm-project
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. llvm-svn: 109784
This commit is contained in:
parent
7f4b81af7a
commit
c81af03fb3
|
@ -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
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<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;
|
||||
}
|
||||
|
|
|
@ -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<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 @@ 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<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 @@ 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<DLLImportAttr>())
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,3 +5,6 @@ struct S {
|
|||
};
|
||||
|
||||
static S globS;
|
||||
|
||||
extern int ext_foo;
|
||||
static int bar = ++ext_foo;
|
||||
|
|
Loading…
Reference in New Issue