Skip to content

Commit 2be2052

Browse files
committed
[C++20][Modules] Improve namespace handling performance for modules.
1 parent d8d87b5 commit 2be2052

File tree

2 files changed

+73
-16
lines changed

2 files changed

+73
-16
lines changed

clang/lib/Serialization/ASTReader.cpp

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,25 @@ namespace {
555555

556556
using MacroDefinitionsMap =
557557
llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/>>;
558-
using DeclsMap = llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8>>;
558+
559+
class DeclsSet {
560+
SmallVector<NamedDecl *, 64> Decls;
561+
llvm::SmallPtrSet<NamedDecl *, 8> Found;
562+
563+
public:
564+
operator ArrayRef<NamedDecl *>() const { return Decls; }
565+
566+
bool empty() const { return Decls.empty(); }
567+
568+
bool insert(NamedDecl *ND) {
569+
auto [_, Inserted] = Found.insert(ND);
570+
if (Inserted)
571+
Decls.push_back(ND);
572+
return Inserted;
573+
}
574+
};
575+
576+
using DeclsMap = llvm::DenseMap<DeclarationName, DeclsSet>;
559577

560578
} // namespace
561579

@@ -8702,14 +8720,23 @@ bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
87028720
return false;
87038721

87048722
// Load the list of declarations.
8705-
SmallVector<NamedDecl *, 64> Decls;
8706-
llvm::SmallPtrSet<NamedDecl *, 8> Found;
8723+
DeclsSet DS;
87078724

87088725
auto Find = [&, this](auto &&Table, auto &&Key) {
87098726
for (GlobalDeclID ID : Table.find(Key)) {
87108727
NamedDecl *ND = cast<NamedDecl>(GetDecl(ID));
8711-
if (ND->getDeclName() == Name && Found.insert(ND).second)
8712-
Decls.push_back(ND);
8728+
if (ND->getDeclName() != Name)
8729+
continue;
8730+
// Special case for namespaces: There can be a lot of redeclarations of
8731+
// some namespaces, and we import a "key declaration" per imported module.
8732+
// Since all declarations of a namespace are essentially interchangeable,
8733+
// we can optimize namespace look-up by only storing the key declaration
8734+
// of the current TU, rather than storing N key declarations where N is
8735+
// the # of imported modules that declare that namespace.
8736+
// TODO: Try to generalize this optimization to other redeclarable decls.
8737+
if (isa<NamespaceDecl>(ND))
8738+
ND = cast<NamedDecl>(getKeyDeclaration(ND));
8739+
DS.insert(ND);
87138740
}
87148741
};
87158742

@@ -8744,8 +8771,8 @@ bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
87448771
Find(It->second.Table, Name);
87458772
}
87468773

8747-
SetExternalVisibleDeclsForName(DC, Name, Decls);
8748-
return !Decls.empty();
8774+
SetExternalVisibleDeclsForName(DC, Name, DS);
8775+
return !DS.empty();
87498776
}
87508777

87518778
void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
@@ -8763,7 +8790,16 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
87638790

87648791
for (GlobalDeclID ID : It->second.Table.findAll()) {
87658792
NamedDecl *ND = cast<NamedDecl>(GetDecl(ID));
8766-
Decls[ND->getDeclName()].push_back(ND);
8793+
// Special case for namespaces: There can be a lot of redeclarations of
8794+
// some namespaces, and we import a "key declaration" per imported module.
8795+
// Since all declarations of a namespace are essentially interchangeable,
8796+
// we can optimize namespace look-up by only storing the key declaration
8797+
// of the current TU, rather than storing N key declarations where N is
8798+
// the # of imported modules that declare that namespace.
8799+
// TODO: Try to generalize this optimization to other redeclarable decls.
8800+
if (isa<NamespaceDecl>(ND))
8801+
ND = cast<NamedDecl>(getKeyDeclaration(ND));
8802+
Decls[ND->getDeclName()].insert(ND);
87678803
}
87688804

87698805
// FIXME: Why a PCH test is failing if we remove the iterator after findAll?
@@ -8773,9 +8809,9 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
87738809
findAll(ModuleLocalLookups, NumModuleLocalVisibleDeclContexts);
87748810
findAll(TULocalLookups, NumTULocalVisibleDeclContexts);
87758811

8776-
for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
8777-
SetExternalVisibleDeclsForName(DC, I->first, I->second);
8778-
}
8812+
for (auto &[Name, DS] : Decls)
8813+
SetExternalVisibleDeclsForName(DC, Name, DS);
8814+
87798815
const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false);
87808816
}
87818817

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4396,20 +4396,20 @@ class ASTDeclContextNameLookupTrait
43964396

43974397
template <typename Coll> data_type getData(const Coll &Decls) {
43984398
unsigned Start = DeclIDs.size();
4399-
for (NamedDecl *D : Decls) {
4399+
auto AddDecl = [this](NamedDecl *D) {
44004400
NamedDecl *DeclForLocalLookup =
44014401
getDeclForLocalLookup(Writer.getLangOpts(), D);
44024402

44034403
if (Writer.getDoneWritingDeclsAndTypes() &&
44044404
!Writer.wasDeclEmitted(DeclForLocalLookup))
4405-
continue;
4405+
return;
44064406

44074407
// Try to avoid writing internal decls to reduced BMI.
44084408
// See comments in ASTWriter::WriteDeclContextLexicalBlock for details.
44094409
if (Writer.isGeneratingReducedBMI() &&
44104410
!DeclForLocalLookup->isFromExplicitGlobalModule() &&
44114411
IsInternalDeclFromFileContext(DeclForLocalLookup))
4412-
continue;
4412+
return;
44134413

44144414
auto ID = Writer.GetDeclRef(DeclForLocalLookup);
44154415

@@ -4423,7 +4423,7 @@ class ASTDeclContextNameLookupTrait
44234423
ModuleLocalDeclsMap.insert({Key, DeclIDsTy{ID}});
44244424
else
44254425
Iter->second.push_back(ID);
4426-
continue;
4426+
return;
44274427
}
44284428
break;
44294429
case LookupVisibility::TULocal: {
@@ -4432,14 +4432,35 @@ class ASTDeclContextNameLookupTrait
44324432
TULocalDeclsMap.insert({D->getDeclName(), DeclIDsTy{ID}});
44334433
else
44344434
Iter->second.push_back(ID);
4435-
continue;
4435+
return;
44364436
}
44374437
case LookupVisibility::GenerallyVisibile:
44384438
// Generally visible decls go into the general lookup table.
44394439
break;
44404440
}
44414441

44424442
DeclIDs.push_back(ID);
4443+
};
4444+
for (NamedDecl *D : Decls) {
4445+
if (isa<NamespaceDecl>(D) && D->isFromASTFile()) {
4446+
// In ASTReader, we stored only the key declaration of a namespace decl
4447+
// for this TU rather than storing all of the key declarations from each
4448+
// imported module. If we have an external namespace decl, this is that
4449+
// key declaration and we need to re-expand it to write out all of the
4450+
// key declarations from each imported module again.
4451+
//
4452+
// See comment 'ASTReader::FindExternalVisibleDeclsByName' for details.
4453+
ASTReader *Chain = Writer.getChain();
4454+
assert(Chain && "An external namespace decl without an ASTReader");
4455+
assert(D == Chain->getKeyDeclaration(D) &&
4456+
"An external namespace decl that is not "
4457+
"the key declaration of this TU");
4458+
Chain->forEachImportedKeyDecl(D, [&AddDecl](const Decl *D) {
4459+
AddDecl(cast<NamedDecl>(const_cast<Decl *>(D)));
4460+
});
4461+
} else {
4462+
AddDecl(D);
4463+
}
44434464
}
44444465
return std::make_pair(Start, DeclIDs.size());
44454466
}

0 commit comments

Comments
 (0)