Skip to content

Commit 268ef3d

Browse files
ChuanqiXu9hahnjo
authored andcommitted
UPSTREAM: [Serialization] Support loading template specializations lazily
Reland llvm#83237 --- (Original comments) Currently all the specializations of a template (including instantiation, specialization and partial specializations) will be loaded at once if we want to instantiate another instance for the template, or find instantiation for the template, or just want to complete the redecl chain. This means basically we need to load every specializations for the template once the template declaration got loaded. This is bad since when we load a specialization, we need to load all of its template arguments. Then we have to deserialize a lot of unnecessary declarations. For example, ``` // M.cppm export module M; export template <class T> class A {}; export class ShouldNotBeLoaded {}; export class Temp { A<ShouldNotBeLoaded> AS; }; // use.cpp import M; A<int> a; ``` We have a specialization ` A<ShouldNotBeLoaded>` in `M.cppm` and we instantiate the template `A` in `use.cpp`. Then we will deserialize `ShouldNotBeLoaded` surprisingly when compiling `use.cpp`. And this patch tries to avoid that. Given that the templates are heavily used in C++, this is a pain point for the performance. This patch adds MultiOnDiskHashTable for specializations in the ASTReader. Then we will only deserialize the specializations with the same template arguments. We made that by using ODRHash for the template arguments as the key of the hash table. To review this patch, I think `ASTReaderDecl::AddLazySpecializations` may be a good entry point. (cherry picked from commit 20e9049)
1 parent 6fc1bf1 commit 268ef3d

29 files changed

+1641
-175
lines changed

clang/include/clang/AST/DeclTemplate.h

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
749749
}
750750

751751
void anchor() override;
752+
752753
protected:
753754
template <typename EntryType> struct SpecEntryTraits {
754755
using DeclType = EntryType;
@@ -789,13 +790,22 @@ class RedeclarableTemplateDecl : public TemplateDecl,
789790
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
790791
}
791792

792-
void loadLazySpecializationsImpl() const;
793+
void loadLazySpecializationsImpl(bool OnlyPartial = false) const;
794+
795+
bool loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
796+
TemplateParameterList *TPL = nullptr) const;
793797

794798
template <class EntryType, typename ...ProfileArguments>
795799
typename SpecEntryTraits<EntryType>::DeclType*
796800
findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
797801
void *&InsertPos, ProfileArguments &&...ProfileArgs);
798802

803+
template <class EntryType, typename... ProfileArguments>
804+
typename SpecEntryTraits<EntryType>::DeclType *
805+
findSpecializationLocally(llvm::FoldingSetVector<EntryType> &Specs,
806+
void *&InsertPos,
807+
ProfileArguments &&...ProfileArgs);
808+
799809
template <class Derived, class EntryType>
800810
void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
801811
EntryType *Entry, void *InsertPos);
@@ -811,13 +821,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
811821
llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
812822
InstantiatedFromMember;
813823

814-
/// If non-null, points to an array of specializations (including
815-
/// partial specializations) known only by their external declaration IDs.
816-
///
817-
/// The first value in the array is the number of specializations/partial
818-
/// specializations that follow.
819-
uint32_t *LazySpecializations = nullptr;
820-
821824
/// The set of "injected" template arguments used within this
822825
/// template.
823826
///
@@ -2301,7 +2304,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
23012304
friend class TemplateDeclInstantiator;
23022305

23032306
/// Load any lazily-loaded specializations from the external source.
2304-
void LoadLazySpecializations() const;
2307+
void LoadLazySpecializations(bool OnlyPartial = false) const;
23052308

23062309
/// Get the underlying class declarations of the template.
23072310
CXXRecordDecl *getTemplatedDecl() const {
@@ -3086,7 +3089,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
30863089
friend class ASTDeclWriter;
30873090

30883091
/// Load any lazily-loaded specializations from the external source.
3089-
void LoadLazySpecializations() const;
3092+
void LoadLazySpecializations(bool OnlyPartial = false) const;
30903093

30913094
/// Get the underlying variable declarations of the template.
30923095
VarDecl *getTemplatedDecl() const {

clang/include/clang/AST/ExternalASTSource.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,21 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
150150
virtual bool
151151
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
152152

153+
/// Load all the external specializations for the Decl \param D if \param
154+
/// OnlyPartial is false. Otherwise, load all the external **partial**
155+
/// specializations for the \param D.
156+
///
157+
/// Return true if any new specializations get loaded. Return false otherwise.
158+
virtual bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial);
159+
160+
/// Load all the specializations for the Decl \param D with the same template
161+
/// args specified by \param TemplateArgs.
162+
///
163+
/// Return true if any new specializations get loaded. Return false otherwise.
164+
virtual bool
165+
LoadExternalSpecializations(const Decl *D,
166+
ArrayRef<TemplateArgument> TemplateArgs);
167+
153168
/// Ensures that the table of all visible declarations inside this
154169
/// context is up to date.
155170
///

clang/include/clang/Sema/MultiplexExternalSemaSource.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
9797
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
9898
DeclarationName Name) override;
9999

100+
bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
101+
102+
bool
103+
LoadExternalSpecializations(const Decl *D,
104+
ArrayRef<TemplateArgument> TemplateArgs) override;
105+
100106
/// Ensures that the table of all visible declarations inside this
101107
/// context is up to date.
102108
void completeVisibleDeclsMap(const DeclContext *DC) override;

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,13 @@ enum ASTRecordTypes {
695695
/// Record code for an unterminated \#pragma clang assume_nonnull begin
696696
/// recorded in a preamble.
697697
PP_ASSUME_NONNULL_LOC = 67,
698+
699+
/// Record code for updated specialization
700+
UPDATE_SPECIALIZATION = 73,
701+
702+
CXX_ADDED_TEMPLATE_SPECIALIZATION = 74,
703+
704+
CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION = 75,
698705
};
699706

700707
/// Record types used within a source manager block.
@@ -1523,6 +1530,12 @@ enum DeclCode {
15231530
/// An ImplicitConceptSpecializationDecl record.
15241531
DECL_IMPLICIT_CONCEPT_SPECIALIZATION,
15251532

1533+
// A decls specilization record.
1534+
DECL_SPECIALIZATIONS,
1535+
1536+
// A decls specilization record.
1537+
DECL_PARTIAL_SPECIALIZATIONS,
1538+
15261539
DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION
15271540
};
15281541

clang/include/clang/Serialization/ASTReader.h

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ class ASTIdentifierLookupTrait;
340340
/// The on-disk hash table(s) used for DeclContext name lookup.
341341
struct DeclContextLookupTable;
342342

343+
/// The on-disk hash table(s) used for specialization decls.
344+
struct LazySpecializationInfoLookupTable;
345+
343346
} // namespace reader
344347

345348
} // namespace serialization
@@ -603,21 +606,41 @@ class ASTReader
603606
llvm::DenseMap<const DeclContext *,
604607
serialization::reader::DeclContextLookupTable> Lookups;
605608

609+
using SpecLookupTableTy =
610+
llvm::DenseMap<const Decl *,
611+
serialization::reader::LazySpecializationInfoLookupTable>;
612+
/// Map from decls to specialized decls.
613+
SpecLookupTableTy SpecializationsLookups;
614+
/// Split partial specialization from specialization to speed up lookups.
615+
SpecLookupTableTy PartialSpecializationsLookups;
616+
617+
bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
618+
const Decl *D);
619+
bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
620+
const Decl *D,
621+
ArrayRef<TemplateArgument> TemplateArgs);
622+
606623
// Updates for visible decls can occur for other contexts than just the
607624
// TU, and when we read those update records, the actual context may not
608625
// be available yet, so have this pending map using the ID as a key. It
609-
// will be realized when the context is actually loaded.
610-
struct PendingVisibleUpdate {
626+
// will be realized when the data is actually loaded.
627+
struct UpdateData {
611628
ModuleFile *Mod;
612629
const unsigned char *Data;
613630
};
614-
using DeclContextVisibleUpdates = SmallVector<PendingVisibleUpdate, 1>;
631+
using DeclContextVisibleUpdates = SmallVector<UpdateData, 1>;
615632

616633
/// Updates to the visible declarations of declaration contexts that
617634
/// haven't been loaded yet.
618635
llvm::DenseMap<serialization::DeclID, DeclContextVisibleUpdates>
619636
PendingVisibleUpdates;
620637

638+
using SpecializationsUpdate = SmallVector<UpdateData, 1>;
639+
using SpecializationsUpdateMap =
640+
llvm::DenseMap<serialization::GlobalDeclID, SpecializationsUpdate>;
641+
SpecializationsUpdateMap PendingSpecializationsUpdates;
642+
SpecializationsUpdateMap PendingPartialSpecializationsUpdates;
643+
621644
/// The set of C++ or Objective-C classes that have forward
622645
/// declarations that have not yet been linked to their definitions.
623646
llvm::SmallPtrSet<Decl *, 4> PendingDefinitions;
@@ -644,6 +667,11 @@ class ASTReader
644667
llvm::BitstreamCursor &Cursor,
645668
uint64_t Offset, serialization::DeclID ID);
646669

670+
bool ReadSpecializations(ModuleFile &M, llvm::BitstreamCursor &Cursor,
671+
uint64_t Offset, Decl *D, bool IsPartial);
672+
void AddSpecializations(const Decl *D, const unsigned char *Data,
673+
ModuleFile &M, bool IsPartial);
674+
647675
/// A vector containing identifiers that have already been
648676
/// loaded.
649677
///
@@ -1347,6 +1375,14 @@ class ASTReader
13471375
const serialization::reader::DeclContextLookupTable *
13481376
getLoadedLookupTables(DeclContext *Primary) const;
13491377

1378+
/// Get the loaded specializations lookup tables for \p D,
1379+
/// if any.
1380+
serialization::reader::LazySpecializationInfoLookupTable *
1381+
getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial);
1382+
1383+
/// If we have any unloaded specialization for \p D
1384+
bool haveUnloadedSpecializations(const Decl *D) const;
1385+
13501386
private:
13511387
struct ImportedModule {
13521388
ModuleFile *Mod;
@@ -1980,6 +2016,12 @@ class ASTReader
19802016
unsigned BlockID,
19812017
uint64_t *StartOfBlockOffset = nullptr);
19822018

2019+
bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
2020+
2021+
bool
2022+
LoadExternalSpecializations(const Decl *D,
2023+
ArrayRef<TemplateArgument> TemplateArgs) override;
2024+
19832025
/// Finds all the visible declarations with a given name.
19842026
/// The current implementation of this method just loads the entire
19852027
/// lookup table as unmaterialized references.

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,13 @@ class ASTWriter : public ASTDeserializationListener,
385385
/// record containing modifications to them.
386386
DeclUpdateMap DeclUpdates;
387387

388+
/// Mapping from decl templates and its new specialization in the
389+
/// current TU.
390+
using SpecializationUpdateMap =
391+
llvm::MapVector<const NamedDecl *, SmallVector<const Decl *>>;
392+
SpecializationUpdateMap SpecializationsUpdates;
393+
SpecializationUpdateMap PartialSpecializationsUpdates;
394+
388395
using FirstLatestDeclMap = llvm::DenseMap<Decl *, Decl *>;
389396

390397
/// Map of first declarations from a chained PCH that point to the
@@ -527,6 +534,12 @@ class ASTWriter : public ASTDeserializationListener,
527534
bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);
528535
bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext *DC);
529536

537+
void GenerateSpecializationInfoLookupTable(
538+
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
539+
llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial);
540+
uint64_t WriteSpecializationInfoLookupTable(
541+
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
542+
bool IsPartial);
530543
void GenerateNameLookupTable(const DeclContext *DC,
531544
llvm::SmallVectorImpl<char> &LookupTable);
532545
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
@@ -538,6 +551,7 @@ class ASTWriter : public ASTDeserializationListener,
538551
void WriteReferencedSelectorsPool(Sema &SemaRef);
539552
void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver,
540553
bool IsModule);
554+
void WriteSpecializationsUpdates(bool IsPartial);
541555
void WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord);
542556
void WriteDeclContextVisibleUpdate(const DeclContext *DC);
543557
void WriteFPPragmaOptions(const FPOptionsOverride &Opts);
@@ -564,6 +578,9 @@ class ASTWriter : public ASTDeserializationListener,
564578
unsigned DeclEnumAbbrev = 0;
565579
unsigned DeclObjCIvarAbbrev = 0;
566580
unsigned DeclCXXMethodAbbrev = 0;
581+
unsigned DeclSpecializationsAbbrev = 0;
582+
unsigned DeclPartialSpecializationsAbbrev = 0;
583+
567584
unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0;
568585
unsigned DeclTemplateCXXMethodAbbrev = 0;
569586
unsigned DeclMemberSpecializedCXXMethodAbbrev = 0;

0 commit comments

Comments
 (0)