Skip to content

Commit 4f82f27

Browse files
authored
[OpenACC] 'collapse' clause 'force' tag (#110906)
The 'force' tag permits intervening code on the applicable 'loop' construct, so this implements the restriction when the 'force' tag isn't present.
1 parent bfb3a44 commit 4f82f27

File tree

3 files changed

+196
-0
lines changed

3 files changed

+196
-0
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12677,6 +12677,9 @@ def err_acc_collapse_multiple_loops
1267712677
def err_acc_collapse_insufficient_loops
1267812678
: Error<"'collapse' clause specifies a loop count greater than the number "
1267912679
"of available loops">;
12680+
def err_acc_collapse_intervening_code
12681+
: Error<"inner loops must be tightly nested inside a 'collapse' clause on "
12682+
"a 'loop' construct">;
1268012683

1268112684
// AMDGCN builtins diagnostics
1268212685
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,11 +1770,61 @@ void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc) {
17701770
CollapseInfo.CurLevelHasLoopAlready = false;
17711771
}
17721772

1773+
namespace {
1774+
SourceLocation FindInterveningCodeInCollapseLoop(const Stmt *CurStmt) {
1775+
// We should diagnose on anything except `CompoundStmt`, `NullStmt`,
1776+
// `ForStmt`, `CXXForRangeStmt`, since those are legal, and `WhileStmt` and
1777+
// `DoStmt`, as those are caught as a violation elsewhere.
1778+
// For `CompoundStmt` we need to search inside of it.
1779+
if (!CurStmt ||
1780+
isa<ForStmt, NullStmt, ForStmt, CXXForRangeStmt, WhileStmt, DoStmt>(
1781+
CurStmt))
1782+
return SourceLocation{};
1783+
1784+
// Any other construct is an error anyway, so it has already been diagnosed.
1785+
if (isa<OpenACCConstructStmt>(CurStmt))
1786+
return SourceLocation{};
1787+
1788+
// Search inside the compound statement, this allows for arbitrary nesting
1789+
// of compound statements, as long as there isn't any code inside.
1790+
if (const auto *CS = dyn_cast<CompoundStmt>(CurStmt)) {
1791+
for (const auto *ChildStmt : CS->children()) {
1792+
SourceLocation ChildStmtLoc =
1793+
FindInterveningCodeInCollapseLoop(ChildStmt);
1794+
if (ChildStmtLoc.isValid())
1795+
return ChildStmtLoc;
1796+
}
1797+
// Empty/not invalid compound statements are legal.
1798+
return SourceLocation{};
1799+
}
1800+
return CurStmt->getBeginLoc();
1801+
}
1802+
} // namespace
1803+
17731804
void SemaOpenACC::ActOnForStmtEnd(SourceLocation ForLoc, StmtResult Body) {
17741805
if (!getLangOpts().OpenACC)
17751806
return;
17761807
// Set this to 'true' so if we find another one at this level we can diagnose.
17771808
CollapseInfo.CurLevelHasLoopAlready = true;
1809+
1810+
if (!Body.isUsable())
1811+
return;
1812+
1813+
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0 &&
1814+
!CollapseInfo.ActiveCollapse->hasForce()) {
1815+
// OpenACC 3.3: 2.9.1
1816+
// If the 'force' modifier does not appear, then the associated loops must
1817+
// be tightly nested. If the force modifier appears, then any intervening
1818+
// code may be executed multiple times as needed to perform the collapse.
1819+
1820+
SourceLocation OtherStmtLoc = FindInterveningCodeInCollapseLoop(Body.get());
1821+
1822+
if (OtherStmtLoc.isValid()) {
1823+
Diag(OtherStmtLoc, diag::err_acc_collapse_intervening_code);
1824+
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
1825+
diag::note_acc_collapse_clause_here);
1826+
}
1827+
}
17781828
}
17791829

17801830
bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K,

clang/test/SemaOpenACC/loop-construct-collapse-clause.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,3 +336,146 @@ void no_other_directives() {
336336
}
337337
}
338338

339+
void call();
340+
341+
template<unsigned Two>
342+
void intervening_without_force_templ() {
343+
// expected-note@+1{{active 'collapse' clause defined here}}
344+
#pragma acc loop collapse(2)
345+
for(;;) {
346+
// expected-error@+1{{inner loops must be tightly nested inside a 'collapse' clause on a 'loop' construct}}
347+
call();
348+
for(;;){}
349+
}
350+
351+
// expected-note@+1{{active 'collapse' clause defined here}}
352+
#pragma acc loop collapse(Two)
353+
for(;;) {
354+
// expected-error@+1{{inner loops must be tightly nested inside a 'collapse' clause on a 'loop' construct}}
355+
call();
356+
for(;;){}
357+
}
358+
359+
// expected-note@+1{{active 'collapse' clause defined here}}
360+
#pragma acc loop collapse(2)
361+
for(;;) {
362+
for(;;){}
363+
// expected-error@+1{{inner loops must be tightly nested inside a 'collapse' clause on a 'loop' construct}}
364+
call();
365+
}
366+
367+
#pragma acc loop collapse(force:2)
368+
for(;;) {
369+
call();
370+
for(;;){}
371+
}
372+
373+
#pragma acc loop collapse(force:Two)
374+
for(;;) {
375+
call();
376+
for(;;){}
377+
}
378+
379+
380+
#pragma acc loop collapse(force:2)
381+
for(;;) {
382+
for(;;){}
383+
call();
384+
}
385+
386+
#pragma acc loop collapse(force:Two)
387+
for(;;) {
388+
for(;;){}
389+
call();
390+
}
391+
392+
#pragma acc loop collapse(Two)
393+
for(;;) {
394+
for(;;){
395+
call();
396+
}
397+
}
398+
399+
#pragma acc loop collapse(Two)
400+
for(;;) {
401+
{
402+
{
403+
for(;;){
404+
call();
405+
}
406+
}
407+
}
408+
}
409+
410+
#pragma acc loop collapse(force:Two)
411+
for(;;) {
412+
for(;;){
413+
call();
414+
}
415+
}
416+
417+
// expected-note@+1{{active 'collapse' clause defined here}}
418+
#pragma acc loop collapse(Two)
419+
for(;;) {
420+
for(;;){}
421+
// expected-error@+1{{inner loops must be tightly nested inside a 'collapse' clause on a 'loop' construct}}
422+
call();
423+
}
424+
}
425+
426+
void intervening_without_force() {
427+
intervening_without_force_templ<2>(); // expected-note{{in instantiation of function template specialization}}
428+
// expected-note@+1{{active 'collapse' clause defined here}}
429+
#pragma acc loop collapse(2)
430+
for(;;) {
431+
// expected-error@+1{{inner loops must be tightly nested inside a 'collapse' clause on a 'loop' construct}}
432+
call();
433+
for(;;){}
434+
}
435+
436+
// expected-note@+1{{active 'collapse' clause defined here}}
437+
#pragma acc loop collapse(2)
438+
for(;;) {
439+
for(;;){}
440+
// expected-error@+1{{inner loops must be tightly nested inside a 'collapse' clause on a 'loop' construct}}
441+
call();
442+
}
443+
444+
// The below two are fine, as they use the 'force' tag.
445+
#pragma acc loop collapse(force:2)
446+
for(;;) {
447+
call();
448+
for(;;){}
449+
}
450+
451+
#pragma acc loop collapse(force:2)
452+
for(;;) {
453+
for(;;){}
454+
call();
455+
}
456+
457+
#pragma acc loop collapse(2)
458+
for(;;) {
459+
for(;;){
460+
call();
461+
}
462+
}
463+
#pragma acc loop collapse(2)
464+
for(;;) {
465+
{
466+
{
467+
for(;;){
468+
call();
469+
}
470+
}
471+
}
472+
}
473+
474+
#pragma acc loop collapse(force:2)
475+
for(;;) {
476+
for(;;){
477+
call();
478+
}
479+
}
480+
}
481+

0 commit comments

Comments
 (0)