Skip to content

[Serialization] Support loading template specializations lazily #119333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
}

void anchor() override;

protected:
template <typename EntryType> struct SpecEntryTraits {
using DeclType = EntryType;
Expand Down Expand Up @@ -775,13 +776,22 @@ class RedeclarableTemplateDecl : public TemplateDecl,
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
}

void loadLazySpecializationsImpl() const;
void loadLazySpecializationsImpl(bool OnlyPartial = false) const;

bool loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
TemplateParameterList *TPL = nullptr) const;

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

template <class EntryType, typename... ProfileArguments>
typename SpecEntryTraits<EntryType>::DeclType *
findSpecializationLocally(llvm::FoldingSetVector<EntryType> &Specs,
void *&InsertPos,
ProfileArguments &&...ProfileArgs);

template <class Derived, class EntryType>
void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
EntryType *Entry, void *InsertPos);
Expand All @@ -796,13 +806,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// was explicitly specialized.
llvm::PointerIntPair<RedeclarableTemplateDecl *, 1, bool>
InstantiatedFromMember;

/// If non-null, points to an array of specializations (including
/// partial specializations) known only by their external declaration IDs.
///
/// The first value in the array is the number of specializations/partial
/// specializations that follow.
GlobalDeclID *LazySpecializations = nullptr;
};

/// Pointer to the common data shared by all declarations of this
Expand Down Expand Up @@ -2283,7 +2286,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
friend class TemplateDeclInstantiator;

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

/// Get the underlying class declarations of the template.
CXXRecordDecl *getTemplatedDecl() const {
Expand Down Expand Up @@ -3033,7 +3036,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
friend class ASTDeclWriter;

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

/// Get the underlying variable declarations of the template.
VarDecl *getTemplatedDecl() const {
Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/AST/ExternalASTSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,21 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
virtual bool
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);

/// Load all the external specializations for the Decl \param D if \param
/// OnlyPartial is false. Otherwise, load all the external **partial**
/// specializations for the \param D.
///
/// Return true if any new specializations get loaded. Return false otherwise.
virtual bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial);

/// Load all the specializations for the Decl \param D with the same template
/// args specified by \param TemplateArgs.
///
/// Return true if any new specializations get loaded. Return false otherwise.
virtual bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs);

/// Ensures that the table of all visible declarations inside this
/// context is up to date.
///
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/MultiplexExternalSemaSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;

bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;

bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) override;

/// Ensures that the table of all visible declarations inside this
/// context is up to date.
void completeVisibleDeclsMap(const DeclContext *DC) override;
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,13 @@ enum ASTRecordTypes {
/// Record code for Sema's vector of functions/blocks with effects to
/// be verified.
DECLS_WITH_EFFECTS_TO_VERIFY = 72,

/// Record code for updated specialization
UPDATE_SPECIALIZATION = 73,

CXX_ADDED_TEMPLATE_SPECIALIZATION = 74,

CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION = 75,
};

/// Record types used within a source manager block.
Expand Down Expand Up @@ -1502,6 +1509,12 @@ enum DeclCode {
/// An ImplicitConceptSpecializationDecl record.
DECL_IMPLICIT_CONCEPT_SPECIALIZATION,

// A decls specilization record.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note specialization is misspelled in this comment and the one below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

DECL_SPECIALIZATIONS,

// A decls specilization record.
DECL_PARTIAL_SPECIALIZATIONS,

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DECL_LAST also needs to be updated her.e

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this! Done in 366dadd

DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION
};

Expand Down
48 changes: 45 additions & 3 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ class ASTIdentifierLookupTrait;
/// The on-disk hash table(s) used for DeclContext name lookup.
struct DeclContextLookupTable;

/// The on-disk hash table(s) used for specialization decls.
struct LazySpecializationInfoLookupTable;

} // namespace reader

} // namespace serialization
Expand Down Expand Up @@ -632,20 +635,40 @@ class ASTReader
llvm::DenseMap<const DeclContext *,
serialization::reader::DeclContextLookupTable> Lookups;

using SpecLookupTableTy =
llvm::DenseMap<const Decl *,
serialization::reader::LazySpecializationInfoLookupTable>;
/// Map from decls to specialized decls.
SpecLookupTableTy SpecializationsLookups;
/// Split partial specialization from specialization to speed up lookups.
SpecLookupTableTy PartialSpecializationsLookups;

bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
const Decl *D);
bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs);

// Updates for visible decls can occur for other contexts than just the
// TU, and when we read those update records, the actual context may not
// be available yet, so have this pending map using the ID as a key. It
// will be realized when the context is actually loaded.
struct PendingVisibleUpdate {
// will be realized when the data is actually loaded.
struct UpdateData {
ModuleFile *Mod;
const unsigned char *Data;
};
using DeclContextVisibleUpdates = SmallVector<PendingVisibleUpdate, 1>;
using DeclContextVisibleUpdates = SmallVector<UpdateData, 1>;

/// Updates to the visible declarations of declaration contexts that
/// haven't been loaded yet.
llvm::DenseMap<GlobalDeclID, DeclContextVisibleUpdates> PendingVisibleUpdates;

using SpecializationsUpdate = SmallVector<UpdateData, 1>;
using SpecializationsUpdateMap =
llvm::DenseMap<GlobalDeclID, SpecializationsUpdate>;
SpecializationsUpdateMap PendingSpecializationsUpdates;
SpecializationsUpdateMap PendingPartialSpecializationsUpdates;

/// The set of C++ or Objective-C classes that have forward
/// declarations that have not yet been linked to their definitions.
llvm::SmallPtrSet<Decl *, 4> PendingDefinitions;
Expand Down Expand Up @@ -678,6 +701,11 @@ class ASTReader
llvm::BitstreamCursor &Cursor,
uint64_t Offset, GlobalDeclID ID);

bool ReadSpecializations(ModuleFile &M, llvm::BitstreamCursor &Cursor,
uint64_t Offset, Decl *D, bool IsPartial);
void AddSpecializations(const Decl *D, const unsigned char *Data,
ModuleFile &M, bool IsPartial);

/// A vector containing identifiers that have already been
/// loaded.
///
Expand Down Expand Up @@ -1419,6 +1447,14 @@ class ASTReader
const serialization::reader::DeclContextLookupTable *
getLoadedLookupTables(DeclContext *Primary) const;

/// Get the loaded specializations lookup tables for \p D,
/// if any.
serialization::reader::LazySpecializationInfoLookupTable *
getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial);

/// If we have any unloaded specialization for \p D
bool haveUnloadedSpecializations(const Decl *D) const;

private:
struct ImportedModule {
ModuleFile *Mod;
Expand Down Expand Up @@ -2076,6 +2112,12 @@ class ASTReader
unsigned BlockID,
uint64_t *StartOfBlockOffset = nullptr);

bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;

bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) override;

/// Finds all the visible declarations with a given name.
/// The current implementation of this method just loads the entire
/// lookup table as unmaterialized references.
Expand Down
17 changes: 17 additions & 0 deletions clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,13 @@ class ASTWriter : public ASTDeserializationListener,
/// Only meaningful for reduced BMI.
DeclUpdateMap DeclUpdatesFromGMF;

/// Mapping from decl templates and its new specialization in the
/// current TU.
using SpecializationUpdateMap =
llvm::MapVector<const NamedDecl *, SmallVector<const Decl *>>;
SpecializationUpdateMap SpecializationsUpdates;
SpecializationUpdateMap PartialSpecializationsUpdates;

using FirstLatestDeclMap = llvm::DenseMap<Decl *, Decl *>;

/// Map of first declarations from a chained PCH that point to the
Expand Down Expand Up @@ -575,6 +582,12 @@ class ASTWriter : public ASTDeserializationListener,

bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);

void GenerateSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial);
uint64_t WriteSpecializationInfoLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
bool IsPartial);
void GenerateNameLookupTable(ASTContext &Context, const DeclContext *DC,
llvm::SmallVectorImpl<char> &LookupTable);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context,
Expand All @@ -590,6 +603,7 @@ class ASTWriter : public ASTDeserializationListener,
void WriteDeclAndTypes(ASTContext &Context);
void PrepareWritingSpecialDecls(Sema &SemaRef);
void WriteSpecialDeclRecords(Sema &SemaRef);
void WriteSpecializationsUpdates(bool IsPartial);
void WriteDeclUpdatesBlocks(ASTContext &Context,
RecordDataImpl &OffsetsRecord);
void WriteDeclContextVisibleUpdate(ASTContext &Context,
Expand Down Expand Up @@ -619,6 +633,9 @@ class ASTWriter : public ASTDeserializationListener,
unsigned DeclEnumAbbrev = 0;
unsigned DeclObjCIvarAbbrev = 0;
unsigned DeclCXXMethodAbbrev = 0;
unsigned DeclSpecializationsAbbrev = 0;
unsigned DeclPartialSpecializationsAbbrev = 0;

unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0;
unsigned DeclTemplateCXXMethodAbbrev = 0;
unsigned DeclMemberSpecializedCXXMethodAbbrev = 0;
Expand Down
Loading
Loading