Skip to content

Commit 8bbf2e3

Browse files
committed
[OPENMP50]Support for imperfectly nested loops.
Added support for imperfectly nested loops introduced in OpenMP 5.0.
1 parent adbf64c commit 8bbf2e3

File tree

7 files changed

+246
-55
lines changed

7 files changed

+246
-55
lines changed

clang/include/clang/AST/StmtOpenMP.h

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,28 +1084,20 @@ class OMPLoopDirective : public OMPExecutableDirective {
10841084
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
10851085
*std::next(child_begin(), CombinedParForInDistConditionOffset)));
10861086
}
1087+
/// Try to find the next loop sub-statement in the specified statement \p
1088+
/// CurStmt.
1089+
/// \param TryImperfectlyNestedLoops true, if we need to try to look for the
1090+
/// imperfectly nested loop.
1091+
static Stmt *tryToFindNextInnerLoop(Stmt *CurStmt,
1092+
bool TryImperfectlyNestedLoops);
1093+
static const Stmt *tryToFindNextInnerLoop(const Stmt *CurStmt,
1094+
bool TryImperfectlyNestedLoops) {
1095+
return tryToFindNextInnerLoop(const_cast<Stmt *>(CurStmt),
1096+
TryImperfectlyNestedLoops);
1097+
}
1098+
Stmt *getBody();
10871099
const Stmt *getBody() const {
1088-
// This relies on the loop form is already checked by Sema.
1089-
const Stmt *Body =
1090-
getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
1091-
if (auto *For = dyn_cast<ForStmt>(Body)) {
1092-
Body = For->getBody();
1093-
} else {
1094-
assert(isa<CXXForRangeStmt>(Body) &&
1095-
"Expected canonical for loop or range-based for loop.");
1096-
Body = cast<CXXForRangeStmt>(Body)->getBody();
1097-
}
1098-
for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) {
1099-
Body = Body->IgnoreContainers();
1100-
if (auto *For = dyn_cast<ForStmt>(Body)) {
1101-
Body = For->getBody();
1102-
} else {
1103-
assert(isa<CXXForRangeStmt>(Body) &&
1104-
"Expected canonical for loop or range-based for loop.");
1105-
Body = cast<CXXForRangeStmt>(Body)->getBody();
1106-
}
1107-
}
1108-
return Body;
1100+
return const_cast<OMPLoopDirective *>(this)->getBody();
11091101
}
11101102

11111103
ArrayRef<Expr *> counters() { return getCounters(); }

clang/lib/AST/StmtOpenMP.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,74 @@ const Stmt *OMPExecutableDirective::getStructuredBlock() const {
4141
return getInnermostCapturedStmt()->getCapturedStmt();
4242
}
4343

44+
Stmt *OMPLoopDirective::tryToFindNextInnerLoop(Stmt *CurStmt,
45+
bool TryImperfectlyNestedLoops) {
46+
Stmt *OrigStmt = CurStmt;
47+
CurStmt = CurStmt->IgnoreContainers();
48+
// Additional work for imperfectly nested loops, introduced in OpenMP 5.0.
49+
if (TryImperfectlyNestedLoops) {
50+
if (auto *CS = dyn_cast<CompoundStmt>(CurStmt)) {
51+
CurStmt = nullptr;
52+
SmallVector<CompoundStmt *, 4> Statements(1, CS);
53+
SmallVector<CompoundStmt *, 4> NextStatements;
54+
while (!Statements.empty()) {
55+
CS = Statements.pop_back_val();
56+
if (!CS)
57+
continue;
58+
for (Stmt *S : CS->body()) {
59+
if (!S)
60+
continue;
61+
if (isa<ForStmt>(S) || isa<CXXForRangeStmt>(S)) {
62+
// Only single loop construct is allowed.
63+
if (CurStmt) {
64+
CurStmt = OrigStmt;
65+
break;
66+
}
67+
CurStmt = S;
68+
continue;
69+
}
70+
S = S->IgnoreContainers();
71+
if (auto *InnerCS = dyn_cast_or_null<CompoundStmt>(S))
72+
NextStatements.push_back(InnerCS);
73+
}
74+
if (Statements.empty()) {
75+
// Found single inner loop or multiple loops - exit.
76+
if (CurStmt)
77+
break;
78+
Statements.swap(NextStatements);
79+
}
80+
}
81+
if (!CurStmt)
82+
CurStmt = OrigStmt;
83+
}
84+
}
85+
return CurStmt;
86+
}
87+
88+
Stmt *OMPLoopDirective::getBody() {
89+
// This relies on the loop form is already checked by Sema.
90+
Stmt *Body =
91+
getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
92+
if (auto *For = dyn_cast<ForStmt>(Body)) {
93+
Body = For->getBody();
94+
} else {
95+
assert(isa<CXXForRangeStmt>(Body) &&
96+
"Expected canonical for loop or range-based for loop.");
97+
Body = cast<CXXForRangeStmt>(Body)->getBody();
98+
}
99+
for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) {
100+
Body = tryToFindNextInnerLoop(Body, /*TryImperfectlyNestedLoops=*/true);
101+
if (auto *For = dyn_cast<ForStmt>(Body)) {
102+
Body = For->getBody();
103+
} else {
104+
assert(isa<CXXForRangeStmt>(Body) &&
105+
"Expected canonical for loop or range-based for loop.");
106+
Body = cast<CXXForRangeStmt>(Body)->getBody();
107+
}
108+
}
109+
return Body;
110+
}
111+
44112
void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) {
45113
assert(A.size() == getCollapsedNumber() &&
46114
"Number of loop counters is not the same as the collapsed number");

clang/lib/CodeGen/CGStmtOpenMP.cpp

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "clang/AST/Stmt.h"
1919
#include "clang/AST/StmtOpenMP.h"
2020
#include "clang/AST/DeclOpenMP.h"
21+
#include "clang/Basic/PrettyStackTrace.h"
2122
using namespace clang;
2223
using namespace CodeGen;
2324

@@ -146,7 +147,8 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
146147
const Stmt *Body =
147148
S.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
148149
for (unsigned Cnt = 0; Cnt < S.getCollapsedNumber(); ++Cnt) {
149-
Body = Body->IgnoreContainers();
150+
Body = OMPLoopDirective::tryToFindNextInnerLoop(
151+
Body, /*TryImperfectlyNestedLoops=*/true);
150152
if (auto *For = dyn_cast<ForStmt>(Body)) {
151153
Body = For->getBody();
152154
} else {
@@ -1339,6 +1341,41 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
13391341
[](CodeGenFunction &) { return nullptr; });
13401342
}
13411343

1344+
static void emitBody(CodeGenFunction &CGF, const Stmt *S, const Stmt *NextLoop,
1345+
int MaxLevel, int Level = 0) {
1346+
assert(Level < MaxLevel && "Too deep lookup during loop body codegen.");
1347+
const Stmt *SimplifiedS = S->IgnoreContainers();
1348+
if (const auto *CS = dyn_cast<CompoundStmt>(SimplifiedS)) {
1349+
PrettyStackTraceLoc CrashInfo(
1350+
CGF.getContext().getSourceManager(), CS->getLBracLoc(),
1351+
"LLVM IR generation of compound statement ('{}')");
1352+
1353+
// Keep track of the current cleanup stack depth, including debug scopes.
1354+
CodeGenFunction::LexicalScope Scope(CGF, S->getSourceRange());
1355+
for (const Stmt *CurStmt : CS->body())
1356+
emitBody(CGF, CurStmt, NextLoop, MaxLevel, Level);
1357+
return;
1358+
}
1359+
if (SimplifiedS == NextLoop) {
1360+
if (const auto *For = dyn_cast<ForStmt>(SimplifiedS)) {
1361+
S = For->getBody();
1362+
} else {
1363+
assert(isa<CXXForRangeStmt>(SimplifiedS) &&
1364+
"Expected canonical for loop or range-based for loop.");
1365+
const auto *CXXFor = cast<CXXForRangeStmt>(SimplifiedS);
1366+
CGF.EmitStmt(CXXFor->getLoopVarStmt());
1367+
S = CXXFor->getBody();
1368+
}
1369+
if (Level + 1 < MaxLevel) {
1370+
NextLoop = OMPLoopDirective::tryToFindNextInnerLoop(
1371+
S, /*TryImperfectlyNestedLoops=*/true);
1372+
emitBody(CGF, S, NextLoop, MaxLevel, Level + 1);
1373+
return;
1374+
}
1375+
}
1376+
CGF.EmitStmt(S);
1377+
}
1378+
13421379
void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
13431380
JumpDest LoopExit) {
13441381
RunCleanupsScope BodyScope(*this);
@@ -1371,20 +1408,12 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
13711408
// Emit loop variables for C++ range loops.
13721409
const Stmt *Body =
13731410
D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
1374-
for (unsigned Cnt = 0; Cnt < D.getCollapsedNumber(); ++Cnt) {
1375-
Body = Body->IgnoreContainers();
1376-
if (auto *For = dyn_cast<ForStmt>(Body)) {
1377-
Body = For->getBody();
1378-
} else {
1379-
assert(isa<CXXForRangeStmt>(Body) &&
1380-
"Expected canonical for loop or range-based for loop.");
1381-
auto *CXXFor = cast<CXXForRangeStmt>(Body);
1382-
EmitStmt(CXXFor->getLoopVarStmt());
1383-
Body = CXXFor->getBody();
1384-
}
1385-
}
13861411
// Emit loop body.
1387-
EmitStmt(D.getBody());
1412+
emitBody(*this, Body,
1413+
OMPLoopDirective::tryToFindNextInnerLoop(
1414+
Body, /*TryImperfectlyNestedLoops=*/true),
1415+
D.getCollapsedNumber());
1416+
13881417
// The end (updates/cleanups).
13891418
EmitBlock(Continue.getBlock());
13901419
BreakContinueStack.pop_back();

clang/lib/Sema/SemaOpenMP.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6979,7 +6979,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
69796979
"Expected canonical for or range-based for loops.");
69806980
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
69816981
}
6982-
CurStmt = CurStmt->IgnoreContainers();
6982+
CurStmt = OMPLoopDirective::tryToFindNextInnerLoop(
6983+
CurStmt, SemaRef.LangOpts.OpenMP >= 50);
69836984
}
69846985
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
69856986
if (checkOpenMPIterationSpace(
@@ -7006,7 +7007,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
70067007
"Expected canonical for or range-based for loops.");
70077008
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
70087009
}
7009-
CurStmt = CurStmt->IgnoreContainers();
7010+
CurStmt = OMPLoopDirective::tryToFindNextInnerLoop(
7011+
CurStmt, SemaRef.LangOpts.OpenMP >= 50);
70107012
}
70117013

70127014
Built.clear(/* size */ NestedLoopCount);

clang/test/OpenMP/for_ast_print.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,22 +114,30 @@ T tmain(T argc) {
114114
// CHECK-NEXT: a = 2;
115115
#pragma omp parallel
116116
#pragma omp for allocate(argc) private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) nowait
117-
for (auto &x : arr)
118-
for (int i = 0; i < 2; ++i)
119-
for (int j = 0; j < 2; ++j)
117+
for (auto &x : arr) {
118+
int j, hhh = 0;
119+
for (int i = 0; i < 2; ++i) {
120+
int j, hhh = 0;
120121
for (int j = 0; j < 2; ++j)
121122
for (int j = 0; j < 2; ++j)
122123
for (int j = 0; j < 2; ++j)
123-
for (int i = 0; i < 2; ++i)
124-
for (int j = 0; j < 2; ++j)
125-
for (int j = 0; j < 2; ++j)
126-
for (int j = 0; j < 2; ++j)
127-
for (int j = 0; j < 2; ++j)
128-
foo();
124+
for (int j = 0; j < 2; ++j)
125+
for (int i = 0; i < 2; ++i)
126+
for (int j = 0; j < 2; ++j)
127+
for (int j = 0; j < 2; ++j)
128+
for (int j = 0; j < 2; ++j)
129+
for (int j = 0; j < 2; ++j)
130+
foo();
131+
++hhh;
132+
}
133+
++hhh;
134+
}
129135
// CHECK-NEXT: #pragma omp parallel
130136
// CHECK-NEXT: #pragma omp for allocate(argc) private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) nowait
131-
// CHECK-NEXT: for (auto &x : arr)
132-
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
137+
// CHECK-NEXT: for (auto &x : arr) {
138+
// CHECK-NEXT: int j, hhh = 0;
139+
// CHECK-NEXT: for (int i = 0; i < 2; ++i) {
140+
// CHECK-NEXT: int j, hhh = 0;
133141
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
134142
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
135143
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
@@ -140,6 +148,10 @@ T tmain(T argc) {
140148
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
141149
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
142150
// CHECK-NEXT: foo();
151+
// CHECK-NEXT: ++hhh;
152+
// CHECK-NEXT: }
153+
// CHECK-NEXT: ++hhh;
154+
// CHECK-NEXT: }
143155
return T();
144156
}
145157

clang/test/OpenMP/for_codegen.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,4 +732,50 @@ T ftemplate() {
732732

733733
int fint(void) { return ftemplate<int>(); }
734734

735+
// Check for imperfectly loop nests codegen.
736+
#if _OPENMP == 201811
737+
void first();
738+
void last();
739+
void inner_f();
740+
void inner_l();
741+
void body_f();
742+
743+
// OMP5-LABEL: imperfectly_nested_loop
744+
void imperfectly_nested_loop() {
745+
// OMP5: call void @__kmpc_for_static_init_4(
746+
#pragma omp for collapse(3)
747+
for (int i = 0; i < 10; ++i) {
748+
{
749+
int a, d;
750+
// OMP5: invoke void @{{.+}}first{{.+}}()
751+
first();
752+
// OMP5: load i32
753+
// OMP5: store i32
754+
a = d;
755+
for (int j = 0; j < 10; ++j) {
756+
int a, d;
757+
// OMP5: invoke void @{{.+}}inner_f{{.+}}()
758+
inner_f();
759+
// OMP5: load i32
760+
// OMP5: store i32
761+
a = d;
762+
for (int k = 0; k < 10; ++k) {
763+
int a, d;
764+
// OMP5: invoke void @{{.+}}body_f{{.+}}()
765+
body_f();
766+
// OMP5: load i32
767+
// OMP5: store i32
768+
a = d;
769+
}
770+
// OMP5: invoke void @{{.+}}inner_l{{.+}}()
771+
inner_l();
772+
}
773+
// OMP5: invoke void @{{.+}}last{{.+}}()
774+
last();
775+
}
776+
}
777+
// OMP5: call void @__kmpc_for_static_fini(
778+
}
779+
#endif
780+
735781
#endif // HEADER

clang/test/OpenMP/for_collapse_messages.cpp

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
// RUN: %clang_cc1 -verify -fopenmp %s -Wuninitialized
2-
// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s -Wuninitialized
3-
// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s -Wuninitialized
1+
// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp %s -Wuninitialized
2+
// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -std=c++98 %s -Wuninitialized
3+
// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -std=c++11 %s -Wuninitialized
4+
// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 %s -Wuninitialized
5+
// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -std=c++98 %s -Wuninitialized
6+
// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -std=c++11 %s -Wuninitialized
47

5-
// RUN: %clang_cc1 -verify -fopenmp-simd %s -Wuninitialized
6-
// RUN: %clang_cc1 -verify -fopenmp-simd -std=c++98 %s -Wuninitialized
7-
// RUN: %clang_cc1 -verify -fopenmp-simd -std=c++11 %s -Wuninitialized
8+
// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd %s -Wuninitialized
9+
// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -std=c++98 %s -Wuninitialized
10+
// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -std=c++11 %s -Wuninitialized
11+
// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 %s -Wuninitialized
12+
// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -std=c++98 %s -Wuninitialized
13+
// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -std=c++11 %s -Wuninitialized
814

915
void foo() {
1016
}
@@ -87,7 +93,7 @@ int main(int argc, char **argv) {
8793
#endif
8894
// expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'collapse' clause}}
8995
// expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}}
90-
#pragma omp for collapse (foobool(argc)), collapse (true), collapse (-5)
96+
#pragma omp for collapse (foobool(argc)), collapse (true), collapse (-5)
9197
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
9298
#pragma omp for collapse (S1) // expected-error {{'S1' does not refer to a value}}
9399
for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4];
@@ -108,3 +114,39 @@ int main(int argc, char **argv) {
108114
return tmain<int, char, 1, 0>(argc, argv);
109115
}
110116

117+
void imperfectlyNestedLoops() {
118+
#pragma omp for collapse(2) // expected-note {{as specified in 'collapse' clause}}
119+
for (int i = 0; i < 10; ++i) { // expected-error {{expected 2 for loops after '#pragma omp for', but found only 1}}
120+
for (int j = 0; j < 10; ++j)
121+
;
122+
for (int j = 0; j < 10; ++j)
123+
;
124+
}
125+
#pragma omp for collapse(2) // expected-note {{as specified in 'collapse' clause}}
126+
for (int i = 0; i < 10; ++i) { // expected-error {{expected 2 for loops after '#pragma omp for', but found only 1}}
127+
{
128+
for (int j = 0; j < 10; ++j)
129+
;
130+
for (int j = 0; j < 10; ++j)
131+
;
132+
}
133+
{
134+
for (int j = 0; j < 10; ++j)
135+
;
136+
for (int j = 0; j < 10; ++j)
137+
;
138+
}
139+
}
140+
#pragma omp for collapse(2) // omp45-note {{as specified in 'collapse' clause}}
141+
for (int i = 0; i < 10; ++i) { // omp45-error {{expected 2 for loops after '#pragma omp for', but found only 1}}
142+
int a, b, c;
143+
for (int j = 0; j < 10; ++j)
144+
;
145+
{
146+
for (int j = 0; j < 10; ++j)
147+
;
148+
for (int j = 0; j < 10; ++j)
149+
;
150+
}
151+
}
152+
}

0 commit comments

Comments
 (0)