aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/CallGraph.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-04-12 22:36:48 +0000
committerAnna Zaks <ganna@apple.com>2012-04-12 22:36:48 +0000
commit6a86082f3a06a2dcceaaf63f78a0e52d64bcbaa3 (patch)
treecf41e29ac97fff116c78975aeecda1a68594e741 /lib/Analysis/CallGraph.cpp
parent273ed9870aa064992fb3c25a1f4d8973b10ad36e (diff)
[analyzer] PCH deserialization optimization.
We should not deserialize unused declarations from the PCH file. Achieve this by storing the top level declarations during parsing (HandleTopLevelDecl ASTConsumer callback) and analyzing/building a call graph only for those. Tested the patch on a sample ObjC file that uses PCH. With the patch, the analyzes is 17.5% faster and clang consumes 40% less memory. Got about 10% overall build/analyzes time decrease on a large Objective C project. A bit of CallGraph refactoring/cleanup as well.. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154625 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CallGraph.cpp')
-rw-r--r--lib/Analysis/CallGraph.cpp93
1 files changed, 32 insertions, 61 deletions
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 01d6c41f91..96a16c3afe 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -14,35 +14,12 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/GraphWriter.h"
using namespace clang;
-/// Determine if a declaration should be included in the graph.
-static bool includeInGraph(const Decl *D) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // We skip function template definitions, as their semantics is
- // only determined when they are instantiated.
- if (!FD->isThisDeclarationADefinition() ||
- FD->isDependentContext())
- return false;
-
- IdentifierInfo *II = FD->getIdentifier();
- if (II && II->getName().startswith("__inline"))
- return false;
- }
-
- if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
- if (!ID->isThisDeclarationADefinition())
- return false;
- }
-
- return true;
-}
-
namespace {
/// A helper class, which walks the AST and locates all the call sites in the
/// given function body.
@@ -60,8 +37,8 @@ public:
void VisitCallExpr(CallExpr *CE) {
// TODO: We need to handle ObjC method calls as well.
if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
- if (includeInGraph(CalleeDecl)) {
- CallGraphNode *CalleeNode = G->getOrInsertFunction(CalleeDecl);
+ if (G->includeInGraph(CalleeDecl)) {
+ CallGraphNode *CalleeNode = G->getOrInsertNode(CalleeDecl);
CallerNode->addCallee(CalleeNode, G);
}
}
@@ -73,38 +50,10 @@ public:
}
};
-/// A helper class which walks the AST declarations.
-// TODO: We might want to specialize the visitor to shrink the call graph.
-// For example, we might not want to include the inline methods from header
-// files.
-class CGDeclVisitor : public RecursiveASTVisitor<CGDeclVisitor> {
- CallGraph *CG;
-
-public:
- CGDeclVisitor(CallGraph * InCG) : CG(InCG) {}
-
- bool VisitFunctionDecl(FunctionDecl *FD) {
- // We skip function template definitions, as their semantics is
- // only determined when they are instantiated.
- if (includeInGraph(FD))
- // If this function has external linkage, anything could call it.
- // Note, we are not precise here. For example, the function could have
- // its address taken.
- CG->addToCallGraph(FD, FD->isGlobal());
- return true;
- }
-
- bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
- if (includeInGraph(MD))
- CG->addToCallGraph(MD, true);
- return true;
- }
-};
-
} // end anonymous namespace
CallGraph::CallGraph() {
- Root = getOrInsertFunction(0);
+ Root = getOrInsertNode(0);
}
CallGraph::~CallGraph() {
@@ -116,10 +65,36 @@ CallGraph::~CallGraph() {
}
}
-void CallGraph::addToCallGraph(Decl* D, bool IsGlobal) {
+bool CallGraph::includeInGraph(const Decl *D) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // We skip function template definitions, as their semantics is
+ // only determined when they are instantiated.
+ if (!FD->isThisDeclarationADefinition() ||
+ FD->isDependentContext())
+ return false;
+
+ IdentifierInfo *II = FD->getIdentifier();
+ if (II && II->getName().startswith("__inline"))
+ return false;
+ }
+
+ if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
+ if (!ID->isThisDeclarationADefinition())
+ return false;
+ }
+
+ return true;
+}
+
+void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
assert(D);
- CallGraphNode *Node = getOrInsertFunction(D);
+ // Do nothing if the node already exists.
+ if (FunctionMap.find(D) != FunctionMap.end())
+ return;
+
+ // Allocate a new node, mark it as root, and process it's calls.
+ CallGraphNode *Node = getOrInsertNode(D);
if (IsGlobal)
Root->addCallee(Node, this);
@@ -129,17 +104,13 @@ void CallGraph::addToCallGraph(Decl* D, bool IsGlobal) {
builder.Visit(Body);
}
-void CallGraph::addToCallGraph(TranslationUnitDecl *TU) {
- CGDeclVisitor(this).TraverseDecl(TU);
-}
-
CallGraphNode *CallGraph::getNode(const Decl *F) const {
FunctionMapTy::const_iterator I = FunctionMap.find(F);
if (I == FunctionMap.end()) return 0;
return I->second;
}
-CallGraphNode *CallGraph::getOrInsertFunction(Decl *F) {
+CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
CallGraphNode *&Node = FunctionMap[F];
if (Node)
return Node;