[clang] [OpenACC] Implement 'tile' loop count/tightly nested loop requirement (PR #111038)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 3 11:24:34 PDT 2024
https://github.com/erichkeane created https://github.com/llvm/llvm-project/pull/111038
the 'tile' clause requires that it be followed by N (where N is the
number of size expressions) 'tightly nested loops'. This means the
same as it does in 'collapse', so much of the implementation is simliar/shared with that.
>From eb232be419fd56fe518fae9c2ddcd0606e1c4c02 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Fri, 27 Sep 2024 07:22:31 -0700
Subject: [PATCH] [OpenACC] Implement 'tile' loop count/tightly nested loop
requirement
the 'tile' clause requires that it be followed by N (where N is the
number of size expressions) 'tightly nested loops'. This means the
same as it does in 'collapse', so much of the implementation is
simliar/shared with that.
---
.../clang/Basic/DiagnosticSemaKinds.td | 22 +-
clang/include/clang/Sema/SemaOpenACC.h | 73 +++--
clang/lib/Sema/SemaOpenACC.cpp | 164 +++++++---
clang/test/ParserOpenACC/parse-clauses.c | 18 +-
...p-construct-auto_seq_independent-clauses.c | 18 +-
.../loop-construct-device_type-clause.c | 4 +-
.../loop-construct-tile-clause.cpp | 281 ++++++++++++++++++
7 files changed, 504 insertions(+), 76 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 59dc81cfeb7111..583475327c5227 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12670,19 +12670,19 @@ def err_acc_size_expr_value
: Error<
"OpenACC 'tile' clause size expression must be %select{an asterisk "
"or a constant expression|positive integer value, evaluated to %1}0">;
-def err_acc_invalid_in_collapse_loop
- : Error<"%select{OpenACC '%1' construct|while loop|do loop}0 cannot appear "
- "in intervening code of a 'loop' with a 'collapse' clause">;
-def note_acc_collapse_clause_here
- : Note<"active 'collapse' clause defined here">;
-def err_acc_collapse_multiple_loops
+def err_acc_invalid_in_loop
+ : Error<"%select{OpenACC '%2' construct|while loop|do loop}0 cannot appear "
+ "in intervening code of a 'loop' with a '%1' clause">;
+def note_acc_active_clause_here
+ : Note<"active '%0' clause defined here">;
+def err_acc_clause_multiple_loops
: Error<"more than one for-loop in a loop associated with OpenACC 'loop' "
- "construct with a 'collapse' clause">;
-def err_acc_collapse_insufficient_loops
- : Error<"'collapse' clause specifies a loop count greater than the number "
+ "construct with a '%select{collapse|tile}0' clause">;
+def err_acc_insufficient_loops
+ : Error<"'%0' clause specifies a loop count greater than the number "
"of available loops">;
-def err_acc_collapse_intervening_code
- : Error<"inner loops must be tightly nested inside a 'collapse' clause on "
+def err_acc_intervening_code
+ : Error<"inner loops must be tightly nested inside a '%0' clause on "
"a 'loop' construct">;
// AMDGCN builtins diagnostics
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index d25c52ec3be43a..97386d2378b758 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -42,6 +42,23 @@ class SemaOpenACC : public SemaBase {
/// above collection.
bool InsideComputeConstruct = false;
+ /// Certain clauses care about the same things that aren't specific to the
+ /// individual clause, but can be shared by a few, so store them here. All
+ /// require a 'no intervening constructs' rule, so we know they are all from
+ /// the same 'place'.
+ struct LoopCheckingInfo {
+ /// Records whether we've seen the top level 'for'. We already diagnose
+ /// later that the 'top level' is a for loop, so we use this to suppress the
+ /// 'collapse inner loop not a 'for' loop' diagnostic.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned TopLevelLoopSeen : 1;
+
+ /// Records whether this 'tier' of the loop has already seen a 'for' loop,
+ /// used to diagnose if there are multiple 'for' loops at any one level.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned CurLevelHasLoopAlready : 1;
+ } LoopInfo{/*TopLevelLoopSeen=*/false, /*CurLevelHasLoopAlready=*/false};
+
/// The 'collapse' clause requires quite a bit of checking while
/// parsing/instantiating its body, so this structure/object keeps all of the
/// necessary information as we do checking. This should rarely be directly
@@ -59,25 +76,27 @@ class SemaOpenACC : public SemaBase {
/// else it should be 'N' minus the current depth traversed.
std::optional<llvm::APSInt> CurCollapseCount;
- /// Records whether we've seen the top level 'for'. We already diagnose
- /// later that the 'top level' is a for loop, so we use this to suppress the
- /// 'collapse inner loop not a 'for' loop' diagnostic.
- LLVM_PREFERRED_TYPE(bool)
- unsigned TopLevelLoopSeen : 1;
-
- /// Records whether this 'tier' of the loop has already seen a 'for' loop,
- /// used to diagnose if there are multiple 'for' loops at any one level.
- LLVM_PREFERRED_TYPE(bool)
- unsigned CurLevelHasLoopAlready : 1;
-
/// Records whether we've hit a CurCollapseCount of '0' on the way down,
/// which allows us to diagnose if the value of 'N' is too large for the
/// current number of 'for' loops.
- LLVM_PREFERRED_TYPE(bool)
- unsigned CollapseDepthSatisfied : 1;
- } CollapseInfo{nullptr, std::nullopt, /*TopLevelLoopSeen=*/false,
- /*CurLevelHasLoopAlready=*/false,
- /*CollapseDepthSatisfied=*/true};
+ bool CollapseDepthSatisfied = true;
+ } CollapseInfo;
+
+ /// The 'tile' clause requires a bit of additional checking as well, so like
+ /// the `CollapseCheckingInfo`, ensure we maintain information here too.
+ struct TileCheckingInfo {
+ OpenACCTileClause *ActiveTile = nullptr;
+
+ /// This is the number of expressions on a 'tile' clause. This doesn't have
+ /// to be an APSInt because it isn't the result of a constexpr, just by our
+ /// own counting of elements.
+ std::optional<unsigned> CurTileCount;
+
+ /// Records whether we've hit a 'CurTileCount' of '0' on the wya down,
+ /// which allows us to diagnose if the number of arguments is too large for
+ /// the current number of 'for' loops.
+ bool TileDepthSatisfied = true;
+ } TileInfo;
public:
// Redeclaration of the version in OpenACCClause.h.
@@ -537,12 +556,15 @@ class SemaOpenACC : public SemaBase {
/// into a loop (for, etc) inside the construct.
class LoopInConstructRAII {
SemaOpenACC &SemaRef;
+ LoopCheckingInfo OldLoopInfo;
CollapseCheckingInfo OldCollapseInfo;
+ TileCheckingInfo OldTileInfo;
bool PreserveDepth;
public:
LoopInConstructRAII(SemaOpenACC &SemaRef, bool PreserveDepth = true)
- : SemaRef(SemaRef), OldCollapseInfo(SemaRef.CollapseInfo),
+ : SemaRef(SemaRef), OldLoopInfo(SemaRef.LoopInfo),
+ OldCollapseInfo(SemaRef.CollapseInfo), OldTileInfo(SemaRef.TileInfo),
PreserveDepth(PreserveDepth) {}
~LoopInConstructRAII() {
// The associated-statement level of this should NOT preserve this, as it
@@ -551,12 +573,20 @@ class SemaOpenACC : public SemaBase {
bool CollapseDepthSatisified =
PreserveDepth ? SemaRef.CollapseInfo.CollapseDepthSatisfied
: OldCollapseInfo.CollapseDepthSatisfied;
+ bool TileDepthSatisfied = PreserveDepth
+ ? SemaRef.TileInfo.TileDepthSatisfied
+ : OldTileInfo.TileDepthSatisfied;
bool CurLevelHasLoopAlready =
- PreserveDepth ? SemaRef.CollapseInfo.CurLevelHasLoopAlready
- : OldCollapseInfo.CurLevelHasLoopAlready;
+ PreserveDepth ? SemaRef.LoopInfo.CurLevelHasLoopAlready
+ : OldLoopInfo.CurLevelHasLoopAlready;
+
+ SemaRef.LoopInfo = OldLoopInfo;
SemaRef.CollapseInfo = OldCollapseInfo;
+ SemaRef.TileInfo = OldTileInfo;
+
SemaRef.CollapseInfo.CollapseDepthSatisfied = CollapseDepthSatisified;
- SemaRef.CollapseInfo.CurLevelHasLoopAlready = CurLevelHasLoopAlready;
+ SemaRef.TileInfo.TileDepthSatisfied = TileDepthSatisfied;
+ SemaRef.LoopInfo.CurLevelHasLoopAlready = CurLevelHasLoopAlready;
}
};
@@ -577,6 +607,9 @@ class SemaOpenACC : public SemaBase {
void SetCollapseInfoBeforeAssociatedStmt(
ArrayRef<const OpenACCClause *> UnInstClauses,
ArrayRef<OpenACCClause *> Clauses);
+ void SetTileInfoBeforeAssociatedStmt(
+ ArrayRef<const OpenACCClause *> UnInstClauses,
+ ArrayRef<OpenACCClause *> Clauses);
~AssociatedStmtRAII();
};
};
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index f3840c6ffba82b..66f8029a2754b9 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -1128,6 +1128,7 @@ SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(
SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);
} else if (DirKind == OpenACCDirectiveKind::Loop) {
SetCollapseInfoBeforeAssociatedStmt(UnInstClauses, Clauses);
+ SetTileInfoBeforeAssociatedStmt(UnInstClauses, Clauses);
}
}
@@ -1136,8 +1137,9 @@ void SemaOpenACC::AssociatedStmtRAII::SetCollapseInfoBeforeAssociatedStmt(
ArrayRef<OpenACCClause *> Clauses) {
// Reset this checking for loops that aren't covered in a RAII object.
- SemaRef.CollapseInfo.CurLevelHasLoopAlready = false;
+ SemaRef.LoopInfo.CurLevelHasLoopAlready = false;
SemaRef.CollapseInfo.CollapseDepthSatisfied = true;
+ SemaRef.TileInfo.TileDepthSatisfied = true;
// We make sure to take an optional list of uninstantiated clauses, so that
// we can check to make sure we don't 'double diagnose' in the event that
@@ -1176,6 +1178,26 @@ void SemaOpenACC::AssociatedStmtRAII::SetCollapseInfoBeforeAssociatedStmt(
cast<ConstantExpr>(LoopCount)->getResultAsAPSInt();
}
+void SemaOpenACC::AssociatedStmtRAII::SetTileInfoBeforeAssociatedStmt(
+ ArrayRef<const OpenACCClause *> UnInstClauses,
+ ArrayRef<OpenACCClause *> Clauses) {
+ // We don't diagnose if this is during instantiation, since the only thing we
+ // care about is the number of arguments, which we can figure out without
+ // instantiation, so we don't want to double-diagnose.
+ if (UnInstClauses.size() > 0)
+ return;
+ auto *TileClauseItr =
+ llvm::find_if(Clauses, llvm::IsaPred<OpenACCTileClause>);
+
+ if (Clauses.end() == TileClauseItr)
+ return;
+
+ OpenACCTileClause *TileClause = cast<OpenACCTileClause>(*TileClauseItr);
+ SemaRef.TileInfo.ActiveTile = TileClause;
+ SemaRef.TileInfo.TileDepthSatisfied = false;
+ SemaRef.TileInfo.CurTileCount = TileClause->getSizeExprs().size();
+}
+
SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
SemaRef.InsideComputeConstruct = WasInsideComputeConstruct;
if (DirKind == OpenACCDirectiveKind::Parallel ||
@@ -1771,38 +1793,66 @@ void SemaOpenACC::ActOnWhileStmt(SourceLocation WhileLoc) {
if (!getLangOpts().OpenACC)
return;
- if (!CollapseInfo.TopLevelLoopSeen)
+ if (!LoopInfo.TopLevelLoopSeen)
return;
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
- Diag(WhileLoc, diag::err_acc_invalid_in_collapse_loop) << /*while loop*/ 1;
+ Diag(WhileLoc, diag::err_acc_invalid_in_loop)
+ << /*while loop*/ 1 << OpenACCClauseKind::Collapse;
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
- diag::note_acc_collapse_clause_here);
+ diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Collapse;
// Remove the value so that we don't get cascading errors in the body. The
// caller RAII object will restore this.
CollapseInfo.CurCollapseCount = std::nullopt;
}
+
+ if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
+ Diag(WhileLoc, diag::err_acc_invalid_in_loop)
+ << /*while loop*/ 1 << OpenACCClauseKind::Tile;
+ assert(TileInfo.ActiveTile && "tile count without object?");
+ Diag(TileInfo.ActiveTile->getBeginLoc(), diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Tile;
+
+ // Remove the value so that we don't get cascading errors in the body. The
+ // caller RAII object will restore this.
+ TileInfo.CurTileCount = std::nullopt;
+ }
}
void SemaOpenACC::ActOnDoStmt(SourceLocation DoLoc) {
if (!getLangOpts().OpenACC)
return;
- if (!CollapseInfo.TopLevelLoopSeen)
+ if (!LoopInfo.TopLevelLoopSeen)
return;
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
- Diag(DoLoc, diag::err_acc_invalid_in_collapse_loop) << /*do loop*/ 2;
+ Diag(DoLoc, diag::err_acc_invalid_in_loop)
+ << /*do loop*/ 2 << OpenACCClauseKind::Collapse;
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
- diag::note_acc_collapse_clause_here);
+ diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Collapse;
// Remove the value so that we don't get cascading errors in the body. The
// caller RAII object will restore this.
CollapseInfo.CurCollapseCount = std::nullopt;
}
+
+ if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
+ Diag(DoLoc, diag::err_acc_invalid_in_loop)
+ << /*do loop*/ 2 << OpenACCClauseKind::Tile;
+ assert(TileInfo.ActiveTile && "tile count without object?");
+ Diag(TileInfo.ActiveTile->getBeginLoc(), diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Tile;
+
+ // Remove the value so that we don't get cascading errors in the body. The
+ // caller RAII object will restore this.
+ TileInfo.CurTileCount = std::nullopt;
+ }
}
void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc) {
@@ -1810,7 +1860,7 @@ void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc) {
return;
// Enable the while/do-while checking.
- CollapseInfo.TopLevelLoopSeen = true;
+ LoopInfo.TopLevelLoopSeen = true;
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
@@ -1819,11 +1869,12 @@ void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc) {
// or loop nest.
// This checks for more than 1 loop at the current level, the
// 'depth'-satisifed checking manages the 'not zero' case.
- if (CollapseInfo.CurLevelHasLoopAlready) {
- Diag(ForLoc, diag::err_acc_collapse_multiple_loops);
+ if (LoopInfo.CurLevelHasLoopAlready) {
+ Diag(ForLoc, diag::err_acc_clause_multiple_loops) << /*Collapse*/ 0;
assert(CollapseInfo.ActiveCollapse && "No collapse object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
- diag::note_acc_collapse_clause_here);
+ diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Collapse;
} else {
--(*CollapseInfo.CurCollapseCount);
@@ -1834,13 +1885,29 @@ void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc) {
}
}
+ if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
+ if (LoopInfo.CurLevelHasLoopAlready) {
+ Diag(ForLoc, diag::err_acc_clause_multiple_loops) << /*Tile*/ 1;
+ assert(TileInfo.ActiveTile && "No tile object?");
+ Diag(TileInfo.ActiveTile->getBeginLoc(),
+ diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Tile;
+ } else {
+ --(*TileInfo.CurTileCount);
+ // Once we've hit zero here, we know we have deep enough 'for' loops to
+ // get to the bottom.
+ if (*TileInfo.CurTileCount == 0)
+ TileInfo.TileDepthSatisfied = true;
+ }
+ }
+
// Set this to 'false' for the body of this loop, so that the next level
// checks independently.
- CollapseInfo.CurLevelHasLoopAlready = false;
+ LoopInfo.CurLevelHasLoopAlready = false;
}
namespace {
-SourceLocation FindInterveningCodeInCollapseLoop(const Stmt *CurStmt) {
+SourceLocation FindInterveningCodeInLoop(const Stmt *CurStmt) {
// We should diagnose on anything except `CompoundStmt`, `NullStmt`,
// `ForStmt`, `CXXForRangeStmt`, since those are legal, and `WhileStmt` and
// `DoStmt`, as those are caught as a violation elsewhere.
@@ -1858,8 +1925,7 @@ SourceLocation FindInterveningCodeInCollapseLoop(const Stmt *CurStmt) {
// of compound statements, as long as there isn't any code inside.
if (const auto *CS = dyn_cast<CompoundStmt>(CurStmt)) {
for (const auto *ChildStmt : CS->children()) {
- SourceLocation ChildStmtLoc =
- FindInterveningCodeInCollapseLoop(ChildStmt);
+ SourceLocation ChildStmtLoc = FindInterveningCodeInLoop(ChildStmt);
if (ChildStmtLoc.isValid())
return ChildStmtLoc;
}
@@ -1874,24 +1940,33 @@ void SemaOpenACC::ActOnForStmtEnd(SourceLocation ForLoc, StmtResult Body) {
if (!getLangOpts().OpenACC)
return;
// Set this to 'true' so if we find another one at this level we can diagnose.
- CollapseInfo.CurLevelHasLoopAlready = true;
+ LoopInfo.CurLevelHasLoopAlready = true;
if (!Body.isUsable())
return;
- if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0 &&
- !CollapseInfo.ActiveCollapse->hasForce()) {
- // OpenACC 3.3: 2.9.1
- // If the 'force' modifier does not appear, then the associated loops must
- // be tightly nested. If the force modifier appears, then any intervening
- // code may be executed multiple times as needed to perform the collapse.
+ bool IsActiveCollapse = CollapseInfo.CurCollapseCount &&
+ *CollapseInfo.CurCollapseCount > 0 &&
+ !CollapseInfo.ActiveCollapse->hasForce();
+ bool IsActiveTile = TileInfo.CurTileCount && *TileInfo.CurTileCount > 0;
- SourceLocation OtherStmtLoc = FindInterveningCodeInCollapseLoop(Body.get());
+ if (IsActiveCollapse || IsActiveTile) {
+ SourceLocation OtherStmtLoc = FindInterveningCodeInLoop(Body.get());
- if (OtherStmtLoc.isValid()) {
- Diag(OtherStmtLoc, diag::err_acc_collapse_intervening_code);
+ if (OtherStmtLoc.isValid() && IsActiveCollapse) {
+ Diag(OtherStmtLoc, diag::err_acc_intervening_code)
+ << OpenACCClauseKind::Collapse;
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
- diag::note_acc_collapse_clause_here);
+ diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Collapse;
+ }
+
+ if (OtherStmtLoc.isValid() && IsActiveTile) {
+ Diag(OtherStmtLoc, diag::err_acc_intervening_code)
+ << OpenACCClauseKind::Tile;
+ Diag(TileInfo.ActiveTile->getBeginLoc(),
+ diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Tile;
}
}
}
@@ -1907,11 +1982,19 @@ bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K,
//
// ALL constructs are ill-formed if there is an active 'collapse'
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
- Diag(StartLoc, diag::err_acc_invalid_in_collapse_loop)
- << /*OpenACC Construct*/ 0 << K;
+ Diag(StartLoc, diag::err_acc_invalid_in_loop)
+ << /*OpenACC Construct*/ 0 << OpenACCClauseKind::Collapse << K;
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
- diag::note_acc_collapse_clause_here);
+ diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Collapse;
+ }
+ if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
+ Diag(StartLoc, diag::err_acc_invalid_in_loop)
+ << /*OpenACC Construct*/ 0 << OpenACCClauseKind::Tile << K;
+ assert(TileInfo.ActiveTile && "Tile count without object?");
+ Diag(TileInfo.ActiveTile->getBeginLoc(), diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Tile;
}
return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true);
@@ -1986,11 +2069,24 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt(SourceLocation DirectiveLoc,
return StmtError();
}
- if (!CollapseInfo.CollapseDepthSatisfied) {
- Diag(DirectiveLoc, diag::err_acc_collapse_insufficient_loops);
- assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
- Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
- diag::note_acc_collapse_clause_here);
+ if (!CollapseInfo.CollapseDepthSatisfied || !TileInfo.TileDepthSatisfied) {
+ if (!CollapseInfo.CollapseDepthSatisfied) {
+ Diag(DirectiveLoc, diag::err_acc_insufficient_loops)
+ << OpenACCClauseKind::Collapse;
+ assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
+ Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
+ diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Collapse;
+ }
+
+ if (!TileInfo.TileDepthSatisfied) {
+ Diag(DirectiveLoc, diag::err_acc_insufficient_loops)
+ << OpenACCClauseKind::Tile;
+ assert(TileInfo.ActiveTile && "Collapse count without object?");
+ Diag(TileInfo.ActiveTile->getBeginLoc(),
+ diag::note_acc_active_clause_here)
+ << OpenACCClauseKind::Tile;
+ }
return StmtError();
}
diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c
index a752b2ebd18b6a..6c382379a8a7ea 100644
--- a/clang/test/ParserOpenACC/parse-clauses.c
+++ b/clang/test/ParserOpenACC/parse-clauses.c
@@ -1174,7 +1174,9 @@ void Tile() {
// expected-error at +1{{indirection requires pointer operand ('int' invalid)}}
#pragma acc loop tile(* returns_int() , *)
- for(;;){}
+ for(;;){
+ for(;;);
+ }
#pragma acc loop tile(*)
for(;;){}
@@ -1184,11 +1186,19 @@ void Tile() {
#pragma acc loop tile(5)
for(;;){}
#pragma acc loop tile(*, 5)
- for(;;){}
+ for(;;){
+ for(;;);
+ }
#pragma acc loop tile(5, *)
- for(;;){}
+ for(;;){
+ for(;;);
+ }
#pragma acc loop tile(5, *, 3, *)
- for(;;){}
+ for(;;){
+ for(;;)
+ for(;;)
+ for(;;);
+ }
}
void Gang() {
diff --git a/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c b/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c
index f66ce6991acb1a..3da7f0e9836be8 100644
--- a/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c
+++ b/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c
@@ -166,7 +166,8 @@ void uses() {
#pragma acc loop auto async
for(;;);
#pragma acc loop auto tile(1+2, 1)
- for(;;);
+ for(;;)
+ for(;;);
// expected-warning at +1{{OpenACC clause 'gang' not yet implemented}}
#pragma acc loop auto gang
for(;;);
@@ -303,7 +304,8 @@ void uses() {
#pragma acc loop async auto
for(;;);
#pragma acc loop tile(1+2, 1) auto
- for(;;);
+ for(;;)
+ for(;;);
// expected-warning at +1{{OpenACC clause 'gang' not yet implemented}}
#pragma acc loop gang auto
for(;;);
@@ -441,7 +443,8 @@ void uses() {
#pragma acc loop independent async
for(;;);
#pragma acc loop independent tile(1+2, 1)
- for(;;);
+ for(;;)
+ for(;;);
// expected-warning at +1{{OpenACC clause 'gang' not yet implemented}}
#pragma acc loop independent gang
for(;;);
@@ -578,7 +581,8 @@ void uses() {
#pragma acc loop async independent
for(;;);
#pragma acc loop tile(1+2, 1) independent
- for(;;);
+ for(;;)
+ for(;;);
// expected-warning at +1{{OpenACC clause 'gang' not yet implemented}}
#pragma acc loop gang independent
for(;;);
@@ -725,7 +729,8 @@ void uses() {
#pragma acc loop seq async
for(;;);
#pragma acc loop seq tile(1+2, 1)
- for(;;);
+ for(;;)
+ for(;;);
// expected-error at +1{{OpenACC 'wait' clause is not valid on 'loop' directive}}
#pragma acc loop seq wait
for(;;);
@@ -871,7 +876,8 @@ void uses() {
#pragma acc loop async seq
for(;;);
#pragma acc loop tile(1+2, 1) seq
- for(;;);
+ for(;;)
+ for(;;);
// expected-error at +1{{OpenACC 'wait' clause is not valid on 'loop' directive}}
#pragma acc loop wait seq
for(;;);
diff --git a/clang/test/SemaOpenACC/loop-construct-device_type-clause.c b/clang/test/SemaOpenACC/loop-construct-device_type-clause.c
index aa7c3201c8319c..3d77c031f42630 100644
--- a/clang/test/SemaOpenACC/loop-construct-device_type-clause.c
+++ b/clang/test/SemaOpenACC/loop-construct-device_type-clause.c
@@ -190,7 +190,9 @@ void uses() {
for(;;);
#pragma acc loop device_type(*) tile(*, 1)
- for(;;);
+ for(;;)
+ for(;;);
+
// expected-warning at +1{{OpenACC clause 'gang' not yet implemented, clause ignored}}
#pragma acc loop dtype(*) gang
for(;;);
diff --git a/clang/test/SemaOpenACC/loop-construct-tile-clause.cpp b/clang/test/SemaOpenACC/loop-construct-tile-clause.cpp
index 28eadde7416c35..ecf8dc1109fb76 100644
--- a/clang/test/SemaOpenACC/loop-construct-tile-clause.cpp
+++ b/clang/test/SemaOpenACC/loop-construct-tile-clause.cpp
@@ -91,5 +91,286 @@ void negative_zero_constexpr() {
#pragma acc loop tile(*, ConvertsOne{})
for(;;)
for(;;);
+}
+
+template<unsigned One>
+void only_for_loops_templ() {
+ // expected-note at +1{{'loop' construct is here}}
+#pragma acc loop tile(One)
+ // expected-error at +1{{OpenACC 'loop' construct can only be applied to a 'for' loop}}
+ while(true);
+
+ // expected-note at +1{{'loop' construct is here}}
+#pragma acc loop tile(One)
+ // expected-error at +1{{OpenACC 'loop' construct can only be applied to a 'for' loop}}
+ do {} while(true);
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile(One, 2) // expected-note 2{{active 'tile' clause defined here}}
+ for (;;)
+ // expected-error at +1{{while loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ while(true);
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile(One, 2) // expected-note 2{{active 'tile' clause defined here}}
+ for (;;)
+ // expected-error at +1{{do loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ do{}while(true);
+}
+
+
+void only_for_loops() {
+ // expected-note at +1{{'loop' construct is here}}
+#pragma acc loop tile(1)
+ // expected-error at +1{{OpenACC 'loop' construct can only be applied to a 'for' loop}}
+ while(true);
+
+ // expected-note at +1{{'loop' construct is here}}
+#pragma acc loop tile(1)
+ // expected-error at +1{{OpenACC 'loop' construct can only be applied to a 'for' loop}}
+ do {} while(true);
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile(1, 2) // expected-note 2{{active 'tile' clause defined here}}
+ for (;;)
+ // expected-error at +1{{while loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ while(true);
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile(1, 2) // expected-note 2{{active 'tile' clause defined here}}
+ for (;;)
+ // expected-error at +1{{do loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ do{}while(true);
+}
+
+void only_one_on_loop() {
+ // expected-error at +2{{OpenACC 'tile' clause cannot appear more than once on a 'loop' directive}}
+ // expected-note at +1{{previous clause is here}}
+#pragma acc loop tile(1) tile(1)
+ for(;;);
+}
+
+template<unsigned Val>
+void depth_too_high_templ() {
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile (Val, *, Val) // expected-note{{active 'tile' clause defined here}}
+ for(;;)
+ for(;;);
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile (Val, *, Val) // expected-note 2{{active 'tile' clause defined here}}
+ for(;;)
+ for(;;)
+ // expected-error at +1{{while loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ while(true);
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile (Val, *, Val) // expected-note 2{{active 'tile' clause defined here}}
+ for(;;)
+ for(;;)
+ // expected-error at +1{{do loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ do{}while(true);
+
+ int Arr[Val+5];
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile (Val, *, Val) // expected-note 2{{active 'tile' clause defined here}}
+ for(;;)
+ for(auto x : Arr)
+ // expected-error at +1{{while loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ while(true)
+ for(;;);
+
+#pragma acc loop tile (Val, *, Val)
+ for(;;)
+ for(auto x : Arr)
+ for(;;)
+ while(true);
+}
+
+void depth_too_high() {
+ depth_too_high_templ<3>();
+
+int Arr[5];
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile (1, *, 3) // expected-note{{active 'tile' clause defined here}}
+ for(;;)
+ for(;;);
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile (1, *, 3) // expected-note 2{{active 'tile' clause defined here}}
+ for(;;)
+ for(;;)
+ // expected-error at +1{{while loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ while(true);
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile (1, *, 3) // expected-note 2{{active 'tile' clause defined here}}
+ for(;;)
+ for(;;)
+ // expected-error at +1{{do loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ do{}while(true);
+
+ // expected-error at +1{{'tile' clause specifies a loop count greater than the number of available loops}}
+#pragma acc loop tile (1, *, 3) // expected-note 2{{active 'tile' clause defined here}}
+ for(;;)
+ for(;;)
+ // expected-error at +1{{while loop cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+ while(true)
+ for(;;);
+
+#pragma acc loop tile (1, *, 3)
+ for(;;)
+ for(auto x : Arr)
+ for(;;)
+ while(true);
+}
+
+template<unsigned Val>
+void not_single_loop_templ() {
+
+ int Arr[Val];
+
+#pragma acc loop tile (Val, *, 3) // expected-note{{active 'tile' clause defined here}}
+ for(;;) {
+ for (auto x : Arr)
+ for(;;);
+ // expected-error at +1{{more than one for-loop in a loop associated with OpenACC 'loop' construct with a 'tile' clause}}
+ for(;;)
+ for(;;);
+ }
+}
+
+void not_single_loop() {
+ not_single_loop_templ<3>(); // no diagnostic, was diagnosed in phase 1.
+
+ int Arr[5];
+
+#pragma acc loop tile (1, *, 3)// expected-note{{active 'tile' clause defined here}}
+ for(;;) {
+ for (auto x : Arr)
+ for(;;);
+ // expected-error at +1{{more than one for-loop in a loop associated with OpenACC 'loop' construct with a 'tile' clause}}
+ for(;;)
+ for(;;);
+ }
+}
+
+template<unsigned Val>
+void no_other_directives_templ() {
+
+ int Arr[Val];
+
+#pragma acc loop tile (Val, *, 3) // expected-note{{active 'tile' clause defined here}}
+ for(;;) {
+ for (auto x : Arr) {
+ // expected-error at +1{{OpenACC 'serial' construct cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+#pragma acc serial
+ ;
+ for(;;);
+ }
+ }
+
+ // OK, in innermost
+#pragma acc loop tile (Val, *, 3)
+ for(;;) {
+ for (;;) {
+ for (auto x : Arr) {
+#pragma acc serial
+ ;
+ }
+ }
+ }
+}
+
+void no_other_directives() {
+ no_other_directives_templ<3>();
+ int Arr[5];
+
+#pragma acc loop tile (1, *, 3) // expected-note{{active 'tile' clause defined here}}
+ for(;;) {
+ for (auto x : Arr) {
+ // expected-error at +1{{OpenACC 'serial' construct cannot appear in intervening code of a 'loop' with a 'tile' clause}}
+#pragma acc serial
+ ;
+ for(;;);
+ }
+ }
+
+ // OK, in innermost
+#pragma acc loop tile (3, *, 3)
+ for(;;) {
+ for (;;) {
+ for (auto x : Arr) {
+#pragma acc serial
+ ;
+ }
+ }
+ }
+}
+
+void call();
+template<unsigned Val>
+void intervening_templ() {
+#pragma acc loop tile(1, Val, *) // expected-note{{active 'tile' clause defined here}}
+ for(;;) {
+ //expected-error at +1{{inner loops must be tightly nested inside a 'tile' clause on a 'loop' construct}}
+ call();
+ for(;;)
+ for(;;);
+ }
+
+#pragma acc loop tile(1, Val, *) // expected-note{{active 'tile' clause defined here}}
+ for(;;) {
+ //expected-error at +1{{inner loops must be tightly nested inside a 'tile' clause on a 'loop' construct}}
+ unsigned I;
+ for(;;)
+ for(;;);
+ }
+
+#pragma acc loop tile(1, Val, *)
+ for(;;) {
+ for(;;)
+ for(;;)
+ call();
+ }
+}
+
+void intervening() {
+ intervening_templ<3>();
+
+#pragma acc loop tile(1, 2, *) // expected-note{{active 'tile' clause defined here}}
+ for(;;) {
+ //expected-error at +1{{inner loops must be tightly nested inside a 'tile' clause on a 'loop' construct}}
+ call();
+ for(;;)
+ for(;;);
+ }
+
+#pragma acc loop tile(1, 2, *) // expected-note{{active 'tile' clause defined here}}
+ for(;;) {
+ //expected-error at +1{{inner loops must be tightly nested inside a 'tile' clause on a 'loop' construct}}
+ unsigned I;
+ for(;;)
+ for(;;);
+ }
+
+#pragma acc loop tile(1, 2, *)
+ for(;;) {
+ for(;;)
+ for(;;)
+ call();
+ }
+}
+
+void collapse_tile_depth() {
+ // expected-error at +4{{'collapse' clause specifies a loop count greater than the number of available loops}}
+ // expected-note at +3{{active 'collapse' clause defined here}}
+ // expected-error at +2{{'tile' clause specifies a loop count greater than the number of available loops}}
+ // expected-note at +1{{active 'tile' clause defined here}}
+#pragma acc loop tile(1, 2, 3) collapse (3)
+ for(;;) {
+ for(;;);
+ }
}
More information about the cfe-commits
mailing list