[PATCH] Implements memoization for ancestor matching.

Manuel Klimek klimek at google.com
Fri Mar 8 14:18:58 PST 2013


Hi djasper,

This yields a log(#ast_nodes) improvement with matchers like
stmt(unless(hasAncestor(...))).

http://llvm-reviews.chandlerc.com/D510

Files:
  lib/ASTMatchers/ASTMatchFinder.cpp

Index: lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -388,7 +388,8 @@
                                  const DynTypedMatcher &Matcher,
                                  BoundNodesTreeBuilder *Builder,
                                  AncestorMatchMode MatchMode) {
-    return matchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode);
+    return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder,
+                                                MatchMode);
   }
 
   // Matches all registered matchers on the given node and calls the
@@ -421,15 +422,36 @@
   bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
 
 private:
-  bool matchesAncestorOfRecursively(
+  bool memoizedMatchesAncestorOfRecursively(
       const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher,
       BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) {
     if (Node.get<TranslationUnitDecl>() ==
         ActiveASTContext->getTranslationUnitDecl())
       return false;
     assert(Node.getMemoizationData() &&
            "Invariant broken: only nodes that support memoization may be "
            "used in the parent map.");
+    const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData());
+
+    MemoizationMap::iterator I = ResultCache.find(input);
+    if (I == ResultCache.end()) {
+      BoundNodesTreeBuilder AncestorBoundNodesBuilder;
+      bool Matches = matchesAncestorOfRecursively(
+          Node, Matcher, &AncestorBoundNodesBuilder, MatchMode);
+      // Note that we cannot insert before the recursive call and keep the
+      // iterator as DenseMap invalidates iterators on insert.
+      I = ResultCache.insert(std::make_pair(input, MemoizedMatchResult()))
+          .first;
+      I->second.Nodes = AncestorBoundNodesBuilder.build();
+      I->second.ResultOfMatch = Matches;
+    }
+    I->second.Nodes.copyTo(Builder);
+    return I->second.ResultOfMatch;
+  }
+
+  bool matchesAncestorOfRecursively(
+      const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher,
+      BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) {
     ASTContext::ParentVector Parents = ActiveASTContext->getParents(Node);
     if (Parents.empty()) {
       assert(false && "Found node that is not in the parent map.");
@@ -446,13 +468,13 @@
     for (ASTContext::ParentVector::const_iterator AncestorI = Parents.begin(),
                                                   AncestorE = Parents.end();
          AncestorI != AncestorE; ++AncestorI) {
-      if (matchesAncestorOfRecursively(*AncestorI, Matcher, Builder, MatchMode))
+      if (memoizedMatchesAncestorOfRecursively(*AncestorI, Matcher, Builder,
+                                               MatchMode))
         return true;
     }
     return false;
   }
 
-
   // Implements a BoundNodesTree::Visitor that calls a MatchCallback with
   // the aggregated bound nodes for each match.
   class MatchVisitor : public BoundNodesTree::Visitor {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D510.1.patch
Type: text/x-patch
Size: 3138 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130308/d0025831/attachment.bin>


More information about the cfe-commits mailing list