r311881 - [StaticAnalyzer] LoopUnrolling: Excluding loops which splits the state

Peter Szecsi via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 28 03:34:51 PDT 2017


Author: szepet
Date: Mon Aug 28 03:34:50 2017
New Revision: 311881

URL: http://llvm.org/viewvc/llvm-project?rev=311881&view=rev
Log:
[StaticAnalyzer] LoopUnrolling: Excluding loops which splits the state

Added check if the execution of the last step of the given unrolled loop has
generated more branches. If yes, than treat it as a normal (non-unrolled) loop
in the remaining part of the analysis.

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


Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
    cfe/trunk/test/Analysis/loop-unrolling.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp?rev=311881&r1=311880&r2=311881&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp Mon Aug 28 03:34:50 2017
@@ -204,6 +204,26 @@ bool shouldCompletelyUnroll(const Stmt *
   return !isPossiblyEscaped(CounterVar->getCanonicalDecl(), Pred);
 }
 
+bool madeNewBranch(ExplodedNode* N, const Stmt* LoopStmt) {
+  const Stmt* S = nullptr;
+  while (!N->pred_empty())
+  {
+    if (N->succ_size() > 1)
+      return true;
+
+    ProgramPoint P = N->getLocation();
+    if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>())
+      S = BE->getBlock()->getTerminator();
+
+    if (S == LoopStmt)
+      return false;
+
+    N = N->getFirstPred();
+  }
+
+  llvm_unreachable("Reached root without encountering the previous step");
+}
+
 // updateLoopStack is called on every basic block, therefore it needs to be fast
 ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
                                 ExplodedNode* Pred) {
@@ -215,8 +235,13 @@ ProgramStateRef updateLoopStack(const St
 
   auto LS = State->get<LoopStack>();
   if (!LS.isEmpty() && LoopStmt == LS.getHead().getLoopStmt() &&
-      LCtx == LS.getHead().getLocationContext())
+      LCtx == LS.getHead().getLocationContext()) {
+    if (LS.getHead().isUnrolled() && madeNewBranch(Pred, LoopStmt)) {
+      State = State->set<LoopStack>(LS.getTail());
+      State = State->add<LoopStack>(LoopState::getNormal(LoopStmt, LCtx));
+    }
     return State;
+  }
 
   if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred)) {
     State = State->add<LoopStack>(LoopState::getNormal(LoopStmt, LCtx));

Modified: cfe/trunk/test/Analysis/loop-unrolling.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/loop-unrolling.cpp?rev=311881&r1=311880&r2=311881&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/loop-unrolling.cpp (original)
+++ cfe/trunk/test/Analysis/loop-unrolling.cpp Mon Aug 28 03:34:50 2017
@@ -1,6 +1,7 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config unroll-loops=true,cfg-loopexit=true -verify -std=c++11 %s
 
 void clang_analyzer_numTimesReached();
+void clang_analyzer_warnIfReached();
 
 int getNum();
 void foo(int &);
@@ -62,8 +63,7 @@ int simple_no_unroll2() {
 int simple_no_unroll3() {
   int a[9];
   int k = 42;
-  int i;
-  for (i = 0; i < 9; i++) {
+  for (int i = 0; i < 9; i++) {
     clang_analyzer_numTimesReached(); // expected-warning {{4}}
     a[i] = 42;
     (void)&i;
@@ -98,6 +98,44 @@ int simple_no_unroll5() {
   return 0;
 }
 
+int make_new_branches_loop_cached() {
+  for (int i = 0; i < 8; i++) {
+    clang_analyzer_numTimesReached(); // expected-warning {{4}}
+    if(getNum()){
+        (void) i; // Since this Stmt does not change the State the analyzer
+                  // won't make a new execution path but reuse the earlier nodes.
+      }
+  }
+  clang_analyzer_warnIfReached(); // no-warning
+  return 0;
+}
+
+int make_new_branches_loop_uncached() {
+  int l = 2;
+  for (int i = 0; i < 8; i++) {
+    clang_analyzer_numTimesReached(); // expected-warning {{10}}
+    if(getNum()){
+      ++l;
+    }
+  }
+  clang_analyzer_warnIfReached(); // no-warning
+  return 0;
+}
+
+int make_new_branches_loop_uncached2() {
+  int l = 2;
+  for (int i = 0; i < 8; i++) {
+    clang_analyzer_numTimesReached(); // expected-warning {{10}}
+    if(getNum()){
+      ++l;
+    }
+    (void)&i; // This ensures that the loop won't be unrolled.
+  }
+  clang_analyzer_warnIfReached(); // no-warning
+  return 0;
+}
+
+
 int escape_before_loop_no_unroll1() {
   int a[9];
   int k = 42;
@@ -142,10 +180,11 @@ int nested_outer_unrolled() {
   int k = 42;
   int j = 0;
   for (int i = 0; i < 9; i++) {
-    clang_analyzer_numTimesReached(); // expected-warning {{16}}
-    for (j = 0; j < getNum(); ++j) {
-      clang_analyzer_numTimesReached(); // expected-warning {{15}}
+    clang_analyzer_numTimesReached(); // expected-warning {{1}}
+    for (j = 0; j < 9; ++j) {
+      clang_analyzer_numTimesReached(); // expected-warning {{4}}
       a[j] = 22;
+      (void) &j; // ensures that the inner loop won't be unrolled
     }
     a[i] = 42;
   }
@@ -213,8 +252,8 @@ int nested_inlined_unroll1() {
 int nested_inlined_no_unroll1() {
   int k;
   for (int i = 0; i < 9; i++) {
-    clang_analyzer_numTimesReached(); // expected-warning {{26}}
-    k = simple_unknown_bound_loop();  // reevaluation without inlining
+    clang_analyzer_numTimesReached(); // expected-warning {{15}}
+    k = simple_unknown_bound_loop();  // reevaluation without inlining, splits the state as well
   }
   int a = 22 / k; // no-warning
   return 0;
@@ -224,10 +263,11 @@ int nested_inlined_no_unroll1() {
 int recursion_unroll1(bool b) {
   int k = 2;
   for (int i = 0; i < 5; i++) {
-    clang_analyzer_numTimesReached(); // expected-warning {{14}}
-    if(i == 0 && b)
+    clang_analyzer_numTimesReached(); // expected-warning {{13}}
+    if(i == 0 && b) // Splits the state in the first iteration but the recursion
+                    // call will be unrolled anyway since the condition is known there.
       recursion_unroll1(false);
-    clang_analyzer_numTimesReached(); // expected-warning {{15}}
+    clang_analyzer_numTimesReached(); // expected-warning {{14}}
   }
   int a = 22 / k; // no-warning
   return 0;
@@ -236,10 +276,10 @@ int recursion_unroll1(bool b) {
 int recursion_unroll2(bool b) {
   int k = 0;
   for (int i = 0; i < 5; i++) {
-    clang_analyzer_numTimesReached(); // expected-warning {{10}}
+    clang_analyzer_numTimesReached(); // expected-warning {{9}}
     if(i == 0 && b)
       recursion_unroll2(false);
-    clang_analyzer_numTimesReached(); // expected-warning {{10}}
+    clang_analyzer_numTimesReached(); // expected-warning {{9}}
   }
   int a = 22 / k; // expected-warning {{Division by zero}}
   return 0;
@@ -262,12 +302,12 @@ int recursion_unroll3(bool b) {
 int recursion_unroll4(bool b) {
   int k = 2;
   for (int i = 0; i < 5; i++) {
-    clang_analyzer_numTimesReached(); // expected-warning {{14}}
+    clang_analyzer_numTimesReached(); // expected-warning {{13}}
     if(i == 0 && b) {
       recursion_unroll4(false);
       continue;
     }
-    clang_analyzer_numTimesReached(); // expected-warning {{14}}
+    clang_analyzer_numTimesReached(); // expected-warning {{13}}
   }
   int a = 22 / k;
   return 0;
@@ -279,3 +319,4 @@ int loop_exit_while_empty_loop_stack() {
       ;
   return 0;
 }
+




More information about the cfe-commits mailing list