]> granicus.if.org Git - clang/commitdiff
This feature allows the analyzer to consider loops to completely unroll. New
authorPeter Szecsi <szepet95@gmail.com>
Wed, 19 Jul 2017 23:50:00 +0000 (23:50 +0000)
committerPeter Szecsi <szepet95@gmail.com>
Wed, 19 Jul 2017 23:50:00 +0000 (23:50 +0000)
requirements/rules (for unrolling) can be added easily via ASTMatchers.

The current implementation is hidden behind a flag.

Right now the blocks which belong to an unrolled loop are marked by the
LoopVisitor which adds them to the ProgramState. Then whenever we encounter a
CFGBlock in the processCFGBlockEntrance which is marked then we skip its
investigating. That means, it won't be considered to be visited more than the
maximal bound for visiting since it won't be checked.

Differential Revision: https://reviews.llvm.org/D34260

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@308558 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
lib/StaticAnalyzer/Core/CMakeLists.txt
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/analyzer-config.c
test/Analysis/analyzer-config.cpp

index 5dd6bdf3849681fe1dd71542c5e0f935625e7b81..f8de3bcb59efc60b97c0d29c0fde64e1d5eb2737 100644 (file)
@@ -275,6 +275,9 @@ private:
   /// \sa shouldWidenLoops
   Optional<bool> WidenLoops;
 
+  /// \sa shouldUnrollLoops
+  Optional<bool> UnrollLoops;
+
   /// \sa shouldDisplayNotesAsEvents
   Optional<bool> DisplayNotesAsEvents;
 
@@ -560,7 +563,11 @@ public:
   /// This is controlled by the 'widen-loops' config option.
   bool shouldWidenLoops();
 
-  /// Returns true if the bug reporter should transparently treat extra note
+  /// Returns true if the analysis should try to unroll loops with known bounds.
+  /// This is controlled by the 'unroll-loops' config option.
+  bool shouldUnrollLoops();
+
+    /// Returns true if the bug reporter should transparently treat extra note
   /// diagnostic pieces as event diagnostic pieces. Useful when the diagnostic
   /// consumer doesn't support the extra note pieces.
   ///
index 32040e71163ddce7dcf0997087629de81cb32b04..4a581bddd9cb6d4bc7eb8d3ac7be6356f12d721c 100644 (file)
@@ -272,6 +272,7 @@ void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
 
     reportBug(llvm::to_string(NumTimesReached), BR, N);
   }
+  ReachedStats.clear();
 }
 
 void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
index 6f48fcb9e20cef9f3dd651d9d6fa19d50482d130..d5d6527f4fc5645d110fd39144ffa1d6a1f3e06f 100644 (file)
@@ -375,6 +375,12 @@ bool AnalyzerOptions::shouldWidenLoops() {
   return WidenLoops.getValue();
 }
 
+bool AnalyzerOptions::shouldUnrollLoops() {
+  if (!UnrollLoops.hasValue())
+    UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false);
+  return UnrollLoops.getValue();
+}
+
 bool AnalyzerOptions::shouldDisplayNotesAsEvents() {
   if (!DisplayNotesAsEvents.hasValue())
     DisplayNotesAsEvents =
index 85878f5e96ee7d5e658dd8fc66d3fca9b475eddb..5ac4f942f37372bad33ab79a9271f5f90249052e 100644 (file)
@@ -35,6 +35,7 @@ add_clang_library(clangStaticAnalyzerCore
   ExprEngineObjC.cpp
   FunctionSummary.cpp
   HTMLDiagnostics.cpp
+  LoopUnrolling.cpp
   LoopWidening.cpp
   MemRegion.cpp
   PathDiagnostic.cpp
@@ -54,6 +55,7 @@ add_clang_library(clangStaticAnalyzerCore
 
   LINK_LIBS
   clangAST
+  clangASTMatchers
   clangAnalysis
   clangBasic
   clangLex
index eee5400fe1771da486fe8a58161ba5f230efc29d..409fe173e263a09046dc9675878f730589619ced 100644 (file)
@@ -17,6 +17,7 @@
 #include "PrettyStackTraceLocationContext.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/ParentMap.h"
+#include "clang/Analysis/CFGStmtMap.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtObjC.h"
 #include "clang/Basic/Builtins.h"
@@ -27,6 +28,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Support/SaveAndRestore.h"
 #include "llvm/Support/raw_ostream.h"
@@ -1497,6 +1499,27 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
                                          NodeBuilderWithSinks &nodeBuilder,
                                          ExplodedNode *Pred) {
   PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
+  // If we reach a loop which has a known bound (and meets
+  // other constraints) then consider completely unrolling it.
+  if (AMgr.options.shouldUnrollLoops()) {
+    const CFGBlock *ActualBlock = nodeBuilder.getContext().getBlock();
+    const Stmt *Term = ActualBlock->getTerminator();
+    if (Term && shouldCompletelyUnroll(Term, AMgr.getASTContext())) {
+      ProgramStateRef UnrolledState =
+              markLoopAsUnrolled(Term, Pred->getState(),
+                                 Pred->getLocationContext()
+                                         ->getAnalysisDeclContext()
+                                         ->getCFGStmtMap());
+      if (UnrolledState != Pred->getState())
+        nodeBuilder.generateNode(UnrolledState, Pred);
+      return;
+    }
+
+    if (isUnrolledLoopBlock(ActualBlock, Pred))
+      return;
+    if (ActualBlock->empty())
+      return;
+  }
 
   // If this block is terminated by a loop and it has already been visited the
   // maximum number of times, widen the loop.
@@ -1664,7 +1687,6 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
   const LocationContext *LCtx = Pred->getLocationContext();
   PrettyStackTraceLocationContext StackCrashInfo(LCtx);
   currBldrCtx = &BldCtx;
-
   // Check for NULL conditions; e.g. "for(;;)"
   if (!Condition) {
     BranchNodeBuilder NullCondBldr(Pred, Dst, BldCtx, DstT, DstF);
index 0d8d34fbf6b0669b769dc29da1776d720bf8d2d4..7bed7cb5e3bade742a72114b2af32ea9cc412b1a 100644 (file)
@@ -27,6 +27,7 @@ void foo() {
 // CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
 // CHECK-NEXT: mode = deep
 // CHECK-NEXT: region-store-small-struct-limit = 2
+// CHECK-NEXT: unroll-loops = false
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 17
+// CHECK-NEXT: num-entries = 18
index 4166a730cf5353f8cad59cdb50b22f234a7a54fe..155ee02e839ee2c839fc0e4cfb7c30d9d27ceb0c 100644 (file)
@@ -38,6 +38,7 @@ public:
 // CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
 // CHECK-NEXT: mode = deep
 // CHECK-NEXT: region-store-small-struct-limit = 2
+// CHECK-NEXT: unroll-loops = false
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 22
+// CHECK-NEXT: num-entries = 23