[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
This commit is contained in:
parent
d91554bc91
commit
d0604acd8e
|
@ -204,6 +204,26 @@ bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx,
|
||||||
return !isPossiblyEscaped(CounterVar->getCanonicalDecl(), Pred);
|
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
|
// updateLoopStack is called on every basic block, therefore it needs to be fast
|
||||||
ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
|
ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
|
||||||
ExplodedNode* Pred) {
|
ExplodedNode* Pred) {
|
||||||
|
@ -215,8 +235,13 @@ ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
|
||||||
|
|
||||||
auto LS = State->get<LoopStack>();
|
auto LS = State->get<LoopStack>();
|
||||||
if (!LS.isEmpty() && LoopStmt == LS.getHead().getLoopStmt() &&
|
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;
|
return State;
|
||||||
|
}
|
||||||
|
|
||||||
if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred)) {
|
if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred)) {
|
||||||
State = State->add<LoopStack>(LoopState::getNormal(LoopStmt, LCtx));
|
State = State->add<LoopStack>(LoopState::getNormal(LoopStmt, LCtx));
|
||||||
|
|
|
@ -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
|
// 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_numTimesReached();
|
||||||
|
void clang_analyzer_warnIfReached();
|
||||||
|
|
||||||
int getNum();
|
int getNum();
|
||||||
void foo(int &);
|
void foo(int &);
|
||||||
|
@ -62,8 +63,7 @@ int simple_no_unroll2() {
|
||||||
int simple_no_unroll3() {
|
int simple_no_unroll3() {
|
||||||
int a[9];
|
int a[9];
|
||||||
int k = 42;
|
int k = 42;
|
||||||
int i;
|
for (int i = 0; i < 9; i++) {
|
||||||
for (i = 0; i < 9; i++) {
|
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
||||||
a[i] = 42;
|
a[i] = 42;
|
||||||
(void)&i;
|
(void)&i;
|
||||||
|
@ -98,6 +98,44 @@ int simple_no_unroll5() {
|
||||||
return 0;
|
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 escape_before_loop_no_unroll1() {
|
||||||
int a[9];
|
int a[9];
|
||||||
int k = 42;
|
int k = 42;
|
||||||
|
@ -142,10 +180,11 @@ int nested_outer_unrolled() {
|
||||||
int k = 42;
|
int k = 42;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{16}}
|
clang_analyzer_numTimesReached(); // expected-warning {{1}}
|
||||||
for (j = 0; j < getNum(); ++j) {
|
for (j = 0; j < 9; ++j) {
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{15}}
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
||||||
a[j] = 22;
|
a[j] = 22;
|
||||||
|
(void) &j; // ensures that the inner loop won't be unrolled
|
||||||
}
|
}
|
||||||
a[i] = 42;
|
a[i] = 42;
|
||||||
}
|
}
|
||||||
|
@ -213,8 +252,8 @@ int nested_inlined_unroll1() {
|
||||||
int nested_inlined_no_unroll1() {
|
int nested_inlined_no_unroll1() {
|
||||||
int k;
|
int k;
|
||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{26}}
|
clang_analyzer_numTimesReached(); // expected-warning {{15}}
|
||||||
k = simple_unknown_bound_loop(); // reevaluation without inlining
|
k = simple_unknown_bound_loop(); // reevaluation without inlining, splits the state as well
|
||||||
}
|
}
|
||||||
int a = 22 / k; // no-warning
|
int a = 22 / k; // no-warning
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -224,10 +263,11 @@ int nested_inlined_no_unroll1() {
|
||||||
int recursion_unroll1(bool b) {
|
int recursion_unroll1(bool b) {
|
||||||
int k = 2;
|
int k = 2;
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{14}}
|
clang_analyzer_numTimesReached(); // expected-warning {{13}}
|
||||||
if(i == 0 && b)
|
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);
|
recursion_unroll1(false);
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{15}}
|
clang_analyzer_numTimesReached(); // expected-warning {{14}}
|
||||||
}
|
}
|
||||||
int a = 22 / k; // no-warning
|
int a = 22 / k; // no-warning
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -236,10 +276,10 @@ int recursion_unroll1(bool b) {
|
||||||
int recursion_unroll2(bool b) {
|
int recursion_unroll2(bool b) {
|
||||||
int k = 0;
|
int k = 0;
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{10}}
|
clang_analyzer_numTimesReached(); // expected-warning {{9}}
|
||||||
if(i == 0 && b)
|
if(i == 0 && b)
|
||||||
recursion_unroll2(false);
|
recursion_unroll2(false);
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{10}}
|
clang_analyzer_numTimesReached(); // expected-warning {{9}}
|
||||||
}
|
}
|
||||||
int a = 22 / k; // expected-warning {{Division by zero}}
|
int a = 22 / k; // expected-warning {{Division by zero}}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -262,12 +302,12 @@ int recursion_unroll3(bool b) {
|
||||||
int recursion_unroll4(bool b) {
|
int recursion_unroll4(bool b) {
|
||||||
int k = 2;
|
int k = 2;
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{14}}
|
clang_analyzer_numTimesReached(); // expected-warning {{13}}
|
||||||
if(i == 0 && b) {
|
if(i == 0 && b) {
|
||||||
recursion_unroll4(false);
|
recursion_unroll4(false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
clang_analyzer_numTimesReached(); // expected-warning {{14}}
|
clang_analyzer_numTimesReached(); // expected-warning {{13}}
|
||||||
}
|
}
|
||||||
int a = 22 / k;
|
int a = 22 / k;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -279,3 +319,4 @@ int loop_exit_while_empty_loop_stack() {
|
||||||
;
|
;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue