From: Anna Zaks Date: Tue, 13 Mar 2012 19:32:13 +0000 (+0000) Subject: [analyzer] Use BFS over call graph when analysing functions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7fe8dcef71ae56e43fd7df345db2895f84f2d0ca;p=clang [analyzer] Use BFS over call graph when analysing functions. BFS should give slightly better performance. Ex: Suppose, we have two roots R1 and R2. A callee function C is reachable through both. However, C is not inlined when analyzing R1 due to inline stack depth limit. With DFS, C will be analyzed as top level even though it would be analyzed as inlined through R2. On the other hand, BFS could avoid analyzing C as top level. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152652 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index a97ff4a1cd..e8903804f9 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -43,6 +43,8 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Statistic.h" +#include + using namespace clang; using namespace ento; using llvm::SmallPtrSet; @@ -282,31 +284,45 @@ void AnalysisConsumer::HandleDeclsGallGraph(TranslationUnitDecl *TU) { NumFunctionTopLevel++; } - // TODO: Sort TopLevelFunctions. + std::queue BFSQueue; + for (llvm::SmallVector::iterator + TI = TopLevelFunctions.begin(), TE = TopLevelFunctions.end(); + TI != TE; ++TI) + BFSQueue.push(*TI); - // DFS over all of the top level nodes. Use external Visited set, which is + // 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. SmallPtrSet Visited; - for (llvm::SmallVector::iterator - TI = TopLevelFunctions.begin(), TE = TopLevelFunctions.end(); - TI != TE; ++TI) { - for (llvm::df_ext_iterator > - DFI = llvm::df_ext_begin(*TI, Visited), - E = llvm::df_ext_end(*TI, Visited); - DFI != E; ++DFI) { - SetOfDecls VisitedCallees; - Decl *D = (*DFI)->getDecl(); - assert(D); - HandleCode(D, ANALYSIS_PATH, - (Mgr->InliningMode == All ? 0 : &VisitedCallees)); - - // Add the visited callees to the global visited set. - for (SetOfDecls::const_iterator I = VisitedCallees.begin(), - E = VisitedCallees.end(); I != E; ++I) { - CallGraphNode *VN = CG.getNode(*I); - if (VN) - Visited.insert(VN); - } + while(!BFSQueue.empty()) { + CallGraphNode *N = BFSQueue.front(); + BFSQueue.pop(); + + // Skip the functions which have been processed already or previously + // inlined. + if (Visited.count(N)) + continue; + + // Analyze the function. + SetOfDecls VisitedCallees; + Decl *D = N->getDecl(); + assert(D); + HandleCode(D, ANALYSIS_PATH, + (Mgr->InliningMode == All ? 0 : &VisitedCallees)); + + // Add the visited callees to the global visited set. + for (SetOfDecls::const_iterator I = VisitedCallees.begin(), + E = VisitedCallees.end(); I != E; ++I) { + CallGraphNode *VN = CG.getNode(*I); + if (VN) + Visited.insert(VN); + } + Visited.insert(N); + + // Push the children into the queue. + for (CallGraphNode::const_iterator CI = N->begin(), + CE = N->end(); CI != CE; ++CI) { + BFSQueue.push(*CI); } } }