]> granicus.if.org Git - clang/commitdiff
[AST] Cache intermediate visibility/linkage results
authorGeorge Burgess IV <george.burgess.iv@gmail.com>
Wed, 9 Aug 2017 04:12:17 +0000 (04:12 +0000)
committerGeorge Burgess IV <george.burgess.iv@gmail.com>
Wed, 9 Aug 2017 04:12:17 +0000 (04:12 +0000)
This is a follow-up to r310436 with actual functional changes. Please
see that commit message for a description of why a cache is appearing
here.

Suggestions for less-bad ways of testing this are appreciated. :)

This fixes PR29160.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@310437 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/Decl.cpp
lib/AST/Linkage.h
lib/AST/Type.cpp
test/CodeGenCXX/pr29160.cpp [new file with mode: 0644]

index 317b493ad6bb64e09b7b6f0bc3fccb4144609299..a3bb025eaa9f34e16e4cc40627dbdb7f29fb6ae7 100644 (file)
@@ -192,7 +192,7 @@ LinkageInfo LinkageComputer::getLVForType(const Type &T,
                                           LVComputationKind computation) {
   if (computation == LVForLinkageOnly)
     return LinkageInfo(T.getLinkage(), DefaultVisibility, true);
-  return T.getLinkageAndVisibility();
+  return getTypeLinkageAndVisibility(&T);
 }
 
 /// \brief Get the most restrictive linkage for the types in the given
@@ -224,7 +224,7 @@ LinkageInfo LinkageComputer::getLVForTemplateParameterList(
       for (unsigned i = 0, n = NTTP->getNumExpansionTypes(); i != n; ++i) {
         QualType type = NTTP->getExpansionType(i);
         if (!type->isDependentType())
-          LV.merge(type->getLinkageAndVisibility());
+          LV.merge(getTypeLinkageAndVisibility(type));
       }
       continue;
     }
@@ -291,7 +291,7 @@ LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
       continue;
 
     case TemplateArgument::NullPtr:
-      LV.merge(Arg.getNullPtrType()->getLinkageAndVisibility());
+      LV.merge(getTypeLinkageAndVisibility(Arg.getNullPtrType()));
       continue;
 
     case TemplateArgument::Template:
@@ -610,7 +610,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
          PrevVar = PrevVar->getPreviousDecl()) {
       if (PrevVar->getStorageClass() == SC_PrivateExtern &&
           Var->getStorageClass() == SC_None)
-        return PrevVar->getLinkageAndVisibility();
+        return getDeclLinkageAndVisibility(PrevVar);
       // Explicitly declared static.
       if (PrevVar->getStorageClass() == SC_Static)
         return getInternalLinkageFor(Var);
@@ -1358,11 +1358,15 @@ LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D,
   if (computation == LVForLinkageOnly && D->hasCachedLinkage())
     return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
 
+  if (llvm::Optional<LinkageInfo> LI = lookup(D, computation))
+    return *LI;
+
   LinkageInfo LV = computeLVForDecl(D, computation);
   if (D->hasCachedLinkage())
     assert(D->getCachedLinkage() == LV.getLinkage());
 
   D->setCachedLinkage(LV.getLinkage());
+  cache(D, computation, LV);
 
 #ifndef NDEBUG
   // In C (because of gnu inline) and in c++ with microsoft extensions an
index 592002e0894eeafec2252881dfb06531740ecb16..5f3458dfb600a9cf33495c1011a5314ff3c72b9f 100644 (file)
@@ -19,6 +19,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
 
 namespace clang {
 enum : unsigned {
@@ -54,8 +55,50 @@ enum LVComputationKind {
   LVForLinkageOnly =
       LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit
 };
+} // namespace clang
+
+namespace llvm {
+template <> struct DenseMapInfo<clang::LVComputationKind> {
+  static inline clang::LVComputationKind getEmptyKey() {
+    return static_cast<clang::LVComputationKind>(-1);
+  }
+  static inline clang::LVComputationKind getTombstoneKey() {
+    return static_cast<clang::LVComputationKind>(-2);
+  }
+  static unsigned getHashValue(const clang::LVComputationKind &Val) {
+    return Val;
+  }
+  static bool isEqual(const clang::LVComputationKind &LHS,
+                      const clang::LVComputationKind &RHS) {
+    return LHS == RHS;
+  }
+};
+} // namespace llvm
 
+namespace clang {
 class LinkageComputer {
+  // We have a cache for repeated linkage/visibility computations. This saves us
+  // from exponential behavior in heavily templated code, such as:
+  //
+  // template <typename T, typename V> struct {};
+  // using A = int;
+  // using B = Foo<A, A>;
+  // using C = Foo<B, B>;
+  // using D = Foo<C, C>;
+  using QueryType = std::pair<const NamedDecl *, LVComputationKind>;
+  llvm::SmallDenseMap<QueryType, LinkageInfo, 8> CachedLinkageInfo;
+  llvm::Optional<LinkageInfo> lookup(const NamedDecl *ND,
+                                     LVComputationKind Kind) const {
+    auto Iter = CachedLinkageInfo.find(std::make_pair(ND, Kind));
+    if (Iter == CachedLinkageInfo.end())
+      return None;
+    return Iter->second;
+  }
+
+  void cache(const NamedDecl *ND, LVComputationKind Kind, LinkageInfo Info) {
+    CachedLinkageInfo[std::make_pair(ND, Kind)] = Info;
+  }
+
   LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
                                            LVComputationKind computation);
 
index 9050e899c66f75fd4029ed541b5acc59806e6d30..93510b244f1564aa427a2b6ceddbffeb961fba2c 100644 (file)
@@ -3453,7 +3453,7 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
 
   case Type::Record:
   case Type::Enum:
-    return cast<TagType>(T)->getDecl()->getLinkageAndVisibility();
+    return getDeclLinkageAndVisibility(cast<TagType>(T)->getDecl());
 
   case Type::Complex:
     return computeTypeLinkageInfo(cast<ComplexType>(T)->getElementType());
@@ -3487,7 +3487,7 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
     return LV;
   }
   case Type::ObjCInterface:
-    return cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
+    return getDeclLinkageAndVisibility(cast<ObjCInterfaceType>(T)->getDecl());
   case Type::ObjCObject:
     return computeTypeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType());
   case Type::ObjCObjectPointer:
diff --git a/test/CodeGenCXX/pr29160.cpp b/test/CodeGenCXX/pr29160.cpp
new file mode 100644 (file)
index 0000000..9c9238e
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++11 %s -o /dev/null -S
+//
+// This test's failure mode is running ~forever. (For some value of "forever"
+// that's greater than 25 minutes on my machine)
+
+template <typename... Ts>
+struct Foo {
+  template <typename... T>
+  static void ignore() {}
+  Foo() { ignore<Ts...>(); }
+};
+
+struct Base {
+  Base();
+  ~Base();
+};
+
+#define STAMP(thiz, prev) using thiz = Foo< \
+  prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, \
+  prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, \
+  prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev \
+  >;
+STAMP(A, Base);
+STAMP(B, A);
+STAMP(C, B);
+STAMP(D, C);
+STAMP(E, D);
+STAMP(F, E);
+STAMP(G, F);
+STAMP(H, G);
+STAMP(I, H);
+STAMP(J, I);
+STAMP(K, J);
+STAMP(L, K);
+STAMP(M, L);
+STAMP(N, M);
+STAMP(O, N);
+STAMP(P, O);
+STAMP(Q, P);
+
+int main() { Q q; }