Modular Codegen: Support homing debug info for types in modular objects
Matching the function-homing support for modular codegen. Any type implicitly (implicit template specializations) or explicitly defined in a module is attached to that module's object file and omitted elsewhere (only a declaration used if necessary for references). llvm-svn: 299987
This commit is contained in:
parent
ddb9ae192a
commit
1ac9c98e6c
|
|
@ -172,7 +172,7 @@ public:
|
||||||
|
|
||||||
enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
|
enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
|
||||||
|
|
||||||
virtual ExtKind hasExternalDefinitions(const FunctionDecl *FD);
|
virtual ExtKind hasExternalDefinitions(const Decl *D);
|
||||||
|
|
||||||
/// \brief Finds all declarations lexically contained within the given
|
/// \brief Finds all declarations lexically contained within the given
|
||||||
/// DeclContext, after applying an optional filter predicate.
|
/// DeclContext, after applying an optional filter predicate.
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ public:
|
||||||
/// initializers themselves.
|
/// initializers themselves.
|
||||||
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
|
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
|
||||||
|
|
||||||
ExtKind hasExternalDefinitions(const FunctionDecl *FD) override;
|
ExtKind hasExternalDefinitions(const Decl *D) override;
|
||||||
|
|
||||||
/// \brief Find all declarations with the given name in the
|
/// \brief Find all declarations with the given name in the
|
||||||
/// given context.
|
/// given context.
|
||||||
|
|
|
||||||
|
|
@ -1115,7 +1115,7 @@ private:
|
||||||
/// predefines buffer may contain additional definitions.
|
/// predefines buffer may contain additional definitions.
|
||||||
std::string SuggestedPredefines;
|
std::string SuggestedPredefines;
|
||||||
|
|
||||||
llvm::DenseMap<const FunctionDecl *, bool> BodySource;
|
llvm::DenseMap<const Decl *, bool> BodySource;
|
||||||
|
|
||||||
/// \brief Reads a statement from the specified cursor.
|
/// \brief Reads a statement from the specified cursor.
|
||||||
Stmt *ReadStmtFromStream(ModuleFile &F);
|
Stmt *ReadStmtFromStream(ModuleFile &F);
|
||||||
|
|
@ -1999,7 +1999,7 @@ public:
|
||||||
/// \brief Return a descriptor for the corresponding module.
|
/// \brief Return a descriptor for the corresponding module.
|
||||||
llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
|
llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
|
||||||
|
|
||||||
ExtKind hasExternalDefinitions(const FunctionDecl *FD) override;
|
ExtKind hasExternalDefinitions(const Decl *D) override;
|
||||||
|
|
||||||
/// \brief Retrieve a selector from the given module with its local ID
|
/// \brief Retrieve a selector from the given module with its local ID
|
||||||
/// number.
|
/// number.
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ ExternalASTSource::getSourceDescriptor(unsigned ID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalASTSource::ExtKind
|
ExternalASTSource::ExtKind
|
||||||
ExternalASTSource::hasExternalDefinitions(const FunctionDecl *FD) {
|
ExternalASTSource::hasExternalDefinitions(const Decl *D) {
|
||||||
return EK_ReplyHazy;
|
return EK_ReplyHazy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1820,6 +1820,10 @@ static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind,
|
||||||
if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
|
if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (auto *ES = RD->getASTContext().getExternalSource())
|
||||||
|
if (ES->hasExternalDefinitions(RD) == ExternalASTSource::EK_Always)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (DebugKind > codegenoptions::LimitedDebugInfo)
|
if (DebugKind > codegenoptions::LimitedDebugInfo)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -2552,11 +2556,17 @@ void CGDebugInfo::completeTemplateDefinition(
|
||||||
const ClassTemplateSpecializationDecl &SD) {
|
const ClassTemplateSpecializationDecl &SD) {
|
||||||
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
|
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
|
||||||
return;
|
return;
|
||||||
|
completeUnusedClass(SD);
|
||||||
|
}
|
||||||
|
|
||||||
completeClassData(&SD);
|
void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) {
|
||||||
|
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
|
||||||
|
return;
|
||||||
|
|
||||||
|
completeClassData(&D);
|
||||||
// In case this type has no member function definitions being emitted, ensure
|
// In case this type has no member function definitions being emitted, ensure
|
||||||
// it is retained
|
// it is retained
|
||||||
RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr());
|
RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
|
llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
|
||||||
|
|
|
||||||
|
|
@ -438,6 +438,7 @@ public:
|
||||||
void completeClass(const RecordDecl *RD);
|
void completeClass(const RecordDecl *RD);
|
||||||
|
|
||||||
void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
|
void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
|
||||||
|
void completeUnusedClass(const CXXRecordDecl &D);
|
||||||
|
|
||||||
/// Create debug info for a macro defined by a #define directive or a macro
|
/// Create debug info for a macro defined by a #define directive or a macro
|
||||||
/// undefined by a #undef directive.
|
/// undefined by a #undef directive.
|
||||||
|
|
|
||||||
|
|
@ -3820,6 +3820,11 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
|
||||||
EmitDeclContext(cast<NamespaceDecl>(D));
|
EmitDeclContext(cast<NamespaceDecl>(D));
|
||||||
break;
|
break;
|
||||||
case Decl::CXXRecord:
|
case Decl::CXXRecord:
|
||||||
|
if (DebugInfo) {
|
||||||
|
if (auto *ES = D->getASTContext().getExternalSource())
|
||||||
|
if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never)
|
||||||
|
DebugInfo->completeUnusedClass(cast<CXXRecordDecl>(*D));
|
||||||
|
}
|
||||||
// Emit any static data members, they may be definitions.
|
// Emit any static data members, they may be definitions.
|
||||||
for (auto *I : cast<CXXRecordDecl>(D)->decls())
|
for (auto *I : cast<CXXRecordDecl>(D)->decls())
|
||||||
if (isa<VarDecl>(I) || isa<CXXRecordDecl>(I))
|
if (isa<VarDecl>(I) || isa<CXXRecordDecl>(I))
|
||||||
|
|
|
||||||
|
|
@ -95,9 +95,9 @@ MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalASTSource::ExtKind
|
ExternalASTSource::ExtKind
|
||||||
MultiplexExternalSemaSource::hasExternalDefinitions(const FunctionDecl *FD) {
|
MultiplexExternalSemaSource::hasExternalDefinitions(const Decl *D) {
|
||||||
for (const auto &S : Sources)
|
for (const auto &S : Sources)
|
||||||
if (auto EK = S->hasExternalDefinitions(FD))
|
if (auto EK = S->hasExternalDefinitions(D))
|
||||||
if (EK != EK_ReplyHazy)
|
if (EK != EK_ReplyHazy)
|
||||||
return EK;
|
return EK;
|
||||||
return EK_ReplyHazy;
|
return EK_ReplyHazy;
|
||||||
|
|
|
||||||
|
|
@ -8147,8 +8147,7 @@ ASTReader::getSourceDescriptor(unsigned ID) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalASTSource::ExtKind
|
ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) {
|
||||||
ASTReader::hasExternalDefinitions(const FunctionDecl *FD) {
|
|
||||||
auto I = BodySource.find(FD);
|
auto I = BodySource.find(FD);
|
||||||
if (I == BodySource.end())
|
if (I == BodySource.end())
|
||||||
return EK_ReplyHazy;
|
return EK_ReplyHazy;
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,8 @@ namespace clang {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update);
|
void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update);
|
||||||
void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data);
|
void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
|
||||||
|
const CXXRecordDecl *D);
|
||||||
void MergeDefinitionData(CXXRecordDecl *D,
|
void MergeDefinitionData(CXXRecordDecl *D,
|
||||||
struct CXXRecordDecl::DefinitionData &&NewDD);
|
struct CXXRecordDecl::DefinitionData &&NewDD);
|
||||||
void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data);
|
void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data);
|
||||||
|
|
@ -1490,7 +1491,7 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTDeclReader::ReadCXXDefinitionData(
|
void ASTDeclReader::ReadCXXDefinitionData(
|
||||||
struct CXXRecordDecl::DefinitionData &Data) {
|
struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D) {
|
||||||
// Note: the caller has deserialized the IsLambda bit already.
|
// Note: the caller has deserialized the IsLambda bit already.
|
||||||
Data.UserDeclaredConstructor = Record.readInt();
|
Data.UserDeclaredConstructor = Record.readInt();
|
||||||
Data.UserDeclaredSpecialMembers = Record.readInt();
|
Data.UserDeclaredSpecialMembers = Record.readInt();
|
||||||
|
|
@ -1536,6 +1537,12 @@ void ASTDeclReader::ReadCXXDefinitionData(
|
||||||
Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt();
|
Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt();
|
||||||
Data.ODRHash = Record.readInt();
|
Data.ODRHash = Record.readInt();
|
||||||
|
|
||||||
|
if (Record.readInt()) {
|
||||||
|
Reader.BodySource[D] = Loc.F->Kind == ModuleKind::MK_MainFile
|
||||||
|
? ExternalASTSource::EK_Never
|
||||||
|
: ExternalASTSource::EK_Always;
|
||||||
|
}
|
||||||
|
|
||||||
Data.NumBases = Record.readInt();
|
Data.NumBases = Record.readInt();
|
||||||
if (Data.NumBases)
|
if (Data.NumBases)
|
||||||
Data.Bases = ReadGlobalOffset();
|
Data.Bases = ReadGlobalOffset();
|
||||||
|
|
@ -1707,7 +1714,7 @@ void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) {
|
||||||
else
|
else
|
||||||
DD = new (C) struct CXXRecordDecl::DefinitionData(D);
|
DD = new (C) struct CXXRecordDecl::DefinitionData(D);
|
||||||
|
|
||||||
ReadCXXDefinitionData(*DD);
|
ReadCXXDefinitionData(*DD, D);
|
||||||
|
|
||||||
// We might already have a definition for this record. This can happen either
|
// We might already have a definition for this record. This can happen either
|
||||||
// because we're reading an update record, or because we've already done some
|
// because we're reading an update record, or because we've already done some
|
||||||
|
|
@ -2554,6 +2561,10 @@ static bool isConsumerInterestedIn(ASTContext &Ctx, Decl *D, bool HasBody) {
|
||||||
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
|
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
|
||||||
return Func->doesThisDeclarationHaveABody() || HasBody;
|
return Func->doesThisDeclarationHaveABody() || HasBody;
|
||||||
|
|
||||||
|
if (auto *ES = D->getASTContext().getExternalSource())
|
||||||
|
if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never)
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5770,6 +5770,12 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
|
||||||
Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
|
Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
|
||||||
Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
|
Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
|
||||||
Record->push_back(Data.ODRHash);
|
Record->push_back(Data.ODRHash);
|
||||||
|
bool ModularCodegen = Writer->Context->getLangOpts().ModularCodegen &&
|
||||||
|
Writer->WritingModule && !D->isDependentType();
|
||||||
|
Record->push_back(ModularCodegen);
|
||||||
|
if (ModularCodegen)
|
||||||
|
Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D));
|
||||||
|
|
||||||
// IsLambda bit is already saved.
|
// IsLambda bit is already saved.
|
||||||
|
|
||||||
Record->push_back(Data.NumBases);
|
Record->push_back(Data.NumBases);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ftempl() {
|
void foot() {
|
||||||
}
|
}
|
||||||
inline void f() {
|
inline void foo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct bart {
|
||||||
|
};
|
||||||
|
struct bar {
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ RUN: %S/Inputs/codegen-nodep/foo.modulemap -o - \
|
||||||
RUN: | llvm-bcanalyzer - -dump \
|
RUN: | llvm-bcanalyzer - -dump \
|
||||||
RUN: | FileCheck %s
|
RUN: | FileCheck %s
|
||||||
|
|
||||||
Ensure there's only one modular codegen decl - the sentinel plain inline
|
Ensure there are only two modular codegen decls (one for the class, one for the
|
||||||
function, not any for the function template.
|
function - none for the class and function templates).
|
||||||
|
|
||||||
CHECK: <MODULAR_CODEGEN_DECLS op0={{[0-9]+}}/>
|
CHECK: <MODULAR_CODEGEN_DECLS op0={{[0-9]+}} op1={{[0-9]+}}/>
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ REQUIRES: x86-registered-target
|
||||||
|
|
||||||
RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen/foo.modulemap -o %t/foo.pcm
|
RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen/foo.modulemap -o %t/foo.pcm
|
||||||
|
|
||||||
RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %t/foo.pcm | FileCheck --check-prefix=FOO --check-prefix=BOTH %s
|
RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - %t/foo.pcm | FileCheck --check-prefix=FOO --check-prefix=BOTH %s
|
||||||
RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -fmodules -fmodule-file=%t/foo.pcm %S/Inputs/codegen/use.cpp | FileCheck --check-prefix=BOTH --check-prefix=USE %s
|
RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - -fmodules -fmodule-file=%t/foo.pcm %S/Inputs/codegen/use.cpp | FileCheck --check-prefix=BOTH --check-prefix=USE %s
|
||||||
|
|
||||||
FOO: $_Z2f1PKcz = comdat any
|
FOO: $_Z2f1PKcz = comdat any
|
||||||
FOO: $_ZN13implicit_dtorD1Ev = comdat any
|
FOO: $_ZN13implicit_dtorD1Ev = comdat any
|
||||||
|
|
@ -25,3 +25,11 @@ FOO: define weak_odr void @_ZN13implicit_dtorD2Ev
|
||||||
USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD1Ev
|
USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD1Ev
|
||||||
USE: define linkonce_odr void @_Z4instIiEvv
|
USE: define linkonce_odr void @_Z4instIiEvv
|
||||||
USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD2Ev
|
USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD2Ev
|
||||||
|
|
||||||
|
Modular debug info puts the definition of a class defined in a module in that
|
||||||
|
module's object. Users of the module only get a declaration.
|
||||||
|
|
||||||
|
'distinct' is used for definition records (the flags field is empty/unspecified)
|
||||||
|
FOO: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "implicit_dtor"
|
||||||
|
Declarations are non-distinct and include the 'DIFlagFwdDecl' flag.
|
||||||
|
USE: = !DICompositeType(tag: DW_TAG_structure_type, name: "implicit_dtor", {{.*}}, flags: DIFlagFwdDecl
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue