diff options
Diffstat (limited to 'clang/lib/Serialization/ASTWriter.cpp')
| -rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 312 |
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"); |
