[modules] Further simplification and speedup of redeclaration chain loading.

Instead of eagerly deserializing a list of DeclIDs when we load a module file
and doing a binary search to find the redeclarations of a decl, store a list of
redeclarations of each chain before the first declaration and load it directly.

llvm-svn: 245789
This commit is contained in:
Richard Smith 2015-08-22 20:13:39 +00:00
parent b17bb06914
commit d61d4acd70
9 changed files with 75 additions and 168 deletions

View File

@ -433,10 +433,7 @@ namespace clang {
/// declarations.
TU_UPDATE_LEXICAL = 22,
/// \brief Record code for the array describing the locations (in the
/// LOCAL_REDECLARATIONS record) of the redeclaration chains, indexed by
/// the first known ID.
LOCAL_REDECLARATIONS_MAP = 23,
// ID 23 used to be for a list of local redeclarations.
/// \brief Record code for declarations that Sema keeps references of.
SEMA_DECL_REFS = 24,
@ -514,13 +511,8 @@ namespace clang {
/// imported by the AST file.
IMPORTED_MODULES = 43,
// ID 40 used to be a table of merged canonical declarations.
/// \brief Record code for the array of redeclaration chains.
///
/// This array can only be interpreted properly using the local
/// redeclarations map.
LOCAL_REDECLARATIONS = 45,
// ID 44 used to be a table of merged canonical declarations.
// ID 45 used to be a list of declaration IDs of local redeclarations.
/// \brief Record code for the array of Objective-C categories (including
/// extensions).
@ -948,6 +940,9 @@ namespace clang {
/// For more information about predefined declarations, see the
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
const unsigned int NUM_PREDEF_DECL_IDS = 12;
/// \brief Record code for a list of local redeclarations of a declaration.
const unsigned int LOCAL_REDECLARATIONS = 50;
/// \brief Record codes for each kind of declaration.
///

View File

@ -933,12 +933,9 @@ private:
std::deque<Decl *> InterestingDecls;
/// \brief The list of redeclaration chains that still need to be
/// reconstructed.
///
/// Each element is the canonical declaration of the chain.
/// Elements in this vector should be unique; use
/// PendingDeclChainsKnown to ensure uniqueness.
SmallVector<Decl *, 16> PendingDeclChains;
/// reconstructed, and the local offset to the corresponding list
/// of redeclarations.
SmallVector<std::pair<Decl *, uint64_t>, 16> PendingDeclChains;
/// \brief The list of canonical declarations whose redeclaration chains
/// need to be marked as incomplete once we're done deserializing things.
@ -1165,7 +1162,7 @@ private:
RecordLocation DeclCursorForID(serialization::DeclID ID,
unsigned &RawLocation);
void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
void loadPendingDeclChain(Decl *D);
void loadPendingDeclChain(Decl *D, uint64_t LocalOffset);
void loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D,
unsigned PreviousGeneration = 0);

View File

@ -547,7 +547,6 @@ private:
void WriteFPPragmaOptions(const FPOptions &Opts);
void WriteOpenCLExtensions(Sema &SemaRef);
void WriteObjCCategories();
void WriteRedeclarations();
void WriteLateParsedTemplates(Sema &SemaRef);
void WriteOptimizePragmaOptions(Sema &SemaRef);

View File

@ -427,17 +427,6 @@ public:
const serialization::DeclID *FileSortedDecls;
unsigned NumFileSortedDecls;
/// \brief Array of redeclaration chain location information within this
/// module file, sorted by the first declaration ID.
const serialization::LocalRedeclarationsInfo *RedeclarationsMap;
/// \brief The number of redeclaration info entries in RedeclarationsMap.
unsigned LocalNumRedeclarationsInMap;
/// \brief The redeclaration chains for declarations local to this
/// module file.
SmallVector<uint64_t, 1> RedeclarationChains;
/// \brief Array of category list location information within this
/// module file, sorted by the definition ID.
const serialization::ObjCCategoriesInfo *ObjCCategoriesMap;

View File

@ -3100,22 +3100,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
}
case LOCAL_REDECLARATIONS: {
F.RedeclarationChains.swap(Record);
break;
}
case LOCAL_REDECLARATIONS_MAP: {
if (F.LocalNumRedeclarationsInMap != 0) {
Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
return Failure;
}
F.LocalNumRedeclarationsInMap = Record[0];
F.RedeclarationsMap = (const LocalRedeclarationsInfo *)Blob.data();
break;
}
case MACRO_OFFSET: {
if (F.LocalNumMacros != 0) {
Error("duplicate MACRO_OFFSET record in AST file");
@ -8124,7 +8108,7 @@ void ASTReader::finishPendingActions() {
// Load pending declaration chains.
for (unsigned I = 0; I != PendingDeclChains.size(); ++I)
loadPendingDeclChain(PendingDeclChains[I]);
loadPendingDeclChain(PendingDeclChains[I].first, PendingDeclChains[I].second);
PendingDeclChains.clear();
// Make the most recent of the top-level declarations visible.

View File

@ -2156,6 +2156,8 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
bool IsKeyDecl = ThisDeclID == FirstDeclID;
bool IsFirstLocalDecl = false;
uint64_t RedeclOffset = 0;
// 0 indicates that this declaration was the only declaration of its entity,
// and is used for space optimization.
if (FirstDeclID == 0) {
@ -2175,6 +2177,8 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
// declaration.
for (unsigned I = 0; I != N - 1; ++I)
MergeWith = ReadDecl(Record, Idx/*, MergeWith*/);
RedeclOffset = Record[Idx++];
} else {
// This declaration was not the first local declaration. Read the first
// local declaration now, to trigger the import of other redeclarations.
@ -2198,7 +2202,7 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
// above; this ensures that the redeclaration chain is built in the correct
// order.
if (IsFirstLocalDecl)
Reader.PendingDeclChains.push_back(DAsT);
Reader.PendingDeclChains.push_back(std::make_pair(DAsT, RedeclOffset));
return RedeclarableResult(FirstDeclID, MergeWith, IsKeyDecl);
}
@ -3393,43 +3397,40 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
}
}
void ASTReader::loadPendingDeclChain(Decl *FirstLocal) {
ModuleFile &M = *getOwningModuleFile(FirstLocal);
DeclID LocalID =
mapGlobalIDToModuleFileGlobalID(M, FirstLocal->getGlobalID());
assert(LocalID && "looking for redecl chain in wrong module file");
// Perform a binary search to find the local redeclarations for this
// declaration (if any).
// FIXME: Just store an offset with the first declaration.
const LocalRedeclarationsInfo Compare = {LocalID, 0};
const LocalRedeclarationsInfo *Result = std::lower_bound(
M.RedeclarationsMap,
M.RedeclarationsMap + M.LocalNumRedeclarationsInMap, Compare);
// Pull out the list of redeclarations.
SmallVector<Decl*, 4> Chain;
if (Result != M.RedeclarationsMap + M.LocalNumRedeclarationsInMap &&
Result->FirstID == LocalID) {
unsigned Offset = Result->Offset;
unsigned N = M.RedeclarationChains[Offset++];
for (unsigned I = 0; I != N; ++I)
Chain.push_back(GetLocalDecl(M, M.RedeclarationChains[Offset++]));
}
Chain.push_back(FirstLocal);
// Hook up the chain.
//
// FIXME: We have three different dispatches on decl kind here; maybe
// we should instead generate one loop per kind and dispatch up-front?
void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) {
// Attach FirstLocal to the end of the decl chain.
Decl *CanonDecl = FirstLocal->getCanonicalDecl();
Decl *MostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl);
if (!MostRecent)
MostRecent = CanonDecl;
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
auto *D = Chain[N - I - 1];
if (D == CanonDecl)
continue;
if (FirstLocal != CanonDecl) {
Decl *PrevMostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl);
ASTDeclReader::attachPreviousDecl(
*this, FirstLocal, PrevMostRecent ? PrevMostRecent : CanonDecl,
CanonDecl);
}
if (!LocalOffset) {
ASTDeclReader::attachLatestDecl(CanonDecl, FirstLocal);
return;
}
// Load the list of other redeclarations from this module file.
ModuleFile *M = getOwningModuleFile(FirstLocal);
assert(M && "imported decl from no module file");
llvm::BitstreamCursor &Cursor = M->DeclsCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(LocalOffset);
RecordData Record;
unsigned Code = Cursor.ReadCode();
unsigned RecCode = Cursor.readRecord(Code, Record);
(void)RecCode;
assert(RecCode == LOCAL_REDECLARATIONS && "expected LOCAL_REDECLARATIONS record!");
// FIXME: We have several different dispatches on decl kind here; maybe
// we should instead generate one loop per kind and dispatch up-front?
Decl *MostRecent = FirstLocal;
for (unsigned I = 0, N = Record.size(); I != N; ++I) {
auto *D = GetLocalDecl(*M, Record[N - I - 1]);
ASTDeclReader::attachPreviousDecl(*this, D, MostRecent, CanonDecl);
MostRecent = D;
}

View File

@ -911,7 +911,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(PPD_ENTITIES_OFFSETS);
RECORD(REFERENCED_SELECTOR_POOL);
RECORD(TU_UPDATE_LEXICAL);
RECORD(LOCAL_REDECLARATIONS_MAP);
RECORD(SEMA_DECL_REFS);
RECORD(WEAK_UNDECLARED_IDENTIFIERS);
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
@ -933,7 +932,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(OBJC_CATEGORIES_MAP);
RECORD(FILE_SORTED_DECLS);
RECORD(IMPORTED_MODULES);
RECORD(LOCAL_REDECLARATIONS);
RECORD(OBJC_CATEGORIES);
RECORD(MACRO_OFFSET);
RECORD(LATE_PARSED_TEMPLATE);
@ -997,6 +995,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(TYPE_ATOMIC);
RECORD(TYPE_DECAYED);
RECORD(TYPE_ADJUSTED);
RECORD(LOCAL_REDECLARATIONS);
RECORD(DECL_TYPEDEF);
RECORD(DECL_TYPEALIAS);
RECORD(DECL_ENUM);
@ -3794,76 +3793,6 @@ void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) {
Stream.EmitRecord(OPENCL_EXTENSIONS, Record);
}
void ASTWriter::WriteRedeclarations() {
RecordData LocalRedeclChains;
SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap;
for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) {
const Decl *FirstLocal = Redeclarations[I];
assert(!FirstLocal->isFromASTFile() &&
(!FirstLocal->getPreviousDecl() ||
FirstLocal->getPreviousDecl()->isFromASTFile() ||
getDeclID(FirstLocal->getPreviousDecl()) < NUM_PREDEF_DECL_IDS) &&
"not the first local declaration");
assert(getDeclID(FirstLocal) >= NUM_PREDEF_DECL_IDS &&
"should not have predefined decl as first decl");
unsigned Offset = LocalRedeclChains.size();
unsigned Size = 0;
LocalRedeclChains.push_back(0); // Placeholder for the size.
// Collect the set of local redeclarations of this declaration, from newest
// to oldest.
for (const Decl *Prev = FirstLocal->getMostRecentDecl(); Prev != FirstLocal;
Prev = Prev->getPreviousDecl()) {
if (!Prev->isFromASTFile()) {
AddDeclRef(Prev, LocalRedeclChains);
++Size;
}
}
// If we only have a single local declaration, there is no point in storing
// a redeclaration chain.
if (LocalRedeclChains.size() == 1)
continue;
LocalRedeclChains[Offset] = Size;
// Add the mapping from the first ID from the AST to the set of local
// declarations.
LocalRedeclarationsInfo Info = { getDeclID(FirstLocal), Offset };
LocalRedeclsMap.push_back(Info);
assert(N == Redeclarations.size() &&
"Deserialized a declaration we shouldn't have");
}
if (LocalRedeclChains.empty())
return;
// Sort the local redeclarations map by the first declaration ID,
// since the reader will be performing binary searches on this information.
llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end());
// Emit the local redeclarations map.
using namespace llvm;
llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS_MAP));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
RecordData Record;
Record.push_back(LOCAL_REDECLARATIONS_MAP);
Record.push_back(LocalRedeclsMap.size());
Stream.EmitRecordWithBlob(AbbrevID, Record,
reinterpret_cast<char*>(LocalRedeclsMap.data()),
LocalRedeclsMap.size() * sizeof(LocalRedeclarationsInfo));
// Emit the redeclaration chains.
Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedeclChains);
}
void ASTWriter::WriteObjCCategories() {
SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
RecordData Categories;
@ -4589,7 +4518,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
WriteDeclReplacementsBlock();
WriteRedeclarations();
WriteObjCCategories();
if(!WritingModule)
WriteOptimizePragmaOptions(SemaRef);

View File

@ -1565,8 +1565,6 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
// first local declaration in the chain.
const Decl *FirstLocal = Writer.getFirstLocalDecl(DAsT);
if (DAsT == FirstLocal) {
Writer.Redeclarations.push_back(DAsT);
// Emit a list of all imported first declarations so that we can be sure
// that all redeclarations visible to this module are before D in the
// redecl chain.
@ -1576,6 +1574,23 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
AddFirstDeclFromEachModule(DAsT, /*IncludeLocal*/false);
// This is the number of imported first declarations + 1.
Record[I] = Record.size() - I;
// Collect the set of local redeclarations of this declaration, from
// newest to oldest.
RecordData LocalRedecls;
for (const Decl *Prev = FirstLocal->getMostRecentDecl();
Prev != FirstLocal; Prev = Prev->getPreviousDecl())
if (!Prev->isFromASTFile())
Writer.AddDeclRef(Prev, LocalRedecls);
// If we have any redecls, write them now as a separate record preceding
// the declaration itself.
if (LocalRedecls.empty())
Record.push_back(0);
else {
Record.push_back(Writer.Stream.GetCurrentBitNo());
Writer.Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedecls);
}
} else {
Record.push_back(0);
Writer.AddDeclRef(FirstLocal, Record);
@ -2114,6 +2129,13 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
VisibleOffset = WriteDeclContextVisibleBlock(Context, DC);
}
// Build a record for this declaration
Record.clear();
W.Code = (serialization::DeclCode)0;
W.AbbrevToUse = 0;
W.Visit(D);
if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
if (isReplacingADecl) {
// We're replacing a decl in a previous file.
ReplacedDecls.push_back(ReplacedDeclInfo(ID, Stream.GetCurrentBitNo(),
@ -2130,19 +2152,12 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
DeclOffsets[Index].setLocation(Loc);
DeclOffsets[Index].BitOffset = Stream.GetCurrentBitNo();
}
SourceManager &SM = Context.getSourceManager();
if (Loc.isValid() && SM.isLocalSourceLocation(Loc))
associateDeclWithFile(D, ID);
}
// Build and emit a record for this declaration
Record.clear();
W.Code = (serialization::DeclCode)0;
W.AbbrevToUse = 0;
W.Visit(D);
if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
if (!W.Code)
llvm::report_fatal_error(StringRef("unexpected declaration kind '") +
D->getDeclKindName() + "'");

View File

@ -40,7 +40,6 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(nullptr),
LocalNumCXXCtorInitializers(0), CXXCtorInitializersOffsets(nullptr),
FileSortedDecls(nullptr), NumFileSortedDecls(0),
RedeclarationsMap(nullptr), LocalNumRedeclarationsInMap(0),
ObjCCategoriesMap(nullptr), LocalNumObjCCategoriesInMap(0),
LocalNumTypes(0), TypeOffsets(nullptr), BaseTypeIndex(0)
{}