Skip to content

Commit f2695a1

Browse files
committed
[C++20] [Modules] Avoid writing untouched DeclUpdates from GMF in
Reduced BMI Mitigate #61447 The root cause of the above problem is that when we write a declaration, we need to lookup all the redeclarations in the imported modules. Then it will be pretty slow if there are too many redeclarations in different modules. This patch doesn't solve the porblem. What the patchs mitigated is, when we writing a named module, we shouldn't write the declarations from GMF if it is unreferenced **in current module unit**. The difference here is that, if the declaration is used in the imported modules, we used to emit it as an update. But we definitely want to avoid that after this patch. For that reproducer in #61447, it used to take 2.5s to compile and now it only takes 0.49s to compile, which is a big win.
1 parent b6cc667 commit f2695a1

File tree

9 files changed

+231
-26
lines changed

9 files changed

+231
-26
lines changed

clang/include/clang/AST/ASTMutationListener.h

+27
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ namespace clang {
2727
class FunctionTemplateDecl;
2828
class Module;
2929
class NamedDecl;
30+
class NamespaceDecl;
3031
class ObjCCategoryDecl;
3132
class ObjCContainerDecl;
3233
class ObjCInterfaceDecl;
@@ -35,6 +36,7 @@ namespace clang {
3536
class QualType;
3637
class RecordDecl;
3738
class TagDecl;
39+
class TranslationUnitDecl;
3840
class ValueDecl;
3941
class VarDecl;
4042
class VarTemplateDecl;
@@ -147,6 +149,31 @@ class ASTMutationListener {
147149
virtual void AddedAttributeToRecord(const Attr *Attr,
148150
const RecordDecl *Record) {}
149151

152+
/// The parser find the named module declaration.
153+
virtual void EnteringModulePurview() {}
154+
155+
/// An mangling number was added to a Decl
156+
///
157+
/// \param D The decl that got a mangling number
158+
///
159+
/// \param Number The mangling number that was added to the Decl
160+
virtual void AddedManglingNumber(const Decl *D, unsigned Number) {}
161+
162+
/// An static local number was added to a Decl
163+
///
164+
/// \param D The decl that got a static local number
165+
///
166+
/// \param Number The static local number that was added to the Decl
167+
virtual void AddedStaticLocalNumbers(const Decl *D, unsigned Number) {}
168+
169+
/// An anonymous namespace was added the translation unit decl
170+
///
171+
/// \param TU The translation unit decl that got a new anonymous namespace
172+
///
173+
/// \param AnonNamespace The anonymous namespace that was added
174+
virtual void AddedAnonymousNamespace(const TranslationUnitDecl *TU,
175+
NamespaceDecl *AnonNamespace) {}
176+
150177
// NOTE: If new methods are added they should also be added to
151178
// MultiplexASTMutationListener.
152179
};

clang/include/clang/AST/Decl.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class TranslationUnitDecl : public Decl,
120120
ASTContext &getASTContext() const { return Ctx; }
121121

122122
NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; }
123-
void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; }
123+
void setAnonymousNamespace(NamespaceDecl *D);
124124

125125
static TranslationUnitDecl *Create(ASTContext &C);
126126

clang/include/clang/Serialization/ASTWriter.h

+10
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,11 @@ class ASTWriter : public ASTDeserializationListener,
399399
/// record containing modifications to them.
400400
DeclUpdateMap DeclUpdates;
401401

402+
/// DeclUpdates added during parsing the GMF. We split these from
403+
/// DeclUpdates since we want to add these updates in GMF on need.
404+
/// Only meaningful for reduced BMI.
405+
DeclUpdateMap DeclUpdatesFromGMF;
406+
402407
using FirstLatestDeclMap = llvm::DenseMap<Decl *, Decl *>;
403408

404409
/// Map of first declarations from a chained PCH that point to the
@@ -866,6 +871,11 @@ class ASTWriter : public ASTDeserializationListener,
866871
void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
867872
void AddedAttributeToRecord(const Attr *Attr,
868873
const RecordDecl *Record) override;
874+
void EnteringModulePurview() override;
875+
void AddedManglingNumber(const Decl *D, unsigned) override;
876+
void AddedStaticLocalNumbers(const Decl *D, unsigned) override;
877+
void AddedAnonymousNamespace(const TranslationUnitDecl *,
878+
NamespaceDecl *AnonNamespace) override;
869879
};
870880

871881
/// AST and semantic-analysis consumer that generates a

clang/lib/AST/ASTContext.cpp

+14-4
Original file line numberDiff line numberDiff line change
@@ -12245,8 +12245,13 @@ QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth,
1224512245
}
1224612246

1224712247
void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) {
12248-
if (Number > 1)
12249-
MangleNumbers[ND] = Number;
12248+
if (Number <= 1)
12249+
return;
12250+
12251+
MangleNumbers[ND] = Number;
12252+
12253+
if (Listener)
12254+
Listener->AddedManglingNumber(ND, Number);
1225012255
}
1225112256

1225212257
unsigned ASTContext::getManglingNumber(const NamedDecl *ND,
@@ -12265,8 +12270,13 @@ unsigned ASTContext::getManglingNumber(const NamedDecl *ND,
1226512270
}
1226612271

1226712272
void ASTContext::setStaticLocalNumber(const VarDecl *VD, unsigned Number) {
12268-
if (Number > 1)
12269-
StaticLocalNumbers[VD] = Number;
12273+
if (Number <= 1)
12274+
return;
12275+
12276+
StaticLocalNumbers[VD] = Number;
12277+
12278+
if (Listener)
12279+
Listener->AddedStaticLocalNumbers(VD, Number);
1227012280
}
1227112281

1227212282
unsigned ASTContext::getStaticLocalNumber(const VarDecl *VD) const {

clang/lib/AST/Decl.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -5274,6 +5274,13 @@ TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
52745274
return new (C, (DeclContext *)nullptr) TranslationUnitDecl(C);
52755275
}
52765276

5277+
void TranslationUnitDecl::setAnonymousNamespace(NamespaceDecl *D) {
5278+
AnonymousNamespace = D;
5279+
5280+
if (ASTMutationListener *Listener = Ctx.getASTMutationListener())
5281+
Listener->AddedAnonymousNamespace(this, D);
5282+
}
5283+
52775284
void PragmaCommentDecl::anchor() {}
52785285

52795286
PragmaCommentDecl *PragmaCommentDecl::Create(const ASTContext &C,

clang/lib/Frontend/MultiplexConsumer.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ using namespace clang;
2020

2121
namespace clang {
2222

23+
class NamespaceDecl;
24+
class TranslationUnitDecl;
25+
2326
MultiplexASTDeserializationListener::MultiplexASTDeserializationListener(
2427
const std::vector<ASTDeserializationListener*>& L)
2528
: Listeners(L) {
@@ -115,6 +118,11 @@ class MultiplexASTMutationListener : public ASTMutationListener {
115118
void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override;
116119
void AddedAttributeToRecord(const Attr *Attr,
117120
const RecordDecl *Record) override;
121+
void EnteringModulePurview() override;
122+
void AddedManglingNumber(const Decl *D, unsigned) override;
123+
void AddedStaticLocalNumbers(const Decl *D, unsigned) override;
124+
void AddedAnonymousNamespace(const TranslationUnitDecl *,
125+
NamespaceDecl *AnonNamespace) override;
118126

119127
private:
120128
std::vector<ASTMutationListener*> Listeners;
@@ -238,6 +246,27 @@ void MultiplexASTMutationListener::AddedAttributeToRecord(
238246
L->AddedAttributeToRecord(Attr, Record);
239247
}
240248

249+
void MultiplexASTMutationListener::EnteringModulePurview() {
250+
for (auto *L : Listeners)
251+
L->EnteringModulePurview();
252+
}
253+
254+
void MultiplexASTMutationListener::AddedManglingNumber(const Decl *D,
255+
unsigned Number) {
256+
for (auto *L : Listeners)
257+
L->AddedManglingNumber(D, Number);
258+
}
259+
void MultiplexASTMutationListener::AddedStaticLocalNumbers(const Decl *D,
260+
unsigned Number) {
261+
for (auto *L : Listeners)
262+
L->AddedStaticLocalNumbers(D, Number);
263+
}
264+
void MultiplexASTMutationListener::AddedAnonymousNamespace(
265+
const TranslationUnitDecl *TU, NamespaceDecl *AnonNamespace) {
266+
for (auto *L : Listeners)
267+
L->AddedAnonymousNamespace(TU, AnonNamespace);
268+
}
269+
241270
} // end namespace clang
242271

243272
MultiplexConsumer::MultiplexConsumer(

clang/lib/Sema/SemaModule.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "clang/AST/ASTConsumer.h"
15+
#include "clang/AST/ASTMutationListener.h"
1516
#include "clang/Lex/HeaderSearch.h"
1617
#include "clang/Lex/Preprocessor.h"
1718
#include "clang/Sema/SemaInternal.h"
@@ -475,6 +476,9 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
475476

476477
getASTContext().setCurrentNamedModule(Mod);
477478

479+
if (auto *Listener = getASTMutationListener())
480+
Listener->EnteringModulePurview();
481+
478482
// We already potentially made an implicit import (in the case of a module
479483
// implementation unit importing its interface). Make this module visible
480484
// and return the import decl to be added to the current TU.

clang/lib/Serialization/ASTWriter.cpp

+43-21
Original file line numberDiff line numberDiff line change
@@ -5026,27 +5026,6 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
50265026
GetDeclRef(D);
50275027
}
50285028

5029-
// If the translation unit has an anonymous namespace, and we don't already
5030-
// have an update block for it, write it as an update block.
5031-
// FIXME: Why do we not do this if there's already an update block?
5032-
if (NamespaceDecl *NS = TU->getAnonymousNamespace()) {
5033-
ASTWriter::UpdateRecord &Record = DeclUpdates[TU];
5034-
if (Record.empty())
5035-
Record.push_back(DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, NS));
5036-
}
5037-
5038-
// Add update records for all mangling numbers and static local numbers.
5039-
// These aren't really update records, but this is a convenient way of
5040-
// tagging this rare extra data onto the declarations.
5041-
for (const auto &Number : Context.MangleNumbers)
5042-
if (!Number.first->isFromASTFile())
5043-
DeclUpdates[Number.first].push_back(DeclUpdate(UPD_MANGLING_NUMBER,
5044-
Number.second));
5045-
for (const auto &Number : Context.StaticLocalNumbers)
5046-
if (!Number.first->isFromASTFile())
5047-
DeclUpdates[Number.first].push_back(DeclUpdate(UPD_STATIC_LOCAL_NUMBER,
5048-
Number.second));
5049-
50505029
// Make sure visible decls, added to DeclContexts previously loaded from
50515030
// an AST file, are registered for serialization. Likewise for template
50525031
// specializations added to imported templates.
@@ -5315,6 +5294,41 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
53155294
return backpatchSignature();
53165295
}
53175296

5297+
void ASTWriter::EnteringModulePurview() {
5298+
// In C++20 named modules, all entities before entering the module purview
5299+
// lives in the GMF.
5300+
if (GeneratingReducedBMI)
5301+
DeclUpdatesFromGMF.swap(DeclUpdates);
5302+
}
5303+
5304+
// Add update records for all mangling numbers and static local numbers.
5305+
// These aren't really update records, but this is a convenient way of
5306+
// tagging this rare extra data onto the declarations.
5307+
void ASTWriter::AddedManglingNumber(const Decl *D, unsigned Number) {
5308+
if (D->isFromASTFile())
5309+
return;
5310+
5311+
DeclUpdates[D].push_back(DeclUpdate(UPD_MANGLING_NUMBER, Number));
5312+
}
5313+
void ASTWriter::AddedStaticLocalNumbers(const Decl *D, unsigned Number) {
5314+
if (D->isFromASTFile())
5315+
return;
5316+
5317+
DeclUpdates[D].push_back(DeclUpdate(UPD_STATIC_LOCAL_NUMBER, Number));
5318+
}
5319+
5320+
void ASTWriter::AddedAnonymousNamespace(const TranslationUnitDecl *TU,
5321+
NamespaceDecl *AnonNamespace) {
5322+
// If the translation unit has an anonymous namespace, and we don't already
5323+
// have an update block for it, write it as an update block.
5324+
// FIXME: Why do we not do this if there's already an update block?
5325+
if (NamespaceDecl *NS = TU->getAnonymousNamespace()) {
5326+
ASTWriter::UpdateRecord &Record = DeclUpdates[TU];
5327+
if (Record.empty())
5328+
Record.push_back(DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, NS));
5329+
}
5330+
}
5331+
53185332
void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
53195333
// Keep writing types, declarations, and declaration update records
53205334
// until we've emitted all of them.
@@ -5860,6 +5874,14 @@ DeclID ASTWriter::GetDeclRef(const Decl *D) {
58605874
return 0;
58615875
}
58625876

5877+
// If the DeclUpdate from the GMF gets touched, emit it.
5878+
if (auto *Iter = DeclUpdatesFromGMF.find(D);
5879+
Iter != DeclUpdatesFromGMF.end()) {
5880+
for (DeclUpdate &Update : Iter->second)
5881+
DeclUpdates[D].push_back(Update);
5882+
DeclUpdatesFromGMF.erase(Iter);
5883+
}
5884+
58635885
// If D comes from an AST file, its declaration ID is already known and
58645886
// fixed.
58655887
if (D->isFromASTFile())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Test that we won't write additional information into the Reduced BMI if the
2+
// 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/M.cppm -emit-reduced-module-interface -o %t/M.pcm
9+
// RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-reduced-module-interface -o %t/A.pcm \
10+
// RUN: -fmodule-file=M=%t/M.pcm
11+
// RUN: llvm-bcanalyzer --dump --disable-histogram --show-binary-blobs %t/A.pcm > %t/A.dump
12+
// RUN: cat %t/A.dump | FileCheck %t/A.cppm
13+
//
14+
// RUN: %clang_cc1 -std=c++20 %t/A1.cppm -emit-reduced-module-interface -o %t/A1.pcm \
15+
// RUN: -fmodule-file=M=%t/M.pcm
16+
// RUN: llvm-bcanalyzer --dump --disable-histogram --show-binary-blobs %t/A1.pcm > %t/A1.dump
17+
// RUN: cat %t/A1.dump | FileCheck %t/A1.cppm
18+
19+
//--- foo.h
20+
namespace ns {
21+
template <class C>
22+
class A {
23+
24+
};
25+
26+
extern template class A<short>;
27+
28+
inline A<int> a() { return A<int>(); }
29+
template <class T>
30+
A<T> _av_ = A<T>();
31+
32+
auto _av_1 = _av_<int>;
33+
auto _av_2 = _av_<double>;
34+
35+
template <>
36+
class A<void> {
37+
38+
};
39+
40+
void func(A<int>, ...) {
41+
42+
}
43+
44+
}
45+
46+
struct S {
47+
union {
48+
unsigned int V;
49+
struct {
50+
int v1;
51+
int v2;
52+
ns::A<int> a1;
53+
} WESQ;
54+
};
55+
56+
union {
57+
double d;
58+
struct {
59+
int v1;
60+
unsigned v2;
61+
ns::A<unsigned> a1;
62+
} Another;
63+
};
64+
};
65+
66+
//--- M.cppm
67+
module;
68+
#include "foo.h"
69+
export module M;
70+
export namespace nv {
71+
using ns::A;
72+
using ns::a;
73+
using ns::_av_;
74+
75+
using ns::func;
76+
}
77+
using ::S;
78+
79+
//--- A.cppm
80+
module;
81+
#include "foo.h"
82+
export module A;
83+
import M;
84+
85+
// CHECK-NOT: <DECL_CXX_RECORD
86+
// CHECK-NOT: <DECL_UPDATE_OFFSETS
87+
88+
//--- A1.cppm
89+
module;
90+
import M;
91+
#include "foo.h"
92+
export module A;
93+
94+
// CHECK-NOT: <DECL_CXX_RECORD
95+
// CHECK-NOT: <DECL_UPDATE_OFFSETS
96+

0 commit comments

Comments
 (0)