Merge PCHWriterDecl.cpp's isRequiredDecl and CodeGenModule::MayDeferGeneration into a new function,

DeclIsRequiredFunctionOrFileScopedVar.

This function is part of the public CodeGen interface since it's 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.
This fixes current (and avoids future) codegen-from-PCH bugs.

llvm-svn: 109546
This commit is contained in:
Argyrios Kyrtzidis 2010-07-27 22:01:17 +00:00
parent ef2f552de4
commit 4fac280618
6 changed files with 76 additions and 91 deletions

View File

@ -19,6 +19,7 @@ namespace clang {
class Diagnostic;
class CodeGenOptions;
class TargetOptions;
class Decl;
enum BackendAction {
Backend_EmitAssembly, ///< Emit native assembly files
@ -32,6 +33,14 @@ namespace clang {
void EmitBackendOutput(Diagnostic &Diags, const CodeGenOptions &CGOpts,
const TargetOptions &TOpts, llvm::Module *M,
BackendAction Action, llvm::raw_ostream *OS);
/// \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);
}
#endif

View File

@ -18,6 +18,7 @@
#include "CGObjCRuntime.h"
#include "Mangle.h"
#include "TargetInfo.h"
#include "clang/CodeGen/BackendUtil.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
@ -323,12 +324,11 @@ void CodeGenModule::EmitAnnotations() {
}
static CodeGenModule::GVALinkage
GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
const LangOptions &Features) {
GetLinkageForFunction(const FunctionDecl *FD, const LangOptions &Features) {
CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
Linkage L = FD->getLinkage();
if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus &&
if (L == ExternalLinkage && Features.CPlusPlus &&
FD->getType()->getLinkage() == UniqueExternalLinkage)
L = UniqueExternalLinkage;
@ -383,7 +383,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
llvm::GlobalValue::LinkageTypes
CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
GVALinkage Linkage = GetLinkageForFunction(getContext(), D, Features);
GVALinkage Linkage = GetLinkageForFunction(D, Features);
if (Linkage == GVA_Internal)
return llvm::Function::InternalLinkage;
@ -642,7 +642,7 @@ llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV,
}
static CodeGenModule::GVALinkage
GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
GetLinkageForVariable(const VarDecl *VD, const LangOptions &Features) {
// If this is a static data member, compute the kind of template
// specialization. Otherwise, this variable is not part of a
// template.
@ -651,7 +651,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
TSK = VD->getTemplateSpecializationKind();
Linkage L = VD->getLinkage();
if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus &&
if (L == ExternalLinkage && Features.CPlusPlus &&
VD->getType()->getLinkage() == UniqueExternalLinkage)
L = UniqueExternalLinkage;
@ -682,61 +682,83 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
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>())
bool clang::DeclIsRequiredFunctionOrFileScopedVar(const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
} else if (!isa<FunctionDecl>(D))
return false;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
// Constructors and destructors should never be deferred.
if (FD->hasAttr<ConstructorAttr>() ||
FD->hasAttr<DestructorAttr>())
// 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;
// The key function for a class must never be deferred.
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Global)) {
// Constructors and destructors are required.
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
return true;
ASTContext &Ctx = FD->getASTContext();
// 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 *KeyFunction = getContext().getKeyFunction(RD);
if (KeyFunction &&
KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
return false;
const CXXMethodDecl *KeyFunc = Ctx.getKeyFunction(RD);
if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
return true;
}
}
GVALinkage Linkage = GetLinkageForFunction(getContext(), FD, Features);
CodeGenModule::GVALinkage Linkage
= GetLinkageForFunction(FD, Ctx.getLangOptions());
// 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;
if (Linkage == CodeGenModule::GVA_Internal ||
Linkage == CodeGenModule::GVA_C99Inline ||
Linkage == CodeGenModule::GVA_CXXInline ||
Linkage == CodeGenModule::GVA_TemplateInstantiation)
return false;
return true;
}
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Invalid decl");
const VarDecl *VD = cast<VarDecl>(D);
assert(VD->isFileVarDecl() && "Expected file scoped var");
// Structs that have non-trivial constructors or destructors are required.
// 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;
return true;
}
}
GVALinkage L = GetLinkageForVariable(getContext(), VD);
if (L == GVA_Internal || L == GVA_TemplateInstantiation) {
if (!(VD->getInit() && VD->getInit()->HasSideEffects(Context)))
return true;
ASTContext &Ctx = VD->getASTContext();
CodeGenModule::GVALinkage L = GetLinkageForVariable(VD, Ctx.getLangOptions());
if (L == CodeGenModule::GVA_Internal ||
L == CodeGenModule::GVA_TemplateInstantiation) {
if (!(VD->getInit() && VD->getInit()->HasSideEffects(Ctx)))
return false;
}
return false;
return true;
}
bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// Never defer when EmitAllDecls is specified.
if (Features.EmitAllDecls)
return false;
return !DeclIsRequiredFunctionOrFileScopedVar(Global);
}
llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
@ -1271,7 +1293,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 = GetLinkageForVariable(D, Features);
if (Linkage == GVA_Internal)
GV->setLinkage(llvm::Function::InternalLinkage);
else if (D->hasAttr<DLLImportAttr>())

View File

@ -16,6 +16,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/CodeGen/BackendUtil.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/ErrorHandling.h"
@ -1078,63 +1079,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 DeclIsRequiredFunctionOrFileScopedVar(D);
}
void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) {

View File

@ -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

View File

@ -5,3 +5,6 @@ struct S {
};
static S globS;
extern int ext_foo;
static int bar = ++ext_foo;

View File

@ -17,7 +17,7 @@ SHARED_LIBRARY = 1
LINK_COMPONENTS := bitreader mc core
USEDLIBS = clangFrontend.a clangDriver.a clangSema.a \
clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a
clangAnalysis.a clangAST.a clangCodeGen.a clangParse.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile