rnk created this revision.
rnk added a reviewer: hans.

I don't like this change, because I had to copy a fair amount of logic
from RAV into the dllimport visitor. However, the build time and size
results were still impressive, so I wanted to upload this and get a
second opinion. Here's the data:

| metric   | before | after | diff  |
| time (s) | 38.7   | 25.3  | -13.4 |
| obj (kb) | 12012  | 9428  | -2584 |
| exe (kb) | 86000  | 85924 | -76   |
|

Do you think I should land this as is? I'm considering factoring some of
this stuff up into a "RecursiveStmtVisitor" that tries to visit "code
that executes in a particular function scope". It could be used for
availability diagnostics that search for use of particular local
variables, etc. That seems to be the main use case we have for RAVs:
given a predicate, find all referenced decls, and check some predicate.


https://reviews.llvm.org/D57268

Files:
  clang/lib/CodeGen/CodeGenModule.cpp

Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -32,7 +32,6 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Mangle.h"
 #include "clang/AST/RecordLayout.h"
-#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/CharInfo.h"
@@ -2317,64 +2316,95 @@
 
   // Make sure we're not referencing non-imported vars or functions.
   struct DLLImportFunctionVisitor
-      : public RecursiveASTVisitor<DLLImportFunctionVisitor> {
-    bool SafeToInline = true;
-
-    bool shouldVisitImplicitCode() const { return true; }
-
-    bool VisitVarDecl(VarDecl *VD) {
-      if (VD->getTLSKind()) {
-        // A thread-local variable cannot be imported.
-        SafeToInline = false;
-        return SafeToInline;
+      : public ConstStmtVisitor<DLLImportFunctionVisitor, bool> {
+    bool VisitDeclStmt(const DeclStmt *E) {
+      for (const Decl *D : E->decls()) {
+        if (const auto *VD = dyn_cast<VarDecl>(D)) {
+          if (!VisitVarDecl(VD))
+            return false;
+          // Traverse variable initializers, which are common sources of
+          // function references.
+          if (!VisitStmt(VD->getInit()))
+            return false;
+        }
       }
+      return true;
+    }
+
+    bool VisitVarDecl(const VarDecl *VD) {
+      // A thread-local variable cannot be imported.
+      if (VD->getTLSKind())
+        return false;
 
       // A variable definition might imply a destructor call.
       if (VD->isThisDeclarationADefinition())
-        SafeToInline = !HasNonDllImportDtor(VD->getType());
+        if (HasNonDllImportDtor(VD->getType()))
+          return false;
 
-      return SafeToInline;
+      return true;
     }
 
-    bool VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+    bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) {
+      bool SafeToInline = true;
       if (const auto *D = E->getTemporary()->getDestructor())
         SafeToInline = D->hasAttr<DLLImportAttr>();
       return SafeToInline;
     }
 
-    bool VisitDeclRefExpr(DeclRefExpr *E) {
-      ValueDecl *VD = E->getDecl();
+    bool VisitDeclRefExpr(const DeclRefExpr *E) {
+      const ValueDecl *VD = E->getDecl();
+      bool SafeToInline = true;
       if (isa<FunctionDecl>(VD))
         SafeToInline = VD->hasAttr<DLLImportAttr>();
-      else if (VarDecl *V = dyn_cast<VarDecl>(VD))
+      else if (const VarDecl *V = dyn_cast<VarDecl>(VD))
         SafeToInline = !V->hasGlobalStorage() || V->hasAttr<DLLImportAttr>();
       return SafeToInline;
     }
 
-    bool VisitCXXConstructExpr(CXXConstructExpr *E) {
-      SafeToInline = E->getConstructor()->hasAttr<DLLImportAttr>();
-      return SafeToInline;
+    bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
+      return E->getConstructor()->hasAttr<DLLImportAttr>();
     }
 
-    bool VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
-      CXXMethodDecl *M = E->getMethodDecl();
-      if (!M) {
-        // Call through a pointer to member function. This is safe to inline.
-        SafeToInline = true;
-      } else {
+    bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *E) {
+      // If M is null, this is a call through a pointer to member function. This
+      // is safe to inline.
+      const CXXMethodDecl *M = E->getMethodDecl();
+      bool SafeToInline = true;
+      if (M)
         SafeToInline = M->hasAttr<DLLImportAttr>();
-      }
       return SafeToInline;
     }
 
-    bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {
-      SafeToInline = E->getOperatorDelete()->hasAttr<DLLImportAttr>();
-      return SafeToInline;
+    bool VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
+      return E->getOperatorDelete()->hasAttr<DLLImportAttr>();
     }
 
-    bool VisitCXXNewExpr(CXXNewExpr *E) {
-      SafeToInline = E->getOperatorNew()->hasAttr<DLLImportAttr>();
-      return SafeToInline;
+    bool VisitCXXNewExpr(const CXXNewExpr *E) {
+      return E->getOperatorNew()->hasAttr<DLLImportAttr>();
+    }
+
+    bool VisitStmt(const Stmt *S) {
+      if (!S)
+        return true;
+      for (const Stmt *Child : S->children())
+        if (Child && !this->Visit(Child))
+          return false;
+      return true;
+    }
+
+    static bool isSafeToInline(const FunctionDecl *FD) {
+      DLLImportFunctionVisitor Visitor;
+      if (!Visitor.Visit(FD->getBody()))
+        return false;
+
+      // We also need to check constructor initializers.
+      if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FD)) {
+        for (auto *I : Ctor->inits()) {
+          if (!Visitor.Visit(I->getInit()))
+            return false;
+        }
+      }
+      return true;
     }
   };
 }
@@ -2409,9 +2439,7 @@
 
   if (F->hasAttr<DLLImportAttr>()) {
     // Check whether it would be safe to inline this dllimport function.
-    DLLImportFunctionVisitor Visitor;
-    Visitor.TraverseFunctionDecl(const_cast<FunctionDecl*>(F));
-    if (!Visitor.SafeToInline)
+    if (!DLLImportFunctionVisitor::isSafeToInline(F))
       return false;
 
     if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(F)) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D57268: [dllimport] ... Reid Kleckner via Phabricator via cfe-commits

Reply via email to