summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Szecsi <szepet95@gmail.com>2017-08-28 10:34:50 +0000
committerPeter Szecsi <szepet95@gmail.com>2017-08-28 10:34:50 +0000
commitd0604acd8ebb8e4d99b025f215ffa4b41ec979ce (patch)
tree8044c51e17b3f69cdb54f67fcd922cef95a092ef
parentd91554bc91a493b9b83572d7e933847ebeb3d5a6 (diff)
downloadbcm5719-llvm-d0604acd8ebb8e4d99b025f215ffa4b41ec979ce.tar.gz
bcm5719-llvm-d0604acd8ebb8e4d99b025f215ffa4b41ec979ce.zip
[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 llvm-svn: 311881
-rw-r--r--clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp27
-rw-r--r--clang/test/Analysis/loop-unrolling.cpp69
2 files changed, 81 insertions, 15 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
index 7db628aa077..7b52dd6ca43 100644
--- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -204,6 +204,26 @@ bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx,
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 Stmt *LoopStmt, ASTContext &ASTCtx,
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));
diff --git a/clang/test/Analysis/loop-unrolling.cpp b/clang/test/Analysis/loop-unrolling.cpp
index 6328bd939c0..5c858d35f71 100644
--- a/clang/test/Analysis/loop-unrolling.cpp
+++ b/clang/test/Analysis/loop-unrolling.cpp
@@ -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;
}
+
OpenPOWER on IntegriCloud