From: Rafael Espindola Date: Fri, 21 Dec 2012 01:30:23 +0000 (+0000) Subject: Revert r170826. The output of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6d42f4d8b8a176336a8c49ec3cf5f7fb6545ccfd;p=clang Revert r170826. The output of ./bin/clang -cc1 -internal-isystem /home/espindola/llvm/build/lib/clang/3.3/include/ -analyze -analyzer-checker=debug.DumpCallGraph /home/espindola/llvm/clang/test/Analysis/debug-CallGraph.c -fblocks changes in each run. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170829 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h index a47cf1358b..d554f3a7af 100644 --- a/include/clang/Analysis/CallGraph.h +++ b/include/clang/Analysis/CallGraph.h @@ -39,9 +39,15 @@ class CallGraph : public RecursiveASTVisitor { /// FunctionMap owns all CallGraphNodes. FunctionMapTy FunctionMap; - /// This is a virtual root node that has edges to all the functions. + /// This is a virtual root node that has edges to all the global functions - + /// 'main' or functions accessible from other translation units. CallGraphNode *Root; + /// The list of nodes that have no parent. These are unreachable from Root. + /// Declarations can get to this list due to impressions in the graph, for + /// example, we do not track functions whose addresses were taken. + llvm::SetVector ParentlessNodes; + public: CallGraph(); ~CallGraph(); @@ -85,6 +91,12 @@ public: /// failing to add a call edge due to the analysis imprecision. typedef llvm::SetVector::iterator nodes_iterator; typedef llvm::SetVector::const_iterator const_nodes_iterator; + nodes_iterator parentless_begin() { return ParentlessNodes.begin(); } + nodes_iterator parentless_end() { return ParentlessNodes.end(); } + const_nodes_iterator + parentless_begin() const { return ParentlessNodes.begin(); } + const_nodes_iterator + parentless_end() const { return ParentlessNodes.end(); } void print(raw_ostream &os) const; void dump() const; @@ -158,6 +170,7 @@ public: void addCallee(CallGraphNode *N, CallGraph *CG) { CalledFunctions.push_back(N); + CG->ParentlessNodes.remove(N); } Decl *getDecl() const { return FD; } diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp index 853e0f9df7..424e5c795e 100644 --- a/lib/Analysis/CallGraph.cpp +++ b/lib/Analysis/CallGraph.cpp @@ -141,8 +141,14 @@ bool CallGraph::includeInGraph(const Decl *D) { void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) { assert(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); // Process all the calls by this function as well. CGBuilder builder(this, Node); @@ -162,9 +168,9 @@ CallGraphNode *CallGraph::getOrInsertNode(Decl *F) { return Node; Node = new CallGraphNode(F); - // Make Root node a parent of all functions to make sure all are reachable. + // If not root, add to the parentless list. if (F != 0) - Root->addCallee(Node, this); + ParentlessNodes.insert(Node); return Node; } diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index ff48bfdd58..025891adf8 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -39,7 +39,6 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" -#include "llvm/ADT/PostOrderIterator.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Support/Timer.h" @@ -418,34 +417,61 @@ AnalysisConsumer::getInliningModeForFunction(const Decl *D, } void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) { - // Build the Call Graph by adding all the top level declarations to the graph. + // Otherwise, use the Callgraph to derive the order. + // Build the Call Graph. + CallGraph CG; + + // Add all the top level declarations to the graph. // Note: CallGraph can trigger deserialization of more items from a pch // (though HandleInterestingDecl); triggering additions to LocalTUDecls. // We rely on random access to add the initially processed Decls to CG. - CallGraph CG; for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) { CG.addToCallGraph(LocalTUDecls[i]); } - // Walk over all of the call graph nodes in topological order, so that we - // analyze parents before the children. Skip the functions inlined into - // the previously processed functions. Use external Visited set to identify - // inlined functions. The topological order allows the "do not reanalyze - // previously inlined function" performance heuristic to be triggered more - // often. + // Find the top level nodes - children of root + the unreachable (parentless) + // nodes. + llvm::SmallVector TopLevelFunctions; + for (CallGraph::nodes_iterator TI = CG.parentless_begin(), + TE = CG.parentless_end(); TI != TE; ++TI) { + TopLevelFunctions.push_back(*TI); + NumFunctionTopLevel++; + } + CallGraphNode *Entry = CG.getRoot(); + for (CallGraphNode::iterator I = Entry->begin(), + E = Entry->end(); I != E; ++I) { + TopLevelFunctions.push_back(*I); + NumFunctionTopLevel++; + } + + // Make sure the nodes are sorted in order reverse of their definition in the + // translation unit. This step is very important for performance. It ensures + // that we analyze the root functions before the externally available + // subroutines. + std::deque BFSQueue; + for (llvm::SmallVector::reverse_iterator + TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend(); + TI != TE; ++TI) + BFSQueue.push_back(*TI); + + // BFS over all of the functions, while skipping the ones inlined into + // the previously processed functions. Use external Visited set, which is + // also modified when we inline a function. SetOfConstDecls Visited; SetOfConstDecls VisitedAsTopLevel; - llvm::ReversePostOrderTraversal RPOT(&CG); - for (llvm::ReversePostOrderTraversal::rpo_iterator - I = RPOT.begin(); I != RPOT.end(); ++I) { - NumFunctionTopLevel++; + while(!BFSQueue.empty()) { + CallGraphNode *N = BFSQueue.front(); + BFSQueue.pop_front(); + + // Push the children into the queue. + for (CallGraphNode::const_iterator CI = N->begin(), + CE = N->end(); CI != CE; ++CI) { + if (!shouldSkipFunction((*CI)->getDecl(), Visited, VisitedAsTopLevel)) + BFSQueue.push_back(*CI); + } - CallGraphNode *N = *I; Decl *D = N->getDecl(); - - // Skip the abstract root node. - if (!D) - continue; + assert(D); // Skip the functions which have been processed already or previously // inlined. diff --git a/test/Analysis/debug-CallGraph.c b/test/Analysis/debug-CallGraph.c index 021a468644..b7c7c8a844 100644 --- a/test/Analysis/debug-CallGraph.c +++ b/test/Analysis/debug-CallGraph.c @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCallGraph %s -fblocks 2>&1 | FileCheck %s +// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCallGraph %s 2>&1 | FileCheck %s static void mmm(int y) { if (y != 0) y++; - y = y/y; + y = y/0; } static int foo(int x, int y) { @@ -17,17 +17,5 @@ void aaa() { foo(1,2); } -void bbb(int y) { - int x = (y > 2); - ^ { - foo(x, y); - }(); -} - // CHECK:--- Call graph Dump --- -// CHECK: Function: < root > calls: mmm foo aaa < > bbb -// CHECK: Function: bbb calls: < > -// CHECK: Function: mmm calls: -// CHECK: Function: aaa calls: foo -// CHECK: Function: foo calls: mmm -// CHECK: Function: < > calls: foo +// CHECK: Function: < root > calls: aaa