[flang-commits] [flang] 760eca1 - [flang][openacc] Accept !$acc end loop

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Tue Aug 29 09:19:25 PDT 2023


Author: Valentin Clement
Date: 2023-08-29T09:17:24-07:00
New Revision: 760eca1d1079d46e430722c8d8999b327b083240

URL: https://github.com/llvm/llvm-project/commit/760eca1d1079d46e430722c8d8999b327b083240
DIFF: https://github.com/llvm/llvm-project/commit/760eca1d1079d46e430722c8d8999b327b083240.diff

LOG: [flang][openacc] Accept !$acc end loop

Some compilers accept `!$acc end loop` associated with an `!$acc loop`
directive. This patch updates the acc loop parser to accept it as well.
The parser is also updated to be stricter on the following statement
to match the OpenACC combined construct parser.
The rewrite canonicalization is not a rewrite anymore and the naming
will be updated in a follow up patch for the Loop and Combined constructs.

Reviewed By: razvanlupusoru

Differential Revision: https://reviews.llvm.org/D159015

Added: 
    flang/test/Semantics/OpenACC/acc-loop-validity.f90

Modified: 
    flang/docs/OpenACC.md
    flang/include/flang/Parser/dump-parse-tree.h
    flang/include/flang/Parser/parse-tree.h
    flang/lib/Parser/openacc-parsers.cpp
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/canonicalize-acc.cpp
    flang/lib/Semantics/resolve-directives.cpp
    flang/test/Semantics/OpenACC/acc-canonicalization-validity.f90
    flang/test/Semantics/OpenACC/acc-loop.f90

Removed: 
    


################################################################################
diff  --git a/flang/docs/OpenACC.md b/flang/docs/OpenACC.md
index c63fcd9a9daa01..79b7e3000b02aa 100644
--- a/flang/docs/OpenACC.md
+++ b/flang/docs/OpenACC.md
@@ -17,3 +17,4 @@
 * The end directive for combined construct can omit the `loop` keyword.
 * An `!$acc routine` with no parallelism clause is treated as if the `seq`
   clause was present.
+* `!$acc end loop` does not trigger a parsing error and is just ignored.

diff  --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 97e93dae84df35..7a009e8cc70828 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -105,6 +105,7 @@ class ParseTreeDumper {
   NODE(parser, AccTileExpr)
   NODE(parser, AccTileExprList)
   NODE(parser, AccLoopDirective)
+  NODE(parser, AccEndLoop)
   NODE(parser, AccWaitArgument)
   static std::string GetNodeName(const llvm::acc::Directive &x) {
     return llvm::Twine(

diff  --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index e70f5aeae117e6..d8449c8b812ae2 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4244,11 +4244,10 @@ struct OpenACCDeclarativeConstruct {
 };
 
 // OpenACC directives enclosing do loop
+EMPTY_CLASS(AccEndLoop);
 struct OpenACCLoopConstruct {
   TUPLE_CLASS_BOILERPLATE(OpenACCLoopConstruct);
-  OpenACCLoopConstruct(AccBeginLoopDirective &&a)
-      : t({std::move(a), std::nullopt}) {}
-  std::tuple<AccBeginLoopDirective, std::optional<DoConstruct>> t;
+  std::tuple<AccBeginLoopDirective, DoConstruct, std::optional<AccEndLoop>> t;
 };
 
 struct OpenACCStandaloneConstruct {

diff  --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp
index dff95decad3f4e..afa12b88019bd9 100644
--- a/flang/lib/Parser/openacc-parsers.cpp
+++ b/flang/lib/Parser/openacc-parsers.cpp
@@ -150,8 +150,13 @@ TYPE_PARSER(sourced(construct<AccLoopDirective>(
 TYPE_PARSER(construct<AccBeginLoopDirective>(
     sourced(Parser<AccLoopDirective>{}), Parser<AccClauseList>{}))
 
-TYPE_PARSER(
-    construct<OpenACCLoopConstruct>(sourced(Parser<AccBeginLoopDirective>{})))
+TYPE_PARSER(construct<AccEndLoop>(startAccLine >> "END LOOP"_tok))
+
+TYPE_PARSER(construct<OpenACCLoopConstruct>(
+    sourced(Parser<AccBeginLoopDirective>{} / endAccLine),
+    withMessage("A DO loop must follow the loop construct"_err_en_US,
+        Parser<DoConstruct>{}),
+    maybe(Parser<AccEndLoop>{} / endAccLine)))
 
 // 2.15.1 Routine directive
 TYPE_PARSER(sourced(construct<OpenACCRoutineConstruct>(verbatim("ROUTINE"_tok),

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index d86049886fc32c..d7626c0ea76293 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -1947,7 +1947,7 @@ class UnparseVisitor {
     Walk(std::get<AccBeginLoopDirective>(x.t));
     Put("\n");
     EndOpenACC();
-    Walk(std::get<std::optional<DoConstruct>>(x.t));
+    Walk(std::get<DoConstruct>(x.t));
   }
   void Unparse(const AccBeginLoopDirective &x) {
     Walk(std::get<AccLoopDirective>(x.t));

diff  --git a/flang/lib/Semantics/canonicalize-acc.cpp b/flang/lib/Semantics/canonicalize-acc.cpp
index 5ad8257bec6945..e79ab997637b08 100644
--- a/flang/lib/Semantics/canonicalize-acc.cpp
+++ b/flang/lib/Semantics/canonicalize-acc.cpp
@@ -52,7 +52,8 @@ class CanonicalizationOfAcc {
   // If there are n tile sizes in the list, the loop construct must be
   // immediately followed by n tightly-nested loops.
   template <typename C, typename D>
-  void CheckTileClauseRestriction(const C &x) {
+  void CheckTileClauseRestriction(
+      const C &x, const parser::DoConstruct &outer) {
     const auto &beginLoopDirective = std::get<D>(x.t);
     const auto &accClauseList =
         std::get<parser::AccClauseList>(beginLoopDirective.t);
@@ -63,11 +64,10 @@ class CanonicalizationOfAcc {
         const std::list<parser::AccTileExpr> &listTileExpr = tileExprList.v;
         std::size_t tileArgNb = listTileExpr.size();
 
-        const auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)};
-        if (outer->IsDoConcurrent()) {
+        if (outer.IsDoConcurrent()) {
           return; // Tile is not allowed on DO CONCURRENT
         }
-        for (const parser::DoConstruct *loop{&*outer}; loop && tileArgNb > 0;
+        for (const parser::DoConstruct *loop{&outer}; loop && tileArgNb > 0;
              --tileArgNb) {
           const auto &block{std::get<parser::Block>(loop->t)};
           const auto it{block.begin()};
@@ -89,9 +89,9 @@ class CanonicalizationOfAcc {
   // A tile and collapse clause may not appear on loop that is associated with
   // do concurrent.
   template <typename C, typename D>
-  void CheckDoConcurrentClauseRestriction(const C &x) {
-    const auto &doCons{std::get<std::optional<parser::DoConstruct>>(x.t)};
-    if (!doCons->IsDoConcurrent()) {
+  void CheckDoConcurrentClauseRestriction(
+      const C &x, const parser::DoConstruct &doCons) {
+    if (!doCons.IsDoConcurrent()) {
       return;
     }
     const auto &beginLoopDirective = std::get<D>(x.t);
@@ -109,73 +109,36 @@ class CanonicalizationOfAcc {
 
   void RewriteOpenACCLoopConstruct(parser::OpenACCLoopConstruct &x,
       parser::Block &block, parser::Block::iterator it) {
-    // Check the sequence of DoConstruct in the same iteration
-    //
-    // Original:
-    //   ExecutableConstruct -> OpenACCConstruct -> OpenACCLoopConstruct
-    //     ACCBeginLoopDirective
-    //   ExecutableConstruct -> DoConstruct
-    //
-    // After rewriting:
-    //   ExecutableConstruct -> OpenACCConstruct -> OpenACCLoopConstruct
-    //     AccBeginLoopDirective
-    //     DoConstruct
-    parser::Block::iterator nextIt;
     auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
     auto &dir{std::get<parser::AccLoopDirective>(beginDir.t)};
+    const auto &doCons{std::get<parser::DoConstruct>(x.t)};
 
-    nextIt = it;
-    if (++nextIt != block.end()) {
-      if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {
-        if (!doCons->GetLoopControl()) {
-          messages_.Say(dir.source,
-              "DO loop after the %s directive must have loop control"_err_en_US,
-              parser::ToUpperCaseLetters(dir.source.ToString()));
-          return;
-        }
-
-        // move DoConstruct
-        std::get<std::optional<parser::DoConstruct>>(x.t) = std::move(*doCons);
-        nextIt = block.erase(nextIt);
-
-        CheckDoConcurrentClauseRestriction<parser::OpenACCLoopConstruct,
-            parser::AccBeginLoopDirective>(x);
-        CheckTileClauseRestriction<parser::OpenACCLoopConstruct,
-            parser::AccBeginLoopDirective>(x);
-
-        return; // found do-loop
-      }
+    if (!doCons.GetLoopControl()) {
+      messages_.Say(dir.source,
+          "DO loop after the %s directive must have loop control"_err_en_US,
+          parser::ToUpperCaseLetters(dir.source.ToString()));
+      return;
     }
-    messages_.Say(dir.source,
-        "A DO loop must follow the %s directive"_err_en_US,
-        parser::ToUpperCaseLetters(dir.source.ToString()));
+
+    CheckDoConcurrentClauseRestriction<parser::OpenACCLoopConstruct,
+        parser::AccBeginLoopDirective>(x, doCons);
+    CheckTileClauseRestriction<parser::OpenACCLoopConstruct,
+        parser::AccBeginLoopDirective>(x, doCons);
   }
 
   void RewriteOpenACCCombinedConstruct(parser::OpenACCCombinedConstruct &x,
       parser::Block &block, parser::Block::iterator it) {
-    // Check the sequence of DoConstruct in the same iteration
-    //
-    // Original:
-    //   ExecutableConstruct -> OpenACCConstruct -> OpenACCCombinedConstruct
-    //     ACCBeginCombinedDirective
-    //   ExecutableConstruct -> DoConstruct
-    //   ExecutableConstruct -> AccEndCombinedDirective (if available)
-    //
-    // After rewriting:
-    //   ExecutableConstruct -> OpenACCConstruct -> OpenACCCombinedConstruct
-    //     ACCBeginCombinedDirective
-    //     DoConstruct
-    //     AccEndCombinedDirective (if available)
+    // Check the sequence of DoConstruct in the same iteration.
     parser::Block::iterator nextIt;
     auto &beginDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
     auto &dir{std::get<parser::AccCombinedDirective>(beginDir.t)};
-    auto &doConstruct{std::get<std::optional<parser::DoConstruct>>(x.t)};
+    const auto &doConstruct{std::get<std::optional<parser::DoConstruct>>(x.t)};
 
     if (doConstruct) {
       CheckDoConcurrentClauseRestriction<parser::OpenACCCombinedConstruct,
-          parser::AccBeginCombinedDirective>(x);
+          parser::AccBeginCombinedDirective>(x, *doConstruct);
       CheckTileClauseRestriction<parser::OpenACCCombinedConstruct,
-          parser::AccBeginCombinedDirective>(x);
+          parser::AccBeginCombinedDirective>(x, *doConstruct);
       if (!doConstruct->GetLoopControl()) {
         messages_.Say(dir.source,
             "DO loop after the %s directive must have loop control"_err_en_US,

diff  --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 83c44a556d19fd..c60c693072f499 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1088,8 +1088,8 @@ void AccAttributeVisitor::PrivatizeAssociatedLoopIndex(
     return nullptr;
   };
 
-  const auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)};
-  for (const parser::DoConstruct *loop{&*outer}; loop && level > 0; --level) {
+  const auto &outer{std::get<parser::DoConstruct>(x.t)};
+  for (const parser::DoConstruct *loop{&outer}; loop && level > 0; --level) {
     // go through all the nested do-loops and resolve index variables
     const parser::Name *iv{GetLoopIndex(*loop)};
     if (iv) {

diff  --git a/flang/test/Semantics/OpenACC/acc-canonicalization-validity.f90 b/flang/test/Semantics/OpenACC/acc-canonicalization-validity.f90
index b431e4fb068506..ced7dd46803eef 100644
--- a/flang/test/Semantics/OpenACC/acc-canonicalization-validity.f90
+++ b/flang/test/Semantics/OpenACC/acc-canonicalization-validity.f90
@@ -15,9 +15,7 @@ program openacc_clause_validity
   real(8) :: a(256)
   real(8) :: aa(256, 256)
 
-  !ERROR: A DO loop must follow the LOOP directive
-  !$acc loop
-  i = 1
+  i = 0
 
   !ERROR: DO loop after the LOOP directive must have loop control
   !$acc loop

diff  --git a/flang/test/Semantics/OpenACC/acc-loop-validity.f90 b/flang/test/Semantics/OpenACC/acc-loop-validity.f90
new file mode 100644
index 00000000000000..906602640efacc
--- /dev/null
+++ b/flang/test/Semantics/OpenACC/acc-loop-validity.f90
@@ -0,0 +1,15 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenacc
+
+program openacc_clause_validity
+
+  implicit none
+
+  integer :: i
+
+  i = 0
+
+  !$acc loop
+  !ERROR: A DO loop must follow the loop construct
+  i = 1
+
+end

diff  --git a/flang/test/Semantics/OpenACC/acc-loop.f90 b/flang/test/Semantics/OpenACC/acc-loop.f90
index 349ac5bd2be1cd..1c0a515441f432 100644
--- a/flang/test/Semantics/OpenACC/acc-loop.f90
+++ b/flang/test/Semantics/OpenACC/acc-loop.f90
@@ -263,4 +263,9 @@ program openacc_loop_validity
   do i = 1, N
   end do
 
+  !$acc loop
+  do i = 1, N
+  end do
+  !$acc end loop
+
 end program openacc_loop_validity


        


More information about the flang-commits mailing list