forked from OSchip/llvm-project
[modules] Cache 'acceptable decl' lookups for namespaces. In projects with
thousands of modules, each of which declares the same namespace, linearly scanning the redecl chain looking for a visible declaration (once for each leaf module, for each use) performs very poorly. Namespace visibility can only decrease when we leave a module during a module build step, and we never care *which* visible declaration of a namespace we find, so we can cache this very effectively. This results in a 35x speedup on one of our internal build steps (2m -> 3.5s), but is hard to unit test because it requires a very large number of modules. Ideas for a test appreciated! No functionality change intended other than the speedup. llvm-svn: 261161
This commit is contained in:
parent
d4590c7304
commit
4083e038e9
|
@ -6617,6 +6617,10 @@ public:
|
|||
/// template defined within it.
|
||||
llvm::DenseSet<Module*> &getLookupModules();
|
||||
|
||||
/// \brief Map from the most recent declaration of a namespace to the most
|
||||
/// recent visible declaration of that namespace.
|
||||
llvm::DenseMap<NamedDecl*, NamedDecl*> VisibleNamespaceCache;
|
||||
|
||||
/// \brief Whether we are in a SFINAE context that is not associated with
|
||||
/// template instantiation.
|
||||
///
|
||||
|
|
|
@ -14826,6 +14826,9 @@ void Sema::ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod) {
|
|||
VisibleModules = std::move(VisibleModulesStack.back());
|
||||
VisibleModulesStack.pop_back();
|
||||
VisibleModules.setVisible(Mod, DirectiveLoc);
|
||||
// Leaving a module hides namespace names, so our visible namespace cache
|
||||
// is now out of date.
|
||||
VisibleNamespaceCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1566,6 +1566,10 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
|
|||
assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
|
||||
|
||||
for (auto RD : D->redecls()) {
|
||||
// Don't bother with extra checks if we already know this one isn't visible.
|
||||
if (RD == D)
|
||||
continue;
|
||||
|
||||
if (auto ND = dyn_cast<NamedDecl>(RD)) {
|
||||
// FIXME: This is wrong in the case where the previous declaration is not
|
||||
// visible in the same scope as D. This needs to be done much more
|
||||
|
@ -1579,6 +1583,23 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
|
|||
}
|
||||
|
||||
NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
|
||||
if (auto *ND = dyn_cast<NamespaceDecl>(D)) {
|
||||
// Namespaces are a bit of a special case: we expect there to be a lot of
|
||||
// redeclarations of some namespaces, all declarations of a namespace are
|
||||
// essentially interchangeable, all declarations are found by name lookup
|
||||
// if any is, and namespaces are never looked up during template
|
||||
// instantiation. So we benefit from caching the check in this case, and
|
||||
// it is correct to do so.
|
||||
auto *Key = ND->getCanonicalDecl();
|
||||
if (auto *Acceptable = getSema().VisibleNamespaceCache.lookup(Key))
|
||||
return Acceptable;
|
||||
auto *Acceptable =
|
||||
isVisible(getSema(), Key) ? Key : findAcceptableDecl(getSema(), Key);
|
||||
if (Acceptable)
|
||||
getSema().VisibleNamespaceCache.insert(std::make_pair(Key, Acceptable));
|
||||
return Acceptable;
|
||||
}
|
||||
|
||||
return findAcceptableDecl(getSema(), D);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue