]> granicus.if.org Git - clang/commitdiff
[analyzer] Add support for NoRedundancy inlining mode.
authorAnna Zaks <ganna@apple.com>
Fri, 9 Mar 2012 21:14:01 +0000 (21:14 +0000)
committerAnna Zaks <ganna@apple.com>
Fri, 9 Mar 2012 21:14:01 +0000 (21:14 +0000)
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

include/clang/Frontend/AnalyzerOptions.h
include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
lib/Frontend/CompilerInvocation.cpp
lib/StaticAnalyzer/Core/CoreEngine.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp

index 90ef93621c0bff09ecff96112fb167e9bab51804..4199df0b6eb752acf00195420ed05b9c0d836564 100644 (file)
@@ -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;
   }
 };
 
index 5fba5b039b8b937d731307bd7a8803d8b02f05c8..c191a658830bbf3dba01b3ad909110a9b3d1203d 100644 (file)
@@ -30,6 +30,8 @@ namespace idx {
 namespace ento {
   class CheckerManager;
 
+typedef llvm::SmallPtrSet<const Decl*,24> SetOfDecls;
+
 class AnalysisManager : public BugReporterData {
   virtual void anchor();
   AnalysisDeclContextManager AnaCtxMgr;
index d9b613664cbba3e8e83976b1a8235688513843cd..18ad0078c6abb88199065f3a658ac1313800a52f 100644 (file)
@@ -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;
index 6016ee1ec4a053f1861f31dc983d23cbd9c2aec5..5714a7edde08b566a4e2a8e7ff1f256060c18091 100644 (file)
@@ -89,7 +89,7 @@ class ExprEngine : public SubEngine {
   GRBugReporter BR;
 
 public:
-  ExprEngine(AnalysisManager &mgr, bool gcEnabled);
+  ExprEngine(AnalysisManager &mgr, bool gcEnabled, SetOfDecls *VisitedCallees);
 
   ~ExprEngine();
 
index 8900906b17b4e3b524165871167931a417b91a03..7f7f35cc09935161d366f2a1982728166345cd7a 100644 (file)
@@ -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));
   }
index e7c3d2a3b3591a43dc0373b8f2dd25ed36b703f6..a350757a0f1854e57d77dcdc9892875fd5130f90 100644 (file)
@@ -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<CallEnter>(Node->getLocation()), Node);
+      case ProgramPoint::CallEnterKind: {
+        CallEnter CEnter = cast<CallEnter>(Node->getLocation());
+        if (AnalyzedCallees)
+          if (const CallExpr* CE =
+              dyn_cast_or_null<CallExpr>(CEnter.getCallExpr()))
+            if (const Decl *CD = CE->getCalleeDecl())
+              AnalyzedCallees->insert(CD);
+        SubEng.processCallEnter(CEnter, Node);
         break;
+      }
 
       case ProgramPoint::CallExitKind:
         SubEng.processCallExit(Node);
index d19cc9c7d3d38af46fd42d37a3fa0b5b7d0f45e7..63027175cad400b7b51370747f9475378e1b7a19 100644 (file)
@@ -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(),
index e126657eb945d1b508b91250cf4f3e4a6c8d2827..51761fb1512b60b55faa0fdbab35e7f5606e4fbf 100644 (file)
@@ -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<CallGraphNode*, 24>  TopLevelFunctions;
+  llvm::SmallVector<CallGraphNode*, 24> 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<FunctionDecl>(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<Decl*> &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<ObjCMethodDecl>(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<ExplodedNode::Auditor> 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;
   }
 }