Skip to content

Commit

Permalink
[C++20] [Modules] [Reduced BMI] Write Special Decl Lazily
Browse files Browse the repository at this point in the history
ASTWrite would write some special records for the consumer of the AST
can get the information easily. This is fine. But currently all the
special records are written eagerly, which is conflicting with reduced
BMI.

In reduced BMI, we hope to write things as less as possible. It is not a
goal for reduced BMI to retain all the informations. So in this patch we
won't record the special declarations eagerly before we starting write.
But only writing the sepcial records after we writes decls and types,
then only the reached declarations will be collected.
  • Loading branch information
ChuanqiXu9 committed Apr 18, 2024
1 parent 83cc605 commit 7ec342b
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 35 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,8 @@ class ASTWriter : public ASTDeserializationListener,

/// Emit a reference to a declaration.
void AddDeclRef(const Decl *D, RecordDataImpl &Record);
// Emit a reference to a declaration if the declaration was emitted.
void AddEmittedDeclRef(const Decl *D, RecordDataImpl &Record);

/// Force a declaration to be emitted and get its ID.
serialization::DeclID GetDeclRef(const Decl *D);
Expand Down
104 changes: 69 additions & 35 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4741,12 +4741,12 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec) {
}
}

template<typename Vector>
static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
ASTWriter::RecordData &Record) {
template <typename Vector>
static void AddLazyVectorEmiitedDecls(ASTWriter &Writer, Vector &Vec,
ASTWriter::RecordData &Record) {
for (typename Vector::iterator I = Vec.begin(nullptr, true), E = Vec.end();
I != E; ++I) {
Writer.AddDeclRef(*I, Record);
Writer.AddEmittedDeclRef(*I, Record);
}
}

Expand Down Expand Up @@ -4882,6 +4882,25 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) {
RegisterPredefDecl(Context.TypePackElementDecl,
PREDEF_DECL_TYPE_PACK_ELEMENT_ID);

const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();

// Force all top level declarations to be emitted.
//
// We start emitting top level declarations from the module purview to
// implement the eliding unreachable declaration feature.
for (const auto *D : TU->noload_decls()) {
if (D->isFromASTFile())
continue;

if (GeneratingReducedBMI && D->isFromExplicitGlobalModule())
continue;

GetDeclRef(D);
}

if (GeneratingReducedBMI)
return;

// Writing all of the tentative definitions in this file, in
// TentativeDefinitions order. Generally, this record will be empty for
// headers.
Expand Down Expand Up @@ -4943,22 +4962,6 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) {
SemaRef.getMismatchingDeleteExpressions())
GetDeclRef(DeleteExprsInfo.first);

const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();

// Force all top level declarations to be emitted.
//
// We start emitting top level declarations from the module purview to
// implement the eliding unreachable declaration feature.
for (const auto *D : TU->noload_decls()) {
if (D->isFromASTFile())
continue;

if (GeneratingReducedBMI && D->isFromExplicitGlobalModule())
continue;

GetDeclRef(D);
}

// Make sure visible decls, added to DeclContexts previously loaded from
// an AST file, are registered for serialization. Likewise for template
// specializations added to imported templates.
Expand Down Expand Up @@ -5001,46 +5004,54 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {

// Write the record containing tentative definitions.
RecordData TentativeDefinitions;
AddLazyVectorDecls(*this, SemaRef.TentativeDefinitions, TentativeDefinitions);
AddLazyVectorEmiitedDecls(*this, SemaRef.TentativeDefinitions,
TentativeDefinitions);
if (!TentativeDefinitions.empty())
Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);

// Write the record containing unused file scoped decls.
RecordData UnusedFileScopedDecls;
if (!isModule)
AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
UnusedFileScopedDecls);
AddLazyVectorEmiitedDecls(*this, SemaRef.UnusedFileScopedDecls,
UnusedFileScopedDecls);
if (!UnusedFileScopedDecls.empty())
Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls);

// Write the record containing ext_vector type names.
RecordData ExtVectorDecls;
AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls);
AddLazyVectorEmiitedDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls);
if (!ExtVectorDecls.empty())
Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls);

// Write the record containing VTable uses information.
RecordData VTableUses;
if (!SemaRef.VTableUses.empty()) {
for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) {
AddDeclRef(SemaRef.VTableUses[I].first, VTableUses);
CXXRecordDecl *D = SemaRef.VTableUses[I].first;
if (!wasDeclEmitted(D))
continue;

AddDeclRef(D, VTableUses);
AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses);
VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]);
VTableUses.push_back(SemaRef.VTablesUsed[D]);
}
Stream.EmitRecord(VTABLE_USES, VTableUses);
}

// Write the record containing potentially unused local typedefs.
RecordData UnusedLocalTypedefNameCandidates;
for (const TypedefNameDecl *TD : SemaRef.UnusedLocalTypedefNameCandidates)
AddDeclRef(TD, UnusedLocalTypedefNameCandidates);
AddEmittedDeclRef(TD, UnusedLocalTypedefNameCandidates);
if (!UnusedLocalTypedefNameCandidates.empty())
Stream.EmitRecord(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES,
UnusedLocalTypedefNameCandidates);

// Write the record containing pending implicit instantiations.
RecordData PendingInstantiations;
for (const auto &I : SemaRef.PendingInstantiations) {
if (!wasDeclEmitted(I.first))
continue;

AddDeclRef(I.first, PendingInstantiations);
AddSourceLocation(I.second, PendingInstantiations);
}
Expand All @@ -5050,39 +5061,49 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
// Write the record containing declaration references of Sema.
RecordData SemaDeclRefs;
if (SemaRef.StdNamespace || SemaRef.StdBadAlloc || SemaRef.StdAlignValT) {
AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs);
AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs);
AddDeclRef(SemaRef.getStdAlignValT(), SemaDeclRefs);
auto AddEmittedDeclRefOrZero = [this, &SemaDeclRefs, &SemaRef](Decl *D) {
if (!D || !wasDeclEmitted(D))
SemaDeclRefs.push_back(0);
else
SemaDeclRefs.push_back(getDeclID(D));
};

AddEmittedDeclRefOrZero(SemaRef.getStdNamespace());
AddEmittedDeclRefOrZero(SemaRef.getStdBadAlloc());
AddEmittedDeclRefOrZero(SemaRef.getStdAlignValT());
}
if (!SemaDeclRefs.empty())
Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);

// Write the record containing decls to be checked for deferred diags.
SmallVector<serialization::DeclID, 64> DeclsToCheckForDeferredDiags;
for (auto *D : SemaRef.DeclsToCheckForDeferredDiags)
DeclsToCheckForDeferredDiags.push_back(GetDeclRef(D));
if (wasDeclEmitted(D))
DeclsToCheckForDeferredDiags.push_back(getDeclID(D));
if (!DeclsToCheckForDeferredDiags.empty())
Stream.EmitRecord(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS,
DeclsToCheckForDeferredDiags);

// Write the record containing CUDA-specific declaration references.
RecordData CUDASpecialDeclRefs;
if (Context.getcudaConfigureCallDecl()) {
AddDeclRef(Context.getcudaConfigureCallDecl(), CUDASpecialDeclRefs);
if (auto *CudaCallDecl = Context.getcudaConfigureCallDecl();
CudaCallDecl && wasDeclEmitted(CudaCallDecl)) {
AddDeclRef(CudaCallDecl, CUDASpecialDeclRefs);
Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs);
}

// Write the delegating constructors.
RecordData DelegatingCtorDecls;
if (!isModule)
AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
AddLazyVectorEmiitedDecls(*this, SemaRef.DelegatingCtorDecls,
DelegatingCtorDecls);
if (!DelegatingCtorDecls.empty())
Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);

// Write the known namespaces.
RecordData KnownNamespaces;
for (const auto &I : SemaRef.KnownNamespaces) {
if (!I.second)
if (!I.second && wasDeclEmitted(I.first))
AddDeclRef(I.first, KnownNamespaces);
}
if (!KnownNamespaces.empty())
Expand All @@ -5093,6 +5114,9 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
SemaRef.getUndefinedButUsed(Undefined);
for (const auto &I : Undefined) {
if (!wasDeclEmitted(I.first))
continue;

AddDeclRef(I.first, UndefinedButUsed);
AddSourceLocation(I.second, UndefinedButUsed);
}
Expand All @@ -5105,6 +5129,9 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
if (!isModule) {
for (const auto &DeleteExprsInfo :
SemaRef.getMismatchingDeleteExpressions()) {
if (!wasDeclEmitted(DeleteExprsInfo.first))
continue;

AddDeclRef(DeleteExprsInfo.first, DeleteExprsToAnalyze);
DeleteExprsToAnalyze.push_back(DeleteExprsInfo.second.size());
for (const auto &DeleteLoc : DeleteExprsInfo.second) {
Expand Down Expand Up @@ -5919,6 +5946,13 @@ TypeID ASTWriter::getTypeID(QualType T) const {
});
}

void ASTWriter::AddEmittedDeclRef(const Decl *D, RecordDataImpl &Record) {
if (!wasDeclEmitted(D))
return;

Record.push_back(GetDeclRef(D));
}

void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) {
Record.push_back(GetDeclRef(D));
}
Expand Down
27 changes: 27 additions & 0 deletions clang/test/Modules/reduced-bmi-empty-module-purview-std.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Test that we won't write additional information from std namespace by default
// into the Reduced BMI if the module purview is empty.
//
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-reduced-module-interface -o %t/A.pcm
// RUN: llvm-bcanalyzer --dump --disable-histogram --show-binary-blobs %t/A.pcm > %t/A.dump
// RUN: cat %t/A.dump | FileCheck %t/A.cppm

//--- std.h
namespace std {
typedef decltype(sizeof(0)) size_t;
enum class align_val_t : std::size_t {};

class bad_alloc { };
}

//--- A.cppm
module;
#include "std.h"
export module A;

// CHECK-NOT: <DECL_NAMESPACE
// CHECK-NOT: <DECL_CONTEXT_LEXICAL
// CHECK-NOT: <DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD

0 comments on commit 7ec342b

Please sign in to comment.