[modules] Switch to the normal reverse postorder visitation algorithm when computing redeclaration chains.

llvm-svn: 242253
This commit is contained in:
Richard Smith 2015-07-15 00:02:40 +00:00
parent 6fce2e4f26
commit e2f8ce91e7
2 changed files with 84 additions and 82 deletions

View File

@ -3423,19 +3423,19 @@ namespace {
GlobalDeclID CanonID)
: Reader(Reader), SearchDecls(SearchDecls), Deserialized(Deserialized),
CanonID(CanonID) {
// Ensure that the canonical ID goes at the start of the chain.
addToChain(Reader.GetDecl(CanonID));
assert(std::is_sorted(SearchDecls.begin(), SearchDecls.end()));
}
static ModuleManager::DFSPreorderControl
visitPreorder(ModuleFile &M, void *UserData) {
return static_cast<RedeclChainVisitor *>(UserData)->visitPreorder(M);
}
static bool visitPostorder(ModuleFile &M, void *UserData) {
return static_cast<RedeclChainVisitor *>(UserData)->visitPostorder(M);
static bool visit(ModuleFile &M, void *UserData) {
return static_cast<RedeclChainVisitor*>(UserData)->visit(M);
}
/// Get the chain, in order from newest to oldest.
ArrayRef<Decl *> getChain() const {
return Chain;
}
private:
void addToChain(Decl *D) {
if (!D)
return;
@ -3444,75 +3444,82 @@ namespace {
Chain.push_back(D);
}
void searchForID(ModuleFile &M, GlobalDeclID GlobalID) {
// Map global ID of the first declaration down to the local ID
// used in this module file.
DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID);
if (!ID)
return;
// If the search decl was from this module, add it to the chain before any
// of its redeclarations in this module or users of it, and after any from
// imported modules.
if (CanonID != GlobalID && Reader.isDeclIDFromModule(GlobalID, M))
addToChain(Reader.GetDecl(GlobalID));
llvm::Optional<unsigned> findRedeclOffset(ModuleFile &M, DeclID LocalID) {
// Perform a binary search to find the local redeclarations for this
// declaration (if any).
const LocalRedeclarationsInfo Compare = { ID, 0 };
const LocalRedeclarationsInfo *Result
= std::lower_bound(M.RedeclarationsMap,
M.RedeclarationsMap + M.LocalNumRedeclarationsInMap,
Compare);
if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap ||
Result->FirstID != ID)
return;
// Dig out all of the redeclarations.
unsigned Offset = Result->Offset;
unsigned N = M.RedeclarationChains[Offset];
M.RedeclarationChains[Offset++] = 0; // Don't try to deserialize again
for (unsigned I = 0; I != N; ++I)
addToChain(Reader.GetLocalDecl(M, M.RedeclarationChains[Offset++]));
}
bool needsToVisitImports(ModuleFile &M, GlobalDeclID GlobalID) {
DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID);
if (!ID)
return false;
const LocalRedeclarationsInfo Compare = {ID, 0};
const LocalRedeclarationsInfo Compare = { LocalID, 0 };
const LocalRedeclarationsInfo *Result = std::lower_bound(
M.RedeclarationsMap,
M.RedeclarationsMap + M.LocalNumRedeclarationsInMap, Compare);
if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap ||
Result->FirstID != ID) {
return true;
}
unsigned Offset = Result->Offset;
unsigned N = M.RedeclarationChains[Offset];
// We don't need to visit a module or any of its imports if we've already
// deserialized the redecls from this module.
return N != 0;
Result->FirstID != LocalID)
return None;
return Result->Offset;
}
ModuleManager::DFSPreorderControl visitPreorder(ModuleFile &M) {
for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I) {
if (needsToVisitImports(M, SearchDecls[I]))
return ModuleManager::Continue;
}
return ModuleManager::SkipImports;
}
bool visit(ModuleFile &M) {
llvm::ArrayRef<DeclID> ToSearch = SearchDecls;
GlobalDeclID LocalSearchDeclID = 0;
bool visitPostorder(ModuleFile &M) {
// Visit each of the declarations.
for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I)
searchForID(M, SearchDecls[I]);
return false;
}
ArrayRef<Decl *> getChain() const {
return Chain;
// First, check whether any of our search decls was declared in M.
auto I = std::lower_bound(SearchDecls.begin(), SearchDecls.end(),
M.BaseDeclID + NUM_PREDEF_DECL_IDS);
if (I != SearchDecls.end() && Reader.isDeclIDFromModule(*I, M)) {
LocalSearchDeclID = *I;
ToSearch = llvm::makeArrayRef(*I);
}
// Now, walk the search decls looking for one that's declared in this
// module file.
bool ImportedModulesMightHaveDecls = false;
for (auto GlobalID : ToSearch) {
// Map global ID of the first declaration down to the local ID
// used in this module file.
DeclID LocalID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID);
if (!LocalID)
continue;
auto MaybeOffset = findRedeclOffset(M, LocalID);
if (MaybeOffset) {
// We found it. Dig out all of the redeclarations.
unsigned Offset = *MaybeOffset;
unsigned N = M.RedeclarationChains[Offset];
if (!N)
// We've already loaded these.
// FIXME: In this case, we may be able to skip processing any
// imported modules too. We can't do that yet, though, because
// it's possible that our list of search decls misses out some
// search decls from modules that M imports.
continue;
M.RedeclarationChains[Offset++] = 0; // Don't try to deserialize again
// Note, declarations are listed from newest to oldest, which is the
// order that we want.
for (unsigned I = 0; I != N; ++I)
addToChain(Reader.GetLocalDecl(M, M.RedeclarationChains[Offset++]));
}
// We found a search decl that is not from this module, but was
// imported into this module, so some imported module has more decls
// of this entity.
if (!LocalSearchDeclID)
ImportedModulesMightHaveDecls = true;
// If we found redecls for some search decl, there are no redecls for
// any other search decl for the same chain in this module.
if (MaybeOffset)
break;
}
if (LocalSearchDeclID && LocalSearchDeclID != CanonID) {
// If the search decl was from this module, add it to the chain.
// Note, the chain is sorted from newest to oldest, so this goes last.
// We exclude the canonical declaration; it implicitly goes at the end.
addToChain(Reader.GetDecl(LocalSearchDeclID));
}
// Stop looking if we know that no imported module has any declarations.
return !ImportedModulesMightHaveDecls;
}
};
}
@ -3531,15 +3538,15 @@ void ASTReader::loadPendingDeclChain(Decl *CanonDecl) {
KeyDeclsMap::iterator KeyPos = KeyDecls.find(CanonDecl);
if (KeyPos != KeyDecls.end())
SearchDecls.append(KeyPos->second.begin(), KeyPos->second.end());
llvm::array_pod_sort(SearchDecls.begin(), SearchDecls.end());
// Build up the list of redeclarations.
RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visitPreorder,
&RedeclChainVisitor::visitPostorder, &Visitor);
ModuleMgr.visit(&RedeclChainVisitor::visit, &Visitor);
// Retrieve the chains.
ArrayRef<Decl *> Chain = Visitor.getChain();
if (Chain.empty() || (Chain.size() == 1 && Chain[0] == CanonDecl))
if (Chain.empty())
return;
// Hook up the chains.
@ -3550,11 +3557,9 @@ void ASTReader::loadPendingDeclChain(Decl *CanonDecl) {
if (!MostRecent)
MostRecent = CanonDecl;
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
if (Chain[I] == CanonDecl)
continue;
ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent, CanonDecl);
MostRecent = Chain[I];
auto *D = Chain[N - I - 1];
ASTDeclReader::attachPreviousDecl(*this, D, MostRecent, CanonDecl);
MostRecent = D;
}
ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
}

View File

@ -3791,7 +3791,8 @@ void ASTWriter::WriteRedeclarations() {
unsigned Size = 0;
LocalRedeclChains.push_back(0); // Placeholder for the size.
// Collect the set of local redeclarations of this declaration.
// Collect the set of local redeclarations of this declaration, from newest
// to oldest.
for (const Decl *Prev = MostRecent; Prev;
Prev = Prev->getPreviousDecl()) {
if (!Prev->isFromASTFile() && Prev != Key) {
@ -3802,10 +3803,6 @@ void ASTWriter::WriteRedeclarations() {
LocalRedeclChains[Offset] = Size;
// Reverse the set of local redeclarations, so that we store them in
// order (since we found them in reverse order).
std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end());
// Add the mapping from the first ID from the AST to the set of local
// declarations.
LocalRedeclarationsInfo Info = { getDeclID(Key), Offset };