rnk created this revision.
rnk added reviewers: arphaman, rsmith.

RecursiveASTVisitor is very expensive to instantiate and results in
needlessly slow compilation. For these availability check fixits, we
don't need to instantiate the full complexity of the declaration walking
machinery, we can use a plain StmtVisitor.

This change reduces time to compile SemaDeclAttr.cpp and saves object
file size:

  | before   | after

time (s) | 1m7.821s | 0m52.459s
obj (kb) | 13280    | 11364

So, 15s and 1.9 MB of object file. If clang had presubmits checks, I'd
add a check that warned on new inclusions of RecursiveASTVisitor.h.  =/

I won't promise that this doesn't change functionality, since RAV walks
through quite a number of things that StmtVisitor doesn't, like blocks
and lambdas.

I noticed that SemaOpenMP has a very similar utility called
LocalVarRefChecker, so there is definitely some opportunity for
refactoring further after this.


https://reviews.llvm.org/D57208

Files:
  clang/lib/Sema/SemaDeclAttr.cpp

Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -21,6 +21,7 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/Mangle.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
@@ -8038,10 +8039,8 @@
                             ObjCPropertyAccess);
 }
 
-namespace {
-
 /// Returns true if the given statement can be a body-like child of \p Parent.
-bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
+static bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
   switch (Parent->getStmtClass()) {
   case Stmt::IfStmtClass:
     return cast<IfStmt>(Parent)->getThen() == S ||
@@ -8064,30 +8063,49 @@
   }
 }
 
-class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> {
+namespace {
+
+class StmtUSEFinder : public ConstStmtVisitor<StmtUSEFinder, bool> {
   const Stmt *Target;
 
 public:
-  bool VisitStmt(Stmt *S) { return S != Target; }
+  bool VisitStmt(const Stmt *S) {
+    if (S == Target)
+      return true;
+    for (const Stmt *Child : S->children())
+      if (Child && Visit(Child))
+        return true;
+    return false;
+  }
 
   /// Returns true if the given statement is present in the given declaration.
-  static bool isContained(const Stmt *Target, const Decl *D) {
+  /// Typically statements are contained in variable initializers.
+  static bool isContained(const Stmt *Target, const VarDecl *VD) {
     StmtUSEFinder Visitor;
     Visitor.Target = Target;
-    return !Visitor.TraverseDecl(const_cast<Decl *>(D));
+    if (const Expr *Init = VD->getInit())
+      return Visitor.Visit(Init);
+    return false;
   }
 };
 
 /// Traverses the AST and finds the last statement that used a given
 /// declaration.
-class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> {
+class LastDeclUSEFinder : public ConstStmtVisitor<LastDeclUSEFinder, bool> {
   const Decl *D;
 
 public:
-  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+  bool VisitDeclRefExpr(const DeclRefExpr *DRE) {
     if (DRE->getDecl() == D)
-      return false;
-    return true;
+      return true;
+    return false;
+  }
+
+  bool VisitStmt(const Stmt *S) {
+    for (const Stmt *Child : S->children())
+      if (Child && Visit(Child))
+        return true;
+    return false;
   }
 
   static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
@@ -8096,7 +8114,7 @@
     Visitor.D = D;
     for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; ++I) {
       const Stmt *S = *I;
-      if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
+      if (S && Visitor.Visit(S))
         return S;
     }
     return nullptr;
@@ -8272,9 +8290,12 @@
     const Stmt *LastStmtOfUse = nullptr;
     if (isa<DeclStmt>(StmtOfUse) && Scope) {
       for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
-        if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
-          LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
-          break;
+        if (const auto *VD = dyn_cast<VarDecl>(D)) {
+          if (StmtUSEFinder::isContained(StmtStack.back(), VD)) {
+            LastStmtOfUse =
+                LastDeclUSEFinder::findLastStmtThatUsesDecl(VD, Scope);
+            break;
+          }
         }
       }
     }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to