-
Notifications
You must be signed in to change notification settings - Fork 12.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[clang][OpenMP] Diagnose badly-formed collapsed imperfect loop nests (#…
…60678) This patch fixes a couple of cases where Clang aborts with loop nests that are being collapsed (via the relevant OpenMP clause) into a new, combined loop. The problematic cases happen when a variable declared within the loop nest is used in the (init, condition, iter) statement of a more deeply-nested loop. I don't think these cases (generally?) fall under the non-rectangular loop nest rules as defined in OpenMP 5.0+, but I could be wrong (and anyway, emitting an error is better than crashing). In terms of implementation: the crash happens because (to a first approximation) all the loop bounds calculations are pulled out to the start of the new, combined loop, but variables declared in the loop nest "haven't been seen yet". I believe there is special handling for iteration variables declared in "for" init statements, but not for variables declared elsewhere in the "imperfect" parts of a loop nest. So, this patch tries to diagnose the troublesome cases before they can cause a crash. This is slightly awkward because at the point where we want to do the diagnosis (SemaOpenMP.cpp), we don't have scope information readily available. Instead we "manually" scan through the AST of the loop nest looking for var decls (ForVarDeclFinder), then we ensure we're not using any of those in loop control subexprs (ForSubExprChecker). All that is only done when we have a "collapse" clause. Range-for loops can also cause crashes at present without this patch, so are handled too.
- Loading branch information
Showing
4 changed files
with
255 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -verify %s | ||
|
||
void func( double *A, int N, int M, int NB ) { | ||
#pragma omp parallel | ||
{ | ||
int nblks = (N-1)/NB; | ||
int lnb = ((N-1)/NB)*NB; | ||
|
||
#pragma omp for collapse(2) | ||
for (int jblk = 0 ; jblk < nblks ; jblk++ ) { | ||
int jb = (jblk == nblks - 1 ? lnb : NB); | ||
for (int jk = 0; jk < N; jk+=jb) { // expected-error{{cannot use variable 'jb' in collapsed imperfectly-nested loop increment statement}} | ||
} | ||
} | ||
|
||
#pragma omp for collapse(2) | ||
for (int a = 0; a < N; a++) { | ||
for (int b = 0; b < M; b++) { | ||
int cx = a+b < NB ? a : b; | ||
for (int c = 0; c < cx; c++) { | ||
} | ||
} | ||
} | ||
|
||
#pragma omp for collapse(3) | ||
for (int a = 0; a < N; a++) { | ||
for (int b = 0; b < M; b++) { | ||
int cx = a+b < NB ? a : b; | ||
for (int c = 0; c < cx; c++) { // expected-error{{cannot use variable 'cx' in collapsed imperfectly-nested loop condition statement}} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
int main(void) { | ||
double arr[256]; | ||
func (arr, 16, 16, 16); | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -verify %s | ||
|
||
// We just want to try out a range for statement... this seems a bit OTT. | ||
template<typename T> | ||
class fakevector { | ||
T *contents; | ||
long size; | ||
public: | ||
fakevector(long sz) : size(sz) { | ||
contents = new T[sz]; | ||
} | ||
~fakevector() { | ||
delete[] contents; | ||
} | ||
T& operator[](long x) { return contents[x]; } | ||
typedef T *iterator; | ||
fakevector<T>::iterator begin() { | ||
return &contents[0]; | ||
} | ||
fakevector<T>::iterator end() { | ||
return &contents[size]; | ||
} | ||
}; | ||
|
||
void func( double *A, int N, int M, int NB ) { | ||
#pragma omp parallel | ||
{ | ||
int nblks = (N-1)/NB; | ||
int lnb = ((N-1)/NB)*NB; | ||
#pragma omp for collapse(2) | ||
for (int jblk = 0 ; jblk < nblks ; jblk++ ) { | ||
int jb = (jblk == nblks - 1 ? lnb : NB); | ||
for (int jk = 0; jk < N; jk+=jb) { // expected-error{{cannot use variable 'jb' in collapsed imperfectly-nested loop increment statement}} | ||
} | ||
} | ||
|
||
#pragma omp for collapse(2) | ||
for (int a = 0; a < N; a++) { | ||
for (int b = 0; b < M; b++) { | ||
int cx = a+b < NB ? a : b; | ||
for (int c = 0; c < cx; c++) { | ||
} | ||
} | ||
} | ||
|
||
fakevector<float> myvec{N}; | ||
#pragma omp for collapse(2) | ||
for (auto &a : myvec) { | ||
fakevector<float> myvec3{M}; | ||
for (auto &b : myvec3) { // expected-error{{cannot use variable 'myvec3' in collapsed imperfectly-nested loop init statement}} | ||
} | ||
} | ||
|
||
fakevector<float> myvec2{M}; | ||
|
||
#pragma omp for collapse(3) | ||
for (auto &a : myvec) { | ||
for (auto &b : myvec2) { | ||
int cx = a < b ? N : M; | ||
for (int c = 0; c < cx; c++) { // expected-error {{cannot use variable 'cx' in collapsed imperfectly-nested loop condition statement}} | ||
} | ||
} | ||
} | ||
|
||
#pragma omp for collapse(3) | ||
for (auto &a : myvec) { | ||
int cx = a < 5 ? M : N; | ||
for (auto &b : myvec2) { | ||
for (int c = 0; c < cx; c++) { // expected-error{{cannot use variable 'cx' in collapsed imperfectly-nested loop condition statement}} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
int main(void) { | ||
double arr[256]; | ||
func (arr, 16, 16, 16); | ||
return 0; | ||
} |