Skip to content

[Serialization] Load Specializations Lazily #76774

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

Closed
wants to merge 4 commits into from
Closed
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
40 changes: 30 additions & 10 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -525,8 +525,11 @@ class FunctionTemplateSpecializationInfo final
return Function.getInt();
}

void loadExternalRedecls();

public:
friend TrailingObjects;
friend class ASTReader;

static FunctionTemplateSpecializationInfo *
Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
Expand Down Expand Up @@ -789,13 +792,20 @@ class RedeclarableTemplateDecl : public TemplateDecl,
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
}

void loadLazySpecializationsImpl() const;
void loadExternalSpecializations() 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 *
findLocalSpecialization(llvm::FoldingSetVector<EntryType> &Specs,
void *&InsertPos, ProfileArguments &&... ProfileArgs);

bool loadLazySpecializationsWithArgs(ArrayRef<TemplateArgument> TemplateArgs);

template <class Derived, class EntryType>
void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
EntryType *Entry, void *InsertPos);
Expand All @@ -814,9 +824,13 @@ class RedeclarableTemplateDecl : public TemplateDecl,
/// If non-null, points to an array of specializations (including
/// partial specializations) known only by their external declaration IDs.
///
/// These specializations needs to be loaded at once in
/// loadExternalSpecializations to complete the redecl chain or be preparing
/// for template resolution.
///
/// The first value in the array is the number of specializations/partial
/// specializations that follow.
uint32_t *LazySpecializations = nullptr;
uint32_t *ExternalSpecializations = nullptr;

/// The set of "injected" template arguments used within this
/// template.
Expand Down Expand Up @@ -850,6 +864,8 @@ class RedeclarableTemplateDecl : public TemplateDecl,
friend class ASTDeclWriter;
friend class ASTReader;
template <class decl_type> friend class RedeclarableTemplate;
friend class ClassTemplateSpecializationDecl;
friend class VarTemplateSpecializationDecl;

/// Retrieves the canonical declaration of this template.
RedeclarableTemplateDecl *getCanonicalDecl() override {
Expand Down Expand Up @@ -977,6 +993,7 @@ SpecEntryTraits<FunctionTemplateSpecializationInfo> {
class FunctionTemplateDecl : public RedeclarableTemplateDecl {
protected:
friend class FunctionDecl;
friend class FunctionTemplateSpecializationInfo;

/// Data that is common to all of the declarations of a given
/// function template.
Expand Down Expand Up @@ -1012,13 +1029,13 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
void addSpecialization(FunctionTemplateSpecializationInfo* Info,
void *InsertPos);

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

public:
friend class ASTDeclReader;
friend class ASTDeclWriter;

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

/// Get the underlying function declaration of the template.
FunctionDecl *getTemplatedDecl() const {
return static_cast<FunctionDecl *>(TemplatedDecl);
Expand Down Expand Up @@ -1839,6 +1856,8 @@ class ClassTemplateSpecializationDecl
LLVM_PREFERRED_TYPE(TemplateSpecializationKind)
unsigned SpecializationKind : 3;

void loadExternalRedecls();

protected:
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
DeclContext *DC, SourceLocation StartLoc,
Expand All @@ -1852,6 +1871,7 @@ class ClassTemplateSpecializationDecl
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class ASTReader;

static ClassTemplateSpecializationDecl *
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
Expand Down Expand Up @@ -2285,9 +2305,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class TemplateDeclInstantiator;

/// Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations() const;
friend class ClassTemplateSpecializationDecl;

/// Get the underlying class declarations of the template.
CXXRecordDecl *getTemplatedDecl() const {
Expand Down Expand Up @@ -2651,6 +2669,8 @@ class VarTemplateSpecializationDecl : public VarDecl,
LLVM_PREFERRED_TYPE(bool)
unsigned IsCompleteDefinition : 1;

void loadExternalRedecls();

protected:
VarTemplateSpecializationDecl(Kind DK, ASTContext &Context, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
Expand All @@ -2664,6 +2684,7 @@ class VarTemplateSpecializationDecl : public VarDecl,
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class ASTReader;
friend class VarDecl;

static VarTemplateSpecializationDecl *
Expand Down Expand Up @@ -3057,8 +3078,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
friend class ASTDeclReader;
friend class ASTDeclWriter;

/// Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations() const;
friend class VarTemplatePartialSpecializationDecl;

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

/// Load all the external specialzations for the Decl and the corresponding
/// template arguments.
virtual bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs);

/// Load all the external specializations for the Decl D.
virtual void LoadAllExternalSpecializations(const Decl *D);

/// Ensures that the table of all visible declarations inside this
/// context is up to date.
///
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/ODRHash.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ class ODRHash {

void AddStructuralValue(const APValue &);

// Add intergers to ID.
void AddInteger(unsigned Value);

static bool isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent);

private:
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ COMPATIBLE_LANGOPT(CPlusPlusModules, 1, 0, "C++ modules syntax")
LANGOPT(BuiltinHeadersInSystemModules, 1, 0, "builtin headers belong to system modules, and _Builtin_ modules are ignored for cstdlib headers")
BENIGN_ENUM_LANGOPT(CompilingModule, CompilingModuleKind, 3, CMK_None,
"compiling a module interface")
COMPATIBLE_LANGOPT(LoadExternalSpecializationsLazily, 1, 0, "Load External Specializations Lazily")
BENIGN_LANGOPT(CompilingPCH, 1, 0, "building a pch")
BENIGN_LANGOPT(BuildingPCHWithObjectFile, 1, 0, "building a pch which has a corresponding object file")
BENIGN_LANGOPT(CacheGeneratedPCH, 1, 0, "cache generated PCH files in memory")
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2978,6 +2978,13 @@ defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules",
PosFlag<SetTrue, [], [ClangOption], "Look up implicit modules in the prebuilt module path">,
NegFlag<SetFalse>, BothFlags<[], [ClangOption, CC1Option]>>;

defm load_external_specializations_lazily : BoolOption<"f", "load-external-specializations-lazily",
LangOpts<"LoadExternalSpecializationsLazily">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Load required external specialization only when required.">,
NegFlag<SetFalse, [], []>>,
Group<f_clang_Group>;

def fmodule_output_EQ : Joined<["-"], "fmodule-output=">,
Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">;
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Sema/MultiplexExternalSemaSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;

/// Load all the external specialzations for the Decl and the corresponding
/// template args.
virtual bool
LoadExternalSpecializations(const Decl *D,
ArrayRef<TemplateArgument> TemplateArgs) override;

void LoadAllExternalSpecializations(const Decl *D) override;

/// Ensures that the table of all visible declarations inside this
/// context is up to date.
void completeVisibleDeclsMap(const DeclContext *DC) override;
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,8 @@ enum ASTRecordTypes {
/// Record code for an unterminated \#pragma clang assume_nonnull begin
/// recorded in a preamble.
PP_ASSUME_NONNULL_LOC = 67,

UPDATE_SPECIALIZATION = 68,
};

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

// A decls specilization record.
DECL_SPECIALIZATIONS,

DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION
};

Expand Down
42 changes: 39 additions & 3 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,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 SpecializationsLookupTable;

} // namespace reader

} // namespace serialization
Expand Down Expand Up @@ -603,21 +606,30 @@ class ASTReader
llvm::DenseMap<const DeclContext *,
serialization::reader::DeclContextLookupTable> Lookups;

/// Map from decls to specialized decls.
llvm::DenseMap<const Decl *,
serialization::reader::SpecializationsLookupTable>
SpecializationsLookups;
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably have a mapping between a template argument hash -> vector of DeclIDs.


// 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<serialization::DeclID, DeclContextVisibleUpdates>
PendingVisibleUpdates;

using SpecializationsUpdate = SmallVector<UpdateData, 1>;
llvm::DenseMap<serialization::DeclID, SpecializationsUpdate>
PendingSpecializationsUpdates;

/// 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 All @@ -644,6 +656,11 @@ class ASTReader
llvm::BitstreamCursor &Cursor,
uint64_t Offset, serialization::DeclID ID);

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

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

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

private:
struct ImportedModule {
ModuleFile *Mod;
Expand Down Expand Up @@ -1986,6 +2008,12 @@ class ASTReader
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;

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

void LoadAllExternalSpecializations(const Decl *D) override;

/// Read all of the declarations lexically stored in a
/// declaration context.
///
Expand Down Expand Up @@ -2408,6 +2436,14 @@ class ASTReader
bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; }
};

/// Get a stable hash for template arguments across compiler invovations.
/// This is used for loading corresponding specializations lazily according
/// to the template arguments.
/// Given it is fine to load additional specializations, we're tolerant to
/// map different template arguments to the same hash value as long as the
/// semantically same template arguments get the same hash value.
unsigned GetTemplateArgsStableHash(ArrayRef<TemplateArgument> TemplateArgs);

/// A simple helper class to unpack an integer to bits and consuming
/// the bits in order.
class BitsUnpacker {
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,10 @@ class ASTWriter : public ASTDeserializationListener,
/// record containing modifications to them.
DeclUpdateMap DeclUpdates;

using SpecializationUpdateMap =
llvm::MapVector<const NamedDecl *, SmallVector<const NamedDecl *>>;
SpecializationUpdateMap SpecializationsUpdates;

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

/// Map of first declarations from a chained PCH that point to the
Expand Down Expand Up @@ -527,6 +531,13 @@ class ASTWriter : public ASTDeserializationListener,
bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);
bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext *DC);

void GenerateSpecializationsLookupTable(
const NamedDecl *D, llvm::SmallVectorImpl<const NamedDecl *> &Specs,
llvm::SmallVectorImpl<char> &LookupTable);
uint64_t WriteSpecializationsLookupTable(
const NamedDecl *D,
llvm::SmallVectorImpl<const NamedDecl *> &Specializations);

void GenerateNameLookupTable(const DeclContext *DC,
llvm::SmallVectorImpl<char> &LookupTable);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
Expand All @@ -538,6 +549,7 @@ class ASTWriter : public ASTDeserializationListener,
void WriteReferencedSelectorsPool(Sema &SemaRef);
void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver,
bool IsModule);
void WriteSpecializationsUpdates();
void WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord);
void WriteDeclContextVisibleUpdate(const DeclContext *DC);
void WriteFPPragmaOptions(const FPOptionsOverride &Opts);
Expand All @@ -564,6 +576,8 @@ class ASTWriter : public ASTDeserializationListener,
unsigned DeclEnumAbbrev = 0;
unsigned DeclObjCIvarAbbrev = 0;
unsigned DeclCXXMethodAbbrev = 0;
unsigned DeclSpecializationsAbbrev = 0;

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