The loop unrolling feature aims to track the maximum possible steps a loop can make. In order to implement this, it investigates the initial value of the counter variable and the bound number. (It has to be known.) These numbers are used as llvm::APInts, however, it was not checked if their bitwidths are the same which lead to some crashes. This revision solves this problem by extending the "shorter" one (to the length of the "longer" one). For the detailed bug report, see: https://bugs.llvm.org/show_bug.cgi?id=34943 Differential Revision: https://reviews.llvm.org/D38922 llvm-svn: 316830
382 lines
8.7 KiB
C++
382 lines
8.7 KiB
C++
// 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 &);
|
|
|
|
int simple_unroll1() {
|
|
int a[9];
|
|
int k = 42;
|
|
for (int i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{9}}
|
|
a[i] = 42;
|
|
}
|
|
int b = 22 / (k - 42); // expected-warning {{Division by zero}}
|
|
return 0;
|
|
}
|
|
|
|
int simple_unroll2() {
|
|
int a[9];
|
|
int k = 42;
|
|
int i;
|
|
for (i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{9}}
|
|
a[i] = 42;
|
|
}
|
|
|
|
for (int j = 0; j <= 9; ++j) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{10}}
|
|
a[j] = 42;
|
|
}
|
|
|
|
int b = 22 / (k - 42); // expected-warning {{Division by zero}}
|
|
return 0;
|
|
}
|
|
|
|
int simple_no_unroll1() {
|
|
int a[9];
|
|
int k = 42;
|
|
for (int i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
a[i] = 42;
|
|
foo(i);
|
|
}
|
|
int b = 22 / (k - 42); // expected-warning {{Division by zero}}
|
|
return 0;
|
|
}
|
|
|
|
int simple_no_unroll2() {
|
|
int a[9];
|
|
int k = 42;
|
|
int i;
|
|
for (i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
a[i] = 42;
|
|
i += getNum();
|
|
}
|
|
int b = 22 / (k - 42); // expected-warning {{Division by zero}}
|
|
return 0;
|
|
}
|
|
|
|
int simple_no_unroll3() {
|
|
int a[9];
|
|
int k = 42;
|
|
for (int i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
a[i] = 42;
|
|
(void)&i;
|
|
}
|
|
int b = 22 / (k - 42); // no-warning
|
|
return 0;
|
|
}
|
|
|
|
int simple_no_unroll4() {
|
|
int a[9];
|
|
int k = 42;
|
|
int i;
|
|
for (i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
a[i] = 42;
|
|
int &j = i;
|
|
}
|
|
int b = 22 / (k - 42); // no-warning
|
|
return 0;
|
|
}
|
|
|
|
int simple_no_unroll5() {
|
|
int a[9];
|
|
int k = 42;
|
|
int i;
|
|
for (i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
a[i] = 42;
|
|
int &j{i};
|
|
}
|
|
int b = 22 / (k - 42); // no-warning
|
|
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;
|
|
int i;
|
|
int &j = i;
|
|
for (i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
a[i] = 42;
|
|
}
|
|
int b = 22 / (k - 42); // no-warning
|
|
return 0;
|
|
}
|
|
|
|
int escape_before_loop_no_unroll2() {
|
|
int a[9];
|
|
int k = 42;
|
|
int i;
|
|
int *p = &i;
|
|
for (i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
a[i] = 42;
|
|
}
|
|
int b = 22 / (k - 42); // no-warning
|
|
return 0;
|
|
}
|
|
|
|
int escape_before_loop_no_unroll3() {
|
|
int a[9];
|
|
int k = 42;
|
|
int i;
|
|
foo(i);
|
|
for (i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
a[i] = 42;
|
|
}
|
|
int b = 22 / (k - 42); // no-warning
|
|
return 0;
|
|
}
|
|
|
|
int nested_outer_unrolled() {
|
|
int a[9];
|
|
int k = 42;
|
|
int j = 0;
|
|
for (int i = 0; i < 9; i++) {
|
|
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;
|
|
}
|
|
int b = 22 / (k - 42); // no-warning
|
|
return 0;
|
|
}
|
|
|
|
int nested_inner_unrolled() {
|
|
int a[9];
|
|
int k = 42;
|
|
int j = 0;
|
|
for (int i = 0; i < getNum(); i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
for (j = 0; j < 8; ++j) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{32}}
|
|
a[j] = 22;
|
|
}
|
|
a[i] = 42;
|
|
}
|
|
int b = 22 / (k - 42); // expected-warning {{Division by zero}}
|
|
return 0;
|
|
}
|
|
|
|
int nested_both_unrolled() {
|
|
int a[9];
|
|
int k = 42;
|
|
int j = 0;
|
|
for (int i = 0; i < 7; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{7}}
|
|
for (j = 0; j < 6; ++j) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{42}}
|
|
a[j] = 22;
|
|
}
|
|
a[i] = 42;
|
|
}
|
|
int b = 22 / (k - 42); // expected-warning {{Division by zero}}
|
|
return 0;
|
|
}
|
|
|
|
int simple_known_bound_loop() {
|
|
for (int i = 2; i < 12; i++) {
|
|
// This function is inlined in nested_inlined_unroll1()
|
|
clang_analyzer_numTimesReached(); // expected-warning {{90}}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int simple_unknown_bound_loop() {
|
|
for (int i = 2; i < getNum(); i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{10}}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int nested_inlined_unroll1() {
|
|
int k;
|
|
for (int i = 0; i < 9; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{9}}
|
|
k = simple_known_bound_loop(); // no reevaluation without inlining
|
|
}
|
|
int a = 22 / k; // expected-warning {{Division by zero}}
|
|
return 0;
|
|
}
|
|
|
|
int nested_inlined_no_unroll1() {
|
|
int k;
|
|
for (int i = 0; i < 9; i++) {
|
|
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;
|
|
}
|
|
|
|
int recursion_unroll1(bool b) {
|
|
int k = 2;
|
|
for (int i = 0; i < 5; i++) {
|
|
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 {{14}}
|
|
}
|
|
int a = 22 / k; // no-warning
|
|
return 0;
|
|
}
|
|
|
|
int recursion_unroll2(bool b) {
|
|
int k = 0;
|
|
for (int i = 0; i < 5; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{9}}
|
|
if(i == 0 && b)
|
|
recursion_unroll2(false);
|
|
clang_analyzer_numTimesReached(); // expected-warning {{9}}
|
|
}
|
|
int a = 22 / k; // expected-warning {{Division by zero}}
|
|
return 0;
|
|
}
|
|
|
|
int recursion_unroll3(bool b) {
|
|
int k = 2;
|
|
for (int i = 0; i < 5; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{10}}
|
|
if (i == 4 && b) {
|
|
recursion_unroll3(false);
|
|
break;
|
|
}
|
|
clang_analyzer_numTimesReached(); // expected-warning {{10}}
|
|
}
|
|
int a = 22 / k;
|
|
return 0;
|
|
}
|
|
|
|
int recursion_unroll4(bool b) {
|
|
int k = 2;
|
|
for (int i = 0; i < 5; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{13}}
|
|
if(i == 0 && b) {
|
|
recursion_unroll4(false);
|
|
continue;
|
|
}
|
|
clang_analyzer_numTimesReached(); // expected-warning {{13}}
|
|
}
|
|
int a = 22 / k;
|
|
return 0;
|
|
}
|
|
|
|
int loop_exit_while_empty_loop_stack() {
|
|
if (getNum())
|
|
for (int i = 1; i < 8; i++)
|
|
;
|
|
return 0;
|
|
}
|
|
|
|
int num_steps_on_limit() {
|
|
for (int i = 0; i < 128; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{128}}
|
|
}
|
|
clang_analyzer_numTimesReached(); // expected-warning {{1}}
|
|
return 0;
|
|
}
|
|
|
|
int num_steps_over_limit1() {
|
|
for (int i = 0; i < 129; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int num_steps_on_limit2() {
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int j = 0; j < 64; j++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{128}}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int num_steps_over_limit2() {
|
|
for (int i = 0; i < 2; i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{1}}
|
|
for (int j = 0; j <= 64; j++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int num_steps_on_limit3() {
|
|
for (int i = 0; i < getNum(); i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
for (int j = 0; j < 32; j++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{128}}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int num_steps_over_limit3() {
|
|
for (int i = 0; i < getNum(); i++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{1}}
|
|
for (int j = 0; j < 33; j++) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{4}}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void pr34943() {
|
|
for (int i = 0; i < 6L; ++i) {
|
|
clang_analyzer_numTimesReached(); // expected-warning {{6}}
|
|
}
|
|
}
|