r261161 - [modules] Cache 'acceptable decl' lookups for namespaces. In projects with

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 17 13:52:45 PST 2016


Author: rsmith
Date: Wed Feb 17 15:52:44 2016
New Revision: 261161

URL: http://llvm.org/viewvc/llvm-project?rev=261161&view=rev
Log:
[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.

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=261161&r1=261160&r2=261161&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Feb 17 15:52:44 2016
@@ -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.
   ///

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=261161&r1=261160&r2=261161&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Feb 17 15:52:44 2016
@@ -14826,6 +14826,9 @@ void Sema::ActOnModuleEnd(SourceLocation
     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();
   }
 }
 

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=261161&r1=261160&r2=261161&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Feb 17 15:52:44 2016
@@ -1566,6 +1566,10 @@ static NamedDecl *findAcceptableDecl(Sem
   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(Sem
 }
 
 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);
 }
 




More information about the cfe-commits mailing list