From: Anna Zaks Date: Fri, 9 Mar 2012 21:14:01 +0000 (+0000) Subject: [analyzer] Add support for NoRedundancy inlining mode. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3fd5f370a28552976c52e76c3035d79012d78dda;p=clang [analyzer] Add support for NoRedundancy inlining mode. We do not reanalyze a function, which has already been analyzed as an inlined callee. As per PRELIMINARY testing, this gives over 50% run time reduction on some benchmarks without decreasing of the number of bugs found. Turning the mode on by default. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152440 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/AnalyzerOptions.h b/include/clang/Frontend/AnalyzerOptions.h index 90ef93621c..4199df0b6e 100644 --- a/include/clang/Frontend/AnalyzerOptions.h +++ b/include/clang/Frontend/AnalyzerOptions.h @@ -126,7 +126,7 @@ public: // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls). InlineMaxStackDepth = 5; InlineMaxFunctionSize = 200; - InliningMode = All; + InliningMode = NoRedundancy; } }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 5fba5b039b..c191a65883 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -30,6 +30,8 @@ namespace idx { namespace ento { class CheckerManager; +typedef llvm::SmallPtrSet SetOfDecls; + class AnalysisManager : public BugReporterData { virtual void anchor(); AnalysisDeclContextManager AnaCtxMgr; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index d9b613664c..18ad0078c6 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -78,6 +78,10 @@ private: /// usually because it could not reason about something. BlocksAborted blocksAborted; + /// The functions which have been analyzed through inlining. This is owned by + /// AnalysisConsumer. It can be null. + SetOfDecls *AnalyzedCallees; + void generateNode(const ProgramPoint &Loc, ProgramStateRef State, ExplodedNode *Pred); @@ -102,17 +106,11 @@ private: public: /// Construct a CoreEngine object to analyze the provided CFG using /// a DFS exploration of the exploded graph. - CoreEngine(SubEngine& subengine) + CoreEngine(SubEngine& subengine, SetOfDecls *VisitedCallees) : SubEng(subengine), G(new ExplodedGraph()), WList(WorkList::makeBFS()), - BCounterFactory(G->getAllocator()) {} - - /// Construct a CoreEngine object to analyze the provided CFG and to - /// use the provided worklist object to execute the worklist algorithm. - /// The CoreEngine object assumes ownership of 'wlist'. - CoreEngine(WorkList* wlist, SubEngine& subengine) - : SubEng(subengine), G(new ExplodedGraph()), WList(wlist), - BCounterFactory(G->getAllocator()) {} + BCounterFactory(G->getAllocator()), + AnalyzedCallees(VisitedCallees) {} ~CoreEngine() { delete WList; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 6016ee1ec4..5714a7edde 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -89,7 +89,7 @@ class ExprEngine : public SubEngine { GRBugReporter BR; public: - ExprEngine(AnalysisManager &mgr, bool gcEnabled); + ExprEngine(AnalysisManager &mgr, bool gcEnabled, SetOfDecls *VisitedCallees); ~ExprEngine(); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 8900906b17..7f7f35cc09 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -138,7 +138,7 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-ipa"); Res.push_back(getAnalysisIPAModeName(Opts.IPAMode)); } - if (Opts.InliningMode != All) { + if (Opts.InliningMode != NoRedundancy) { Res.push_back("-analyzer-inlining-mode"); Res.push_back(getAnalysisInliningModeName(Opts.InliningMode)); } diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index e7c3d2a3b3..a350757a0f 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -214,9 +214,16 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, assert (false && "BlockExit location never occur in forward analysis."); break; - case ProgramPoint::CallEnterKind: - SubEng.processCallEnter(cast(Node->getLocation()), Node); + case ProgramPoint::CallEnterKind: { + CallEnter CEnter = cast(Node->getLocation()); + if (AnalyzedCallees) + if (const CallExpr* CE = + dyn_cast_or_null(CEnter.getCallExpr())) + if (const Decl *CD = CE->getCalleeDecl()) + AnalyzedCallees->insert(CD); + SubEng.processCallEnter(CEnter, Node); break; + } case ProgramPoint::CallExitKind: SubEng.processCallExit(Node); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index d19cc9c7d3..63027175ca 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -57,10 +57,11 @@ static inline Selector GetNullarySelector(const char* name, ASTContext &Ctx) { // Engine construction and deletion. //===----------------------------------------------------------------------===// -ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled) +ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled, + SetOfDecls *VisitedCallees) : AMgr(mgr), AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()), - Engine(*this), + Engine(*this, VisitedCallees), G(Engine.getGraph()), StateMgr(getContext(), mgr.getStoreManagerCreator(), mgr.getConstraintManagerCreator(), G.getAllocator(), diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index e126657eb9..51761fb151 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -48,6 +48,7 @@ using llvm::SmallPtrSet; static ExplodedNode::Auditor* CreateUbiViz(); +STATISTIC(NumFunctionTopLevel, "The # of functions at top level."); STATISTIC(NumFunctionsAnalyzed, "The # of functions analysed (as top level)."); //===----------------------------------------------------------------------===// @@ -189,7 +190,9 @@ public: void HandleDeclContextDecl(ASTContext &C, Decl *D); void HandleDeclContextDeclFunction(ASTContext &C, Decl *D); - void HandleCode(Decl *D); + void HandleCode(Decl *D, SetOfDecls *VisitedCallees = 0); + void RunPathSensitiveChecks(Decl *D, SetOfDecls *VisitedCallees); + void ActionExprEngine(Decl *D, bool ObjCGCEnabled, SetOfDecls *VisitedCallees); }; } // end anonymous namespace @@ -219,15 +222,18 @@ void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) { // Find the top level nodes - children of root + the unreachable (parentless) // nodes. - llvm::SmallVector TopLevelFunctions; + llvm::SmallVector TopLevelFunctions; CallGraphNode *Entry = CG.getRoot(); for (CallGraphNode::iterator I = Entry->begin(), - E = Entry->end(); I != E; ++I) + E = Entry->end(); I != E; ++I) { TopLevelFunctions.push_back(*I); - + NumFunctionTopLevel++; + } for (CallGraph::nodes_iterator TI = CG.parentless_begin(), - TE = CG.parentless_end(); TI != TE; ++TI) + TE = CG.parentless_end(); TI != TE; ++TI) { TopLevelFunctions.push_back(*TI); + NumFunctionTopLevel++; + } // TODO: Sort TopLevelFunctions. @@ -241,12 +247,20 @@ void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) { 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); + HandleCode(D, (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); + } } } - } void AnalysisConsumer::HandleDeclContextDecl(ASTContext &C, Decl *D) { @@ -284,6 +298,9 @@ void AnalysisConsumer::HandleDeclContextDeclFunction(ASTContext &C, Decl *D) { case Decl::CXXMethod: case Decl::Function: { FunctionDecl *FD = cast(D); + IdentifierInfo *II = FD->getIdentifier(); + if (II && II->getName().startswith("__inline")) + break; // We skip function template definitions, as their semantics is // only determined when they are instantiated. if (FD->isThisDeclarationADefinition() && @@ -350,9 +367,6 @@ static void FindBlocks(DeclContext *D, SmallVectorImpl &WL) { FindBlocks(DC, WL); } -static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr, - Decl *D); - static std::string getFunctionName(const Decl *D) { if (const ObjCMethodDecl *ID = dyn_cast(D)) { return ID->getSelector().getAsString(); @@ -365,7 +379,7 @@ static std::string getFunctionName(const Decl *D) { return ""; } -void AnalysisConsumer::HandleCode(Decl *D) { +void AnalysisConsumer::HandleCode(Decl *D, SetOfDecls *VisitedCallees) { if (!Opts.AnalyzeSpecificFunction.empty() && getFunctionName(D) != Opts.AnalyzeSpecificFunction) return; @@ -400,7 +414,7 @@ void AnalysisConsumer::HandleCode(Decl *D) { if ((*WI)->hasBody()) { checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR); if (checkerMgr->hasPathSensitiveCheckers()) - RunPathSensitiveChecks(*this, *Mgr, *WI); + RunPathSensitiveChecks(*WI, VisitedCallees); } NumFunctionsAnalyzed++; } @@ -409,52 +423,52 @@ void AnalysisConsumer::HandleCode(Decl *D) { // Path-sensitive checking. //===----------------------------------------------------------------------===// -static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager &mgr, - Decl *D, bool ObjCGCEnabled) { +void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled, + SetOfDecls *VisitedCallees) { // Construct the analysis engine. First check if the CFG is valid. // FIXME: Inter-procedural analysis will need to handle invalid CFGs. - if (!mgr.getCFG(D)) + if (!Mgr->getCFG(D)) return; - ExprEngine Eng(mgr, ObjCGCEnabled); + + ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees); // Set the graph auditor. OwningPtr Auditor; - if (mgr.shouldVisualizeUbigraph()) { + if (Mgr->shouldVisualizeUbigraph()) { Auditor.reset(CreateUbiViz()); ExplodedNode::SetAuditor(Auditor.get()); } // Execute the worklist algorithm. - Eng.ExecuteWorkList(mgr.getAnalysisDeclContextManager().getStackFrame(D, 0), - mgr.getMaxNodes()); + Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D, 0), + Mgr->getMaxNodes()); // Release the auditor (if any) so that it doesn't monitor the graph // created BugReporter. ExplodedNode::SetAuditor(0); // Visualize the exploded graph. - if (mgr.shouldVisualizeGraphviz()) - Eng.ViewGraph(mgr.shouldTrimGraph()); + if (Mgr->shouldVisualizeGraphviz()) + Eng.ViewGraph(Mgr->shouldTrimGraph()); // Display warnings. Eng.getBugReporter().FlushReports(); } -static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr, - Decl *D) { +void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, SetOfDecls *Visited) { - switch (mgr.getLangOptions().getGC()) { + switch (Mgr->getLangOptions().getGC()) { case LangOptions::NonGC: - ActionExprEngine(C, mgr, D, false); + ActionExprEngine(D, false, Visited); break; case LangOptions::GCOnly: - ActionExprEngine(C, mgr, D, true); + ActionExprEngine(D, true, Visited); break; case LangOptions::HybridGC: - ActionExprEngine(C, mgr, D, false); - ActionExprEngine(C, mgr, D, true); + ActionExprEngine(D, false, Visited); + ActionExprEngine(D, true, Visited); break; } }