diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -86,6 +86,8 @@ NODE(parser, AccSizeExpr) NODE(parser, AccSizeExprList) NODE(parser, AccStandaloneDirective) + NODE(parser, AccTileExpr) + NODE(parser, AccTileExprList) NODE(parser, AccLoopDirective) NODE(parser, AccWaitArgument) static std::string GetNodeName(const llvm::acc::Directive &x) { diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3857,6 +3857,16 @@ std::tuple, std::list> t; }; +struct AccTileExpr { + TUPLE_CLASS_BOILERPLATE(AccTileExpr); + CharBlock source; + std::tuple> t; // if null then * +}; + +struct AccTileExprList { + WRAPPER_CLASS_BOILERPLATE(AccTileExprList, std::list); +}; + struct AccSizeExpr { TUPLE_CLASS_BOILERPLATE(AccSizeExpr); CharBlock source; diff --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp --- a/flang/lib/Parser/openacc-parsers.cpp +++ b/flang/lib/Parser/openacc-parsers.cpp @@ -102,7 +102,7 @@ maybe(parenthesized(scalarLogicalExpr)))) || "SEQ" >> construct(construct()) || "TILE" >> construct(construct( - parenthesized(Parser{}))) || + parenthesized(Parser{}))) || "USE_DEVICE" >> construct(construct( parenthesized(Parser{}))) || "VECTOR_LENGTH" >> construct(construct( @@ -131,11 +131,20 @@ "QUEUES:" >> nonemptyList(scalarIntExpr) || nonemptyList(scalarIntExpr))) // 2.9 (1609) size-expr is one of: +// * (represented as an empty std::optional) // int-expr TYPE_PARSER(construct(scalarIntExpr) || - construct("*" >> maybe(scalarIntExpr))) + construct("*" >> construct>())) TYPE_PARSER(construct(nonemptyList(Parser{}))) +// tile size is one of: +// * (represented as an empty std::optional) +// constant-int-expr +TYPE_PARSER(construct(scalarIntConstantExpr) || + construct( + "*" >> construct>())) +TYPE_PARSER(construct(nonemptyList(Parser{}))) + // 2.9 (1607) gang-arg is one of: // [num:]int-expr // static:size-expr diff --git a/flang/lib/Semantics/canonicalize-acc.cpp b/flang/lib/Semantics/canonicalize-acc.cpp --- a/flang/lib/Semantics/canonicalize-acc.cpp +++ b/flang/lib/Semantics/canonicalize-acc.cpp @@ -48,6 +48,40 @@ } private: + // Check constraint in 2.9.7 + // If there are n tile sizes in the list, the loop construct must be + // immediately followed by n tightly-nested loops. + template + void CheckTileClauseRestriction(const C &x) { + const auto &beginLoopDirective = std::get(x.t); + const auto &accClauseList = + std::get(beginLoopDirective.t); + for (const auto &clause : accClauseList.v) { + if (const auto *tileClause = + std::get_if(&clause.u)) { + const parser::AccTileExprList &tileExprList = tileClause->v; + const std::list &listTileExpr = tileExprList.v; + std::size_t tileArgNb = listTileExpr.size(); + + const auto &outer{std::get>(x.t)}; + for (const parser::DoConstruct *loop{&*outer}; loop && tileArgNb > 0; + --tileArgNb) { + const auto &block{std::get(loop->t)}; + const auto it{block.begin()}; + loop = it != block.end() ? parser::Unwrap(*it) + : nullptr; + } + + if (tileArgNb > 0) { + messages_.Say(beginLoopDirective.source, + "The loop construct with the TILE clause must be followed by %d " + "tightly-nested loops"_err_en_US, + listTileExpr.size()); + } + } + } + } + void RewriteOpenACCLoopConstruct(parser::OpenACCLoopConstruct &x, parser::Block &block, parser::Block::iterator it) { // Check the sequence of DoConstruct in the same iteration @@ -78,6 +112,8 @@ "DO loop after the %s directive must have loop control"_err_en_US, parser::ToUpperCaseLetters(dir.source.ToString())); } + CheckTileClauseRestriction(x); return; // found do-loop } } @@ -127,6 +163,8 @@ "DO loop after the %s directive must have loop control"_err_en_US, parser::ToUpperCaseLetters(dir.source.ToString())); } + CheckTileClauseRestriction(x); return; // found do-loop } } diff --git a/flang/test/Semantics/acc-canonicalization-validity.f90 b/flang/test/Semantics/acc-canonicalization-validity.f90 --- a/flang/test/Semantics/acc-canonicalization-validity.f90 +++ b/flang/test/Semantics/acc-canonicalization-validity.f90 @@ -92,4 +92,18 @@ do end do + !$acc parallel + !ERROR: The loop construct with the TILE clause must be followed by 2 tightly-nested loops + !$acc loop tile(2, 2) + do i = 1, N + a(i) = 3.14 + end do + !$acc end parallel + + !ERROR: The loop construct with the TILE clause must be followed by 2 tightly-nested loops + !$acc parallel loop tile(2, 2) + do i = 1, N + a(i) = 3.14 + end do + end program openacc_clause_validity diff --git a/flang/test/Semantics/acc-clause-validity.f90 b/flang/test/Semantics/acc-clause-validity.f90 --- a/flang/test/Semantics/acc-clause-validity.f90 +++ b/flang/test/Semantics/acc-clause-validity.f90 @@ -24,6 +24,7 @@ logical, dimension(N) :: d, e real :: reduction_r logical :: reduction_l + real(8), dimension(N, N) :: aa !ERROR: At least one clause is required on the DECLARE directive !$acc declare @@ -83,6 +84,25 @@ end do !$acc end parallel + !$acc parallel + !$acc loop tile(2) + do i = 1, N + a(i) = 3.14 + end do + !$acc end parallel + + !$acc parallel loop tile(2) + do i = 1, N + a(i) = 3.14 + end do + + !$acc parallel loop tile(2, 2) + do i = 1, N + do j = 1, N + aa(i, j) = 3.14 + end do + end do + !$acc parallel device_type(*) num_gangs(2) !$acc loop do i = 1, N diff --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td --- a/llvm/include/llvm/Frontend/OpenACC/ACC.td +++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td @@ -192,7 +192,7 @@ // 2.9.7 def ACCC_Tile : Clause <"tile"> { - let flangClassValue = "AccSizeExprList"; + let flangClassValue = "AccTileExprList"; } // 2.8.1