summaryrefslogtreecommitdiff
path: root/clang/lib/Serialization/ASTWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Serialization/ASTWriter.cpp')
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp312
1 files changed, 278 insertions, 34 deletions
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index a52d59c61c4c..4a6027943072 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -13,6 +13,7 @@
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
#include "MultiOnDiskHashTable.h"
+#include "TemplateArgumentHasher.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTUnresolvedSet.h"
#include "clang/AST/AbstractTypeWriter.h"
@@ -184,14 +185,30 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
const SourceManager &SM = PP.getSourceManager();
const ModuleMap &MM = HS.getModuleMap();
- llvm::DenseSet<FileID> ModuleMaps;
-
- llvm::DenseSet<const Module *> ProcessedModules;
- auto CollectModuleMapsForHierarchy = [&](const Module *M) {
+ // Module maps used only by textual headers are special. Their FileID is
+ // non-affecting, but their FileEntry is (i.e. must be written as InputFile).
+ enum AffectedReason : bool {
+ AR_TextualHeader = 0,
+ AR_ImportOrTextualHeader = 1,
+ };
+ auto AssignMostImportant = [](AffectedReason &LHS, AffectedReason RHS) {
+ LHS = std::max(LHS, RHS);
+ };
+ llvm::DenseMap<FileID, AffectedReason> ModuleMaps;
+ llvm::DenseMap<const Module *, AffectedReason> ProcessedModules;
+ auto CollectModuleMapsForHierarchy = [&](const Module *M,
+ AffectedReason Reason) {
M = M->getTopLevelModule();
- if (!ProcessedModules.insert(M).second)
+ // We need to process the header either when it was not present or when we
+ // previously flagged module map as textual headers and now we found a
+ // proper import.
+ if (auto [It, Inserted] = ProcessedModules.insert({M, Reason});
+ !Inserted && Reason <= It->second) {
return;
+ } else {
+ It->second = Reason;
+ }
std::queue<const Module *> Q;
Q.push(M);
@@ -202,12 +219,12 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
// The containing module map is affecting, because it's being pointed
// into by Module::DefinitionLoc.
if (auto F = MM.getContainingModuleMapFileID(Mod); F.isValid())
- ModuleMaps.insert(F);
+ AssignMostImportant(ModuleMaps[F], Reason);
// For inferred modules, the module map that allowed inferring is not
// related to the virtual containing module map file. It did affect the
// compilation, though.
if (auto UniqF = MM.getModuleMapFileIDForUniquing(Mod); UniqF.isValid())
- ModuleMaps.insert(UniqF);
+ AssignMostImportant(ModuleMaps[UniqF], Reason);
for (auto *SubM : Mod->submodules())
Q.push(SubM);
@@ -216,7 +233,7 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
// Handle all the affecting modules referenced from the root module.
- CollectModuleMapsForHierarchy(RootModule);
+ CollectModuleMapsForHierarchy(RootModule, AR_ImportOrTextualHeader);
std::queue<const Module *> Q;
Q.push(RootModule);
@@ -225,9 +242,9 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
Q.pop();
for (const Module *ImportedModule : CurrentModule->Imports)
- CollectModuleMapsForHierarchy(ImportedModule);
+ CollectModuleMapsForHierarchy(ImportedModule, AR_ImportOrTextualHeader);
for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses)
- CollectModuleMapsForHierarchy(UndeclaredModule);
+ CollectModuleMapsForHierarchy(UndeclaredModule, AR_ImportOrTextualHeader);
for (auto *M : CurrentModule->submodules())
Q.push(M);
@@ -256,7 +273,7 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
for (const auto &KH : HS.findResolvedModulesForHeader(*File))
if (const Module *M = KH.getModule())
- CollectModuleMapsForHierarchy(M);
+ CollectModuleMapsForHierarchy(M, AR_TextualHeader);
}
// FIXME: This algorithm is not correct for module map hierarchies where
@@ -278,13 +295,16 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
// includes a module map defining a module that's not a submodule of X.
llvm::DenseSet<const FileEntry *> ModuleFileEntries;
- for (FileID MM : ModuleMaps) {
- if (auto *FE = SM.getFileEntryForID(MM))
+ llvm::DenseSet<FileID> ModuleFileIDs;
+ for (auto [FID, Reason] : ModuleMaps) {
+ if (Reason == AR_ImportOrTextualHeader)
+ ModuleFileIDs.insert(FID);
+ if (auto *FE = SM.getFileEntryForID(FID))
ModuleFileEntries.insert(FE);
}
AffectingModuleMaps R;
- R.DefinitionFileIDs = std::move(ModuleMaps);
+ R.DefinitionFileIDs = std::move(ModuleFileIDs);
R.DefinitionFiles = std::move(ModuleFileEntries);
return std::move(R);
}
@@ -921,7 +941,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
RECORD(UPDATE_VISIBLE);
RECORD(DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD);
- RECORD(FUNCTION_DECL_TO_LAMBDAS_MAP);
+ RECORD(RELATED_DECLS_MAP);
RECORD(DECL_UPDATE_OFFSETS);
RECORD(DECL_UPDATES);
RECORD(CUDA_SPECIAL_DECL_REFS);
@@ -4148,6 +4168,175 @@ public:
} // namespace
+namespace {
+class LazySpecializationInfoLookupTrait {
+ ASTWriter &Writer;
+ llvm::SmallVector<serialization::reader::LazySpecializationInfo, 64> Specs;
+
+public:
+ using key_type = unsigned;
+ using key_type_ref = key_type;
+
+ /// A start and end index into Specs, representing a sequence of decls.
+ using data_type = std::pair<unsigned, unsigned>;
+ using data_type_ref = const data_type &;
+
+ using hash_value_type = unsigned;
+ using offset_type = unsigned;
+
+ explicit LazySpecializationInfoLookupTrait(ASTWriter &Writer)
+ : Writer(Writer) {}
+
+ template <typename Col, typename Col2>
+ data_type getData(Col &&C, Col2 &ExistingInfo) {
+ unsigned Start = Specs.size();
+ for (auto *D : C) {
+ NamedDecl *ND = getDeclForLocalLookup(Writer.getLangOpts(),
+ const_cast<NamedDecl *>(D));
+ Specs.push_back(GlobalDeclID(Writer.GetDeclRef(ND).getRawValue()));
+ }
+ for (const serialization::reader::LazySpecializationInfo &Info :
+ ExistingInfo)
+ Specs.push_back(Info);
+ return std::make_pair(Start, Specs.size());
+ }
+
+ data_type ImportData(
+ const reader::LazySpecializationInfoLookupTrait::data_type &FromReader) {
+ unsigned Start = Specs.size();
+ for (auto ID : FromReader)
+ Specs.push_back(ID);
+ return std::make_pair(Start, Specs.size());
+ }
+
+ static bool EqualKey(key_type_ref a, key_type_ref b) { return a == b; }
+
+ hash_value_type ComputeHash(key_type Name) { return Name; }
+
+ void EmitFileRef(raw_ostream &Out, ModuleFile *F) const {
+ assert(Writer.hasChain() &&
+ "have reference to loaded module file but no chain?");
+
+ using namespace llvm::support;
+ endian::write<uint32_t>(Out, Writer.getChain()->getModuleFileID(F),
+ llvm::endianness::little);
+ }
+
+ std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &Out,
+ key_type HashValue,
+ data_type_ref Lookup) {
+ // 4 bytes for each slot.
+ unsigned KeyLen = 4;
+ unsigned DataLen = sizeof(serialization::reader::LazySpecializationInfo) *
+ (Lookup.second - Lookup.first);
+
+ return emitULEBKeyDataLength(KeyLen, DataLen, Out);
+ }
+
+ void EmitKey(raw_ostream &Out, key_type HashValue, unsigned) {
+ using namespace llvm::support;
+
+ endian::Writer LE(Out, llvm::endianness::little);
+ LE.write<uint32_t>(HashValue);
+ }
+
+ void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup,
+ unsigned DataLen) {
+ using namespace llvm::support;
+
+ endian::Writer LE(Out, llvm::endianness::little);
+ uint64_t Start = Out.tell();
+ (void)Start;
+ for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) {
+ LE.write<DeclID>(Specs[I].getRawValue());
+ }
+ assert(Out.tell() - Start == DataLen && "Data length is wrong");
+ }
+};
+
+unsigned CalculateODRHashForSpecs(const Decl *Spec) {
+ ArrayRef<TemplateArgument> Args;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Spec))
+ Args = CTSD->getTemplateArgs().asArray();
+ else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Spec))
+ Args = VTSD->getTemplateArgs().asArray();
+ else if (auto *FD = dyn_cast<FunctionDecl>(Spec))
+ Args = FD->getTemplateSpecializationArgs()->asArray();
+ else
+ llvm_unreachable("New Specialization Kind?");
+
+ return StableHashForTemplateArguments(Args);
+}
+} // namespace
+
+void ASTWriter::GenerateSpecializationInfoLookupTable(
+ const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
+ llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial) {
+ assert(D->isFirstDecl());
+
+ // Create the on-disk hash table representation.
+ MultiOnDiskHashTableGenerator<reader::LazySpecializationInfoLookupTrait,
+ LazySpecializationInfoLookupTrait>
+ Generator;
+ LazySpecializationInfoLookupTrait Trait(*this);
+
+ llvm::DenseMap<unsigned, llvm::SmallVector<const NamedDecl *, 4>>
+ SpecializationMaps;
+
+ for (auto *Specialization : Specializations) {
+ unsigned HashedValue = CalculateODRHashForSpecs(Specialization);
+
+ auto Iter = SpecializationMaps.find(HashedValue);
+ if (Iter == SpecializationMaps.end())
+ Iter = SpecializationMaps
+ .try_emplace(HashedValue,
+ llvm::SmallVector<const NamedDecl *, 4>())
+ .first;
+
+ Iter->second.push_back(cast<NamedDecl>(Specialization));
+ }
+
+ auto *Lookups =
+ Chain ? Chain->getLoadedSpecializationsLookupTables(D, IsPartial)
+ : nullptr;
+
+ for (auto &[HashValue, Specs] : SpecializationMaps) {
+ SmallVector<serialization::reader::LazySpecializationInfo, 16>
+ ExisitingSpecs;
+ // We have to merge the lookup table manually here. We can't depend on the
+ // merge mechanism offered by
+ // clang::serialization::MultiOnDiskHashTableGenerator since that generator
+ // assumes the we'll get the same value with the same key.
+ // And also underlying llvm::OnDiskChainedHashTableGenerator assumes that we
+ // won't insert the values with the same key twice. So we have to merge the
+ // lookup table here manually.
+ if (Lookups)
+ ExisitingSpecs = Lookups->Table.find(HashValue);
+
+ Generator.insert(HashValue, Trait.getData(Specs, ExisitingSpecs), Trait);
+ }
+
+ Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr);
+}
+
+uint64_t ASTWriter::WriteSpecializationInfoLookupTable(
+ const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
+ bool IsPartial) {
+
+ llvm::SmallString<4096> LookupTable;
+ GenerateSpecializationInfoLookupTable(D, Specializations, LookupTable,
+ IsPartial);
+
+ uint64_t Offset = Stream.GetCurrentBitNo();
+ RecordData::value_type Record[] = {static_cast<RecordData::value_type>(
+ IsPartial ? DECL_PARTIAL_SPECIALIZATIONS : DECL_SPECIALIZATIONS)};
+ Stream.EmitRecordWithBlob(IsPartial ? DeclPartialSpecializationsAbbrev
+ : DeclSpecializationsAbbrev,
+ Record, LookupTable);
+
+ return Offset;
+}
+
bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
DeclContext *DC) {
return Result.hasExternalDecls() &&
@@ -4922,7 +5111,7 @@ ASTWriter::WriteAST(llvm::PointerUnion<Sema *, Preprocessor *> Subject,
Sema *SemaPtr = Subject.dyn_cast<Sema *>();
Preprocessor &PPRef =
- SemaPtr ? SemaPtr->getPreprocessor() : *Subject.get<Preprocessor *>();
+ SemaPtr ? SemaPtr->getPreprocessor() : *cast<Preprocessor *>(Subject);
ASTHasCompilerErrors = PPRef.getDiagnostics().hasUncompilableErrorOccurred();
@@ -5729,7 +5918,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
// Keep writing types, declarations, and declaration update records
// until we've emitted all of them.
RecordData DeclUpdatesOffsetsRecord;
- Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5);
+ Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/ 6);
DeclTypesBlockStartOffset = Stream.GetCurrentBitNo();
WriteTypeAbbrevs();
WriteDeclAbbrevs();
@@ -5783,26 +5972,36 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
Stream.EmitRecord(DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD,
DelayedNamespaceRecord);
- if (!FunctionToLambdasMap.empty()) {
- // TODO: on disk hash table for function to lambda mapping might be more
+ if (!RelatedDeclsMap.empty()) {
+ // TODO: on disk hash table for related decls mapping might be more
// efficent becuase it allows lazy deserialization.
- RecordData FunctionToLambdasMapRecord;
- for (const auto &Pair : FunctionToLambdasMap) {
- FunctionToLambdasMapRecord.push_back(Pair.first.getRawValue());
- FunctionToLambdasMapRecord.push_back(Pair.second.size());
+ RecordData RelatedDeclsMapRecord;
+ for (const auto &Pair : RelatedDeclsMap) {
+ RelatedDeclsMapRecord.push_back(Pair.first.getRawValue());
+ RelatedDeclsMapRecord.push_back(Pair.second.size());
for (const auto &Lambda : Pair.second)
- FunctionToLambdasMapRecord.push_back(Lambda.getRawValue());
+ RelatedDeclsMapRecord.push_back(Lambda.getRawValue());
}
auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
- Abv->Add(llvm::BitCodeAbbrevOp(FUNCTION_DECL_TO_LAMBDAS_MAP));
+ Abv->Add(llvm::BitCodeAbbrevOp(RELATED_DECLS_MAP));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array));
Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
unsigned FunctionToLambdaMapAbbrev = Stream.EmitAbbrev(std::move(Abv));
- Stream.EmitRecord(FUNCTION_DECL_TO_LAMBDAS_MAP, FunctionToLambdasMapRecord,
+ Stream.EmitRecord(RELATED_DECLS_MAP, RelatedDeclsMapRecord,
FunctionToLambdaMapAbbrev);
}
+ if (!SpecializationsUpdates.empty()) {
+ WriteSpecializationsUpdates(/*IsPartial=*/false);
+ SpecializationsUpdates.clear();
+ }
+
+ if (!PartialSpecializationsUpdates.empty()) {
+ WriteSpecializationsUpdates(/*IsPartial=*/true);
+ PartialSpecializationsUpdates.clear();
+ }
+
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
@@ -5846,6 +6045,33 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
WriteDeclContextVisibleUpdate(Context, DC);
}
+void ASTWriter::WriteSpecializationsUpdates(bool IsPartial) {
+ auto RecordType = IsPartial ? CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION
+ : CXX_ADDED_TEMPLATE_SPECIALIZATION;
+
+ auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
+ Abv->Add(llvm::BitCodeAbbrevOp(RecordType));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
+ auto UpdateSpecializationAbbrev = Stream.EmitAbbrev(std::move(Abv));
+
+ auto &SpecUpdates =
+ IsPartial ? PartialSpecializationsUpdates : SpecializationsUpdates;
+ for (auto &SpecializationUpdate : SpecUpdates) {
+ const NamedDecl *D = SpecializationUpdate.first;
+
+ llvm::SmallString<4096> LookupTable;
+ GenerateSpecializationInfoLookupTable(D, SpecializationUpdate.second,
+ LookupTable, IsPartial);
+
+ // Write the lookup table
+ RecordData::value_type Record[] = {
+ static_cast<RecordData::value_type>(RecordType),
+ getDeclID(D).getRawValue()};
+ Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable);
+ }
+}
+
void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context,
RecordDataImpl &OffsetsRecord) {
if (DeclUpdates.empty())
@@ -5875,12 +6101,10 @@ void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context,
switch (Kind) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
- case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
assert(Update.getDecl() && "no decl to add?");
Record.AddDeclRef(Update.getDecl());
break;
-
case UPD_CXX_ADDED_FUNCTION_DEFINITION:
case UPD_CXX_ADDED_VAR_DEFINITION:
break;
@@ -8102,6 +8326,12 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
AddStmt(E);
return;
}
+ case OpenACCClauseKind::DeviceNum: {
+ const auto *DNC = cast<OpenACCDeviceNumClause>(C);
+ writeSourceLocation(DNC->getLParenLoc());
+ AddStmt(const_cast<Expr*>(DNC->getIntExpr()));
+ return;
+ }
case OpenACCClauseKind::NumWorkers: {
const auto *NWC = cast<OpenACCNumWorkersClause>(C);
writeSourceLocation(NWC->getLParenLoc());
@@ -8132,6 +8362,24 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
writeOpenACCVarList(AC);
return;
}
+ case OpenACCClauseKind::Detach: {
+ const auto *DC = cast<OpenACCDetachClause>(C);
+ writeSourceLocation(DC->getLParenLoc());
+ writeOpenACCVarList(DC);
+ return;
+ }
+ case OpenACCClauseKind::Delete: {
+ const auto *DC = cast<OpenACCDeleteClause>(C);
+ writeSourceLocation(DC->getLParenLoc());
+ writeOpenACCVarList(DC);
+ return;
+ }
+ case OpenACCClauseKind::UseDevice: {
+ const auto *UDC = cast<OpenACCUseDeviceClause>(C);
+ writeSourceLocation(UDC->getLParenLoc());
+ writeOpenACCVarList(UDC);
+ return;
+ }
case OpenACCClauseKind::DevicePtr: {
const auto *DPC = cast<OpenACCDevicePtrClause>(C);
writeSourceLocation(DPC->getLParenLoc());
@@ -8227,6 +8475,8 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::Seq:
case OpenACCClauseKind::Independent:
case OpenACCClauseKind::Auto:
+ case OpenACCClauseKind::Finalize:
+ case OpenACCClauseKind::IfPresent:
// Nothing to do here, there is no additional information beyond the
// begin/end loc and clause kind.
return;
@@ -8272,18 +8522,12 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
return;
}
- case OpenACCClauseKind::Finalize:
- case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::NoHost:
- case OpenACCClauseKind::UseDevice:
- case OpenACCClauseKind::Delete:
- case OpenACCClauseKind::Detach:
case OpenACCClauseKind::Device:
case OpenACCClauseKind::DeviceResident:
case OpenACCClauseKind::Host:
case OpenACCClauseKind::Link:
case OpenACCClauseKind::Bind:
- case OpenACCClauseKind::DeviceNum:
case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");