Skip to content

Commit 7ec342b

Browse files
committed
[C++20] [Modules] [Reduced BMI] Write Special Decl Lazily
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.
1 parent 83cc605 commit 7ec342b

File tree

3 files changed

+98
-35
lines changed

3 files changed

+98
-35
lines changed

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,8 @@ class ASTWriter : public ASTDeserializationListener,
714714

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

718720
/// Force a declaration to be emitted and get its ID.
719721
serialization::DeclID GetDeclRef(const Decl *D);

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4741,12 +4741,12 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec) {
47414741
}
47424742
}
47434743

4744-
template<typename Vector>
4745-
static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
4746-
ASTWriter::RecordData &Record) {
4744+
template <typename Vector>
4745+
static void AddLazyVectorEmiitedDecls(ASTWriter &Writer, Vector &Vec,
4746+
ASTWriter::RecordData &Record) {
47474747
for (typename Vector::iterator I = Vec.begin(nullptr, true), E = Vec.end();
47484748
I != E; ++I) {
4749-
Writer.AddDeclRef(*I, Record);
4749+
Writer.AddEmittedDeclRef(*I, Record);
47504750
}
47514751
}
47524752

@@ -4882,6 +4882,25 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) {
48824882
RegisterPredefDecl(Context.TypePackElementDecl,
48834883
PREDEF_DECL_TYPE_PACK_ELEMENT_ID);
48844884

4885+
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
4886+
4887+
// Force all top level declarations to be emitted.
4888+
//
4889+
// We start emitting top level declarations from the module purview to
4890+
// implement the eliding unreachable declaration feature.
4891+
for (const auto *D : TU->noload_decls()) {
4892+
if (D->isFromASTFile())
4893+
continue;
4894+
4895+
if (GeneratingReducedBMI && D->isFromExplicitGlobalModule())
4896+
continue;
4897+
4898+
GetDeclRef(D);
4899+
}
4900+
4901+
if (GeneratingReducedBMI)
4902+
return;
4903+
48854904
// Writing all of the tentative definitions in this file, in
48864905
// TentativeDefinitions order. Generally, this record will be empty for
48874906
// headers.
@@ -4943,22 +4962,6 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) {
49434962
SemaRef.getMismatchingDeleteExpressions())
49444963
GetDeclRef(DeleteExprsInfo.first);
49454964

4946-
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
4947-
4948-
// Force all top level declarations to be emitted.
4949-
//
4950-
// We start emitting top level declarations from the module purview to
4951-
// implement the eliding unreachable declaration feature.
4952-
for (const auto *D : TU->noload_decls()) {
4953-
if (D->isFromASTFile())
4954-
continue;
4955-
4956-
if (GeneratingReducedBMI && D->isFromExplicitGlobalModule())
4957-
continue;
4958-
4959-
GetDeclRef(D);
4960-
}
4961-
49624965
// Make sure visible decls, added to DeclContexts previously loaded from
49634966
// an AST file, are registered for serialization. Likewise for template
49644967
// specializations added to imported templates.
@@ -5001,46 +5004,54 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
50015004

50025005
// Write the record containing tentative definitions.
50035006
RecordData TentativeDefinitions;
5004-
AddLazyVectorDecls(*this, SemaRef.TentativeDefinitions, TentativeDefinitions);
5007+
AddLazyVectorEmiitedDecls(*this, SemaRef.TentativeDefinitions,
5008+
TentativeDefinitions);
50055009
if (!TentativeDefinitions.empty())
50065010
Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);
50075011

50085012
// Write the record containing unused file scoped decls.
50095013
RecordData UnusedFileScopedDecls;
50105014
if (!isModule)
5011-
AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
5012-
UnusedFileScopedDecls);
5015+
AddLazyVectorEmiitedDecls(*this, SemaRef.UnusedFileScopedDecls,
5016+
UnusedFileScopedDecls);
50135017
if (!UnusedFileScopedDecls.empty())
50145018
Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls);
50155019

50165020
// Write the record containing ext_vector type names.
50175021
RecordData ExtVectorDecls;
5018-
AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls);
5022+
AddLazyVectorEmiitedDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls);
50195023
if (!ExtVectorDecls.empty())
50205024
Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls);
50215025

50225026
// Write the record containing VTable uses information.
50235027
RecordData VTableUses;
50245028
if (!SemaRef.VTableUses.empty()) {
50255029
for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) {
5026-
AddDeclRef(SemaRef.VTableUses[I].first, VTableUses);
5030+
CXXRecordDecl *D = SemaRef.VTableUses[I].first;
5031+
if (!wasDeclEmitted(D))
5032+
continue;
5033+
5034+
AddDeclRef(D, VTableUses);
50275035
AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses);
5028-
VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]);
5036+
VTableUses.push_back(SemaRef.VTablesUsed[D]);
50295037
}
50305038
Stream.EmitRecord(VTABLE_USES, VTableUses);
50315039
}
50325040

50335041
// Write the record containing potentially unused local typedefs.
50345042
RecordData UnusedLocalTypedefNameCandidates;
50355043
for (const TypedefNameDecl *TD : SemaRef.UnusedLocalTypedefNameCandidates)
5036-
AddDeclRef(TD, UnusedLocalTypedefNameCandidates);
5044+
AddEmittedDeclRef(TD, UnusedLocalTypedefNameCandidates);
50375045
if (!UnusedLocalTypedefNameCandidates.empty())
50385046
Stream.EmitRecord(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES,
50395047
UnusedLocalTypedefNameCandidates);
50405048

50415049
// Write the record containing pending implicit instantiations.
50425050
RecordData PendingInstantiations;
50435051
for (const auto &I : SemaRef.PendingInstantiations) {
5052+
if (!wasDeclEmitted(I.first))
5053+
continue;
5054+
50445055
AddDeclRef(I.first, PendingInstantiations);
50455056
AddSourceLocation(I.second, PendingInstantiations);
50465057
}
@@ -5050,39 +5061,49 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
50505061
// Write the record containing declaration references of Sema.
50515062
RecordData SemaDeclRefs;
50525063
if (SemaRef.StdNamespace || SemaRef.StdBadAlloc || SemaRef.StdAlignValT) {
5053-
AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs);
5054-
AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs);
5055-
AddDeclRef(SemaRef.getStdAlignValT(), SemaDeclRefs);
5064+
auto AddEmittedDeclRefOrZero = [this, &SemaDeclRefs, &SemaRef](Decl *D) {
5065+
if (!D || !wasDeclEmitted(D))
5066+
SemaDeclRefs.push_back(0);
5067+
else
5068+
SemaDeclRefs.push_back(getDeclID(D));
5069+
};
5070+
5071+
AddEmittedDeclRefOrZero(SemaRef.getStdNamespace());
5072+
AddEmittedDeclRefOrZero(SemaRef.getStdBadAlloc());
5073+
AddEmittedDeclRefOrZero(SemaRef.getStdAlignValT());
50565074
}
50575075
if (!SemaDeclRefs.empty())
50585076
Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);
50595077

50605078
// Write the record containing decls to be checked for deferred diags.
50615079
SmallVector<serialization::DeclID, 64> DeclsToCheckForDeferredDiags;
50625080
for (auto *D : SemaRef.DeclsToCheckForDeferredDiags)
5063-
DeclsToCheckForDeferredDiags.push_back(GetDeclRef(D));
5081+
if (wasDeclEmitted(D))
5082+
DeclsToCheckForDeferredDiags.push_back(getDeclID(D));
50645083
if (!DeclsToCheckForDeferredDiags.empty())
50655084
Stream.EmitRecord(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS,
50665085
DeclsToCheckForDeferredDiags);
50675086

50685087
// Write the record containing CUDA-specific declaration references.
50695088
RecordData CUDASpecialDeclRefs;
5070-
if (Context.getcudaConfigureCallDecl()) {
5071-
AddDeclRef(Context.getcudaConfigureCallDecl(), CUDASpecialDeclRefs);
5089+
if (auto *CudaCallDecl = Context.getcudaConfigureCallDecl();
5090+
CudaCallDecl && wasDeclEmitted(CudaCallDecl)) {
5091+
AddDeclRef(CudaCallDecl, CUDASpecialDeclRefs);
50725092
Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs);
50735093
}
50745094

50755095
// Write the delegating constructors.
50765096
RecordData DelegatingCtorDecls;
50775097
if (!isModule)
5078-
AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
5098+
AddLazyVectorEmiitedDecls(*this, SemaRef.DelegatingCtorDecls,
5099+
DelegatingCtorDecls);
50795100
if (!DelegatingCtorDecls.empty())
50805101
Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
50815102

50825103
// Write the known namespaces.
50835104
RecordData KnownNamespaces;
50845105
for (const auto &I : SemaRef.KnownNamespaces) {
5085-
if (!I.second)
5106+
if (!I.second && wasDeclEmitted(I.first))
50865107
AddDeclRef(I.first, KnownNamespaces);
50875108
}
50885109
if (!KnownNamespaces.empty())
@@ -5093,6 +5114,9 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
50935114
SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
50945115
SemaRef.getUndefinedButUsed(Undefined);
50955116
for (const auto &I : Undefined) {
5117+
if (!wasDeclEmitted(I.first))
5118+
continue;
5119+
50965120
AddDeclRef(I.first, UndefinedButUsed);
50975121
AddSourceLocation(I.second, UndefinedButUsed);
50985122
}
@@ -5105,6 +5129,9 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
51055129
if (!isModule) {
51065130
for (const auto &DeleteExprsInfo :
51075131
SemaRef.getMismatchingDeleteExpressions()) {
5132+
if (!wasDeclEmitted(DeleteExprsInfo.first))
5133+
continue;
5134+
51085135
AddDeclRef(DeleteExprsInfo.first, DeleteExprsToAnalyze);
51095136
DeleteExprsToAnalyze.push_back(DeleteExprsInfo.second.size());
51105137
for (const auto &DeleteLoc : DeleteExprsInfo.second) {
@@ -5919,6 +5946,13 @@ TypeID ASTWriter::getTypeID(QualType T) const {
59195946
});
59205947
}
59215948

5949+
void ASTWriter::AddEmittedDeclRef(const Decl *D, RecordDataImpl &Record) {
5950+
if (!wasDeclEmitted(D))
5951+
return;
5952+
5953+
Record.push_back(GetDeclRef(D));
5954+
}
5955+
59225956
void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) {
59235957
Record.push_back(GetDeclRef(D));
59245958
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Test that we won't write additional information from std namespace by default
2+
// into the Reduced BMI if the module purview is empty.
3+
//
4+
// RUN: rm -rf %t
5+
// RUN: mkdir -p %t
6+
// RUN: split-file %s %t
7+
//
8+
// RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-reduced-module-interface -o %t/A.pcm
9+
// RUN: llvm-bcanalyzer --dump --disable-histogram --show-binary-blobs %t/A.pcm > %t/A.dump
10+
// RUN: cat %t/A.dump | FileCheck %t/A.cppm
11+
12+
//--- std.h
13+
namespace std {
14+
typedef decltype(sizeof(0)) size_t;
15+
enum class align_val_t : std::size_t {};
16+
17+
class bad_alloc { };
18+
}
19+
20+
//--- A.cppm
21+
module;
22+
#include "std.h"
23+
export module A;
24+
25+
// CHECK-NOT: <DECL_NAMESPACE
26+
// CHECK-NOT: <DECL_CONTEXT_LEXICAL
27+
// CHECK-NOT: <DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD

0 commit comments

Comments
 (0)