[clang] 7ec342b - [C++20] [Modules] [Reduced BMI] Write Special Decl Lazily

Chuanqi Xu via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 17 23:43:27 PDT 2024


Author: Chuanqi Xu
Date: 2024-04-18T14:35:38+08:00
New Revision: 7ec342ba16ca97206aa2ddd5b7ec0da063042e03

URL: https://github.com/llvm/llvm-project/commit/7ec342ba16ca97206aa2ddd5b7ec0da063042e03
DIFF: https://github.com/llvm/llvm-project/commit/7ec342ba16ca97206aa2ddd5b7ec0da063042e03.diff

LOG: [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.

Added: 
    clang/test/Modules/reduced-bmi-empty-module-purview-std.cppm

Modified: 
    clang/include/clang/Serialization/ASTWriter.h
    clang/lib/Serialization/ASTWriter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h
index e093e6ad9d12c7..13b4ad4ad2953d 100644
--- a/clang/include/clang/Serialization/ASTWriter.h
+++ b/clang/include/clang/Serialization/ASTWriter.h
@@ -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);

diff  --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index ffeab4db9f6afc..9ae9648f38a3b7 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -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);
   }
 }
 
@@ -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.
@@ -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.
@@ -5001,21 +5004,22 @@ 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);
 
@@ -5023,9 +5027,13 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
   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);
   }
@@ -5033,7 +5041,7 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
   // 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);
@@ -5041,6 +5049,9 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
   // 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);
   }
@@ -5050,9 +5061,16 @@ 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);
@@ -5060,29 +5078,32 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
   // 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())
@@ -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);
   }
@@ -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) {
@@ -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));
 }

diff  --git a/clang/test/Modules/reduced-bmi-empty-module-purview-std.cppm b/clang/test/Modules/reduced-bmi-empty-module-purview-std.cppm
new file mode 100644
index 00000000000000..3146fda3555fdf
--- /dev/null
+++ b/clang/test/Modules/reduced-bmi-empty-module-purview-std.cppm
@@ -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


        


More information about the cfe-commits mailing list