diff options
author | Anna Zaks <ganna@apple.com> | 2012-04-12 22:36:48 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-04-12 22:36:48 +0000 |
commit | 6a86082f3a06a2dcceaaf63f78a0e52d64bcbaa3 (patch) | |
tree | cf41e29ac97fff116c78975aeecda1a68594e741 /lib/Analysis/CallGraph.cpp | |
parent | 273ed9870aa064992fb3c25a1f4d8973b10ad36e (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.cpp | 93 |
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; |