[flang-commits] [flang] 05169af - [flang][openacc] Handle optional end directive in combined construct

via flang-commits flang-commits at lists.llvm.org
Thu Aug 13 11:05:09 PDT 2020


Author: Valentin Clement
Date: 2020-08-13T14:05:00-04:00
New Revision: 05169af5cea2c3b9aa0f38354d0e81ddf6b7a3d9

URL: https://github.com/llvm/llvm-project/commit/05169af5cea2c3b9aa0f38354d0e81ddf6b7a3d9
DIFF: https://github.com/llvm/llvm-project/commit/05169af5cea2c3b9aa0f38354d0e81ddf6b7a3d9.diff

LOG: [flang][openacc] Handle optional end directive in combined construct

OpenACC combined construct can have an optional end directive. This patch handle this
case in the parsing/unparsing with a canonicalization step. Unlike OmpEndLoopDirective,
this doesn't need a special treatment in the pre-fir tree as there is no clause attached to
a AccEndCombinedDirective.

Reviewed By: klausler

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

Added: 
    flang/test/Semantics/acc-canonicalization-validity.f90

Modified: 
    flang/include/flang/Parser/parse-tree.h
    flang/lib/Parser/executable-parsers.cpp
    flang/lib/Parser/openacc-parsers.cpp
    flang/lib/Parser/program-parsers.cpp
    flang/lib/Parser/type-parsers.h
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/canonicalize-acc.cpp
    flang/lib/Semantics/check-acc-structure.cpp
    flang/test/Lower/pre-fir-tree05.f90
    flang/test/Semantics/acc-clause-validity.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 2fecac5118d8..695121f83959 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -258,6 +258,7 @@ struct AssignStmt;
 struct AssignedGotoStmt;
 struct PauseStmt;
 struct OpenACCConstruct;
+struct AccEndCombinedDirective;
 struct OpenACCDeclarativeConstruct;
 struct OpenMPConstruct;
 struct OpenMPDeclarativeConstruct;
@@ -517,6 +518,7 @@ struct ExecutableConstruct {
       common::Indirection<WhereConstruct>, common::Indirection<ForallConstruct>,
       common::Indirection<CompilerDirective>,
       common::Indirection<OpenACCConstruct>,
+      common::Indirection<AccEndCombinedDirective>,
       common::Indirection<OpenMPConstruct>,
       common::Indirection<OmpEndLoopDirective>>
       u;
@@ -3970,6 +3972,7 @@ struct OpenACCStandaloneDeclarativeConstruct {
 
 struct AccBeginCombinedDirective {
   TUPLE_CLASS_BOILERPLATE(AccBeginCombinedDirective);
+  CharBlock source;
   std::tuple<AccCombinedDirective, AccClauseList> t;
 };
 
@@ -3981,7 +3984,9 @@ struct AccEndCombinedDirective {
 struct OpenACCCombinedConstruct {
   TUPLE_CLASS_BOILERPLATE(OpenACCCombinedConstruct);
   CharBlock source;
-  std::tuple<AccBeginCombinedDirective, Block,
+  OpenACCCombinedConstruct(AccBeginCombinedDirective &&a)
+      : t({std::move(a), std::nullopt, std::nullopt}) {}
+  std::tuple<AccBeginCombinedDirective, std::optional<DoConstruct>,
       std::optional<AccEndCombinedDirective>>
       t;
 };

diff  --git a/flang/lib/Parser/executable-parsers.cpp b/flang/lib/Parser/executable-parsers.cpp
index d6dd4688dbac..a0b5cf232abf 100644
--- a/flang/lib/Parser/executable-parsers.cpp
+++ b/flang/lib/Parser/executable-parsers.cpp
@@ -50,8 +50,9 @@ constexpr auto executableConstruct{
         construct<ExecutableConstruct>(indirect(whereConstruct)),
         construct<ExecutableConstruct>(indirect(forallConstruct)),
         construct<ExecutableConstruct>(indirect(ompEndLoopDirective)),
-        construct<ExecutableConstruct>(indirect(openaccConstruct)),
         construct<ExecutableConstruct>(indirect(openmpConstruct)),
+        construct<ExecutableConstruct>(indirect(accEndCombinedDirective)),
+        construct<ExecutableConstruct>(indirect(openaccConstruct)),
         construct<ExecutableConstruct>(indirect(compilerDirective)))};
 
 // R510 execution-part-construct ->

diff  --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp
index 0a61921c9087..823fbaec0ace 100644
--- a/flang/lib/Parser/openacc-parsers.cpp
+++ b/flang/lib/Parser/openacc-parsers.cpp
@@ -199,16 +199,9 @@ TYPE_PARSER(sourced(
         parenthesized(Parser<AccObjectListWithModifier>{}))))
 
 // 2.11 Combined constructs
-TYPE_PARSER(startAccLine >> construct<AccEndCombinedDirective>(sourced(
-                                "END"_tok >> Parser<AccCombinedDirective>{})))
-
 TYPE_PARSER(construct<AccBeginCombinedDirective>(
     sourced(Parser<AccCombinedDirective>{}), Parser<AccClauseList>{}))
 
-TYPE_PARSER(construct<OpenACCCombinedConstruct>(
-    Parser<AccBeginCombinedDirective>{} / endAccLine, block,
-    maybe(Parser<AccEndCombinedDirective>{} / endAccLine)))
-
 // 2.12 Atomic constructs
 TYPE_PARSER(construct<AccEndAtomic>(startAccLine >> "END ATOMIC"_tok))
 
@@ -281,4 +274,11 @@ TYPE_CONTEXT_PARSER("OpenACC construct"_en_US,
             construct<OpenACCConstruct>(Parser<OpenACCCacheConstruct>{}),
             construct<OpenACCConstruct>(Parser<OpenACCWaitConstruct>{}),
             construct<OpenACCConstruct>(Parser<OpenACCAtomicConstruct>{})))
+
+TYPE_PARSER(startAccLine >> sourced(construct<AccEndCombinedDirective>(sourced(
+                                "END"_tok >> Parser<AccCombinedDirective>{}))))
+
+TYPE_PARSER(construct<OpenACCCombinedConstruct>(
+    sourced(Parser<AccBeginCombinedDirective>{} / endAccLine)))
+
 } // namespace Fortran::parser

diff  --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp
index 1be1207c8626..278cc6fdb51a 100644
--- a/flang/lib/Parser/program-parsers.cpp
+++ b/flang/lib/Parser/program-parsers.cpp
@@ -76,10 +76,10 @@ TYPE_CONTEXT_PARSER("specification part"_en_US,
 // are in contexts that impose constraints on the kinds of statements that
 // are allowed, and so we have a variant production for declaration-construct
 // that implements those constraints.
-constexpr auto execPartLookAhead{first(actionStmt >> ok,
-    ompEndLoopDirective >> ok, openaccConstruct >> ok, openmpConstruct >> ok,
-    "ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok,
-    "CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok)};
+constexpr auto execPartLookAhead{
+    first(actionStmt >> ok, openaccConstruct >> ok, openmpConstruct >> ok,
+        "ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok,
+        "CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok)};
 constexpr auto declErrorRecovery{
     stmtErrorRecoveryStart >> !execPartLookAhead >> skipStmtErrorRecovery};
 constexpr auto misplacedSpecificationStmt{Parser<UseStmt>{} >>

diff  --git a/flang/lib/Parser/type-parsers.h b/flang/lib/Parser/type-parsers.h
index a2f38e90db21..d6269cbdc715 100644
--- a/flang/lib/Parser/type-parsers.h
+++ b/flang/lib/Parser/type-parsers.h
@@ -131,6 +131,7 @@ constexpr Parser<EntryStmt> entryStmt; // R1541
 constexpr Parser<ContainsStmt> containsStmt; // R1543
 constexpr Parser<CompilerDirective> compilerDirective;
 constexpr Parser<OpenACCConstruct> openaccConstruct;
+constexpr Parser<AccEndCombinedDirective> accEndCombinedDirective;
 constexpr Parser<OpenACCDeclarativeConstruct> openaccDeclarativeConstruct;
 constexpr Parser<OpenMPConstruct> openmpConstruct;
 constexpr Parser<OpenMPDeclarativeConstruct> openmpDeclarativeConstruct;

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 1093cb21709c..85ed1a2bd60b 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2104,10 +2104,9 @@ class UnparseVisitor {
     Walk(std::get<AccBeginCombinedDirective>(x.t));
     Put("\n");
     EndOpenACC();
-    Walk(std::get<Block>(x.t), "");
+    Walk(std::get<std::optional<DoConstruct>>(x.t));
     BeginOpenACC();
-    Word("!$ACC END ");
-    Walk(std::get<std::optional<AccEndCombinedDirective>>(x.t));
+    Walk("!$ACC END ", std::get<std::optional<DoConstruct>>(x.t));
     Put("\n");
     EndOpenACC();
   }

diff  --git a/flang/lib/Semantics/canonicalize-acc.cpp b/flang/lib/Semantics/canonicalize-acc.cpp
index 4c4d716fe7de..8cf04910ba6e 100644
--- a/flang/lib/Semantics/canonicalize-acc.cpp
+++ b/flang/lib/Semantics/canonicalize-acc.cpp
@@ -16,6 +16,9 @@
 //   1. move structured DoConstruct into
 //      OpenACCLoopConstruct. Compilation will not proceed in case of errors
 //      after this pass.
+//   2. move structured DoConstruct into OpenACCCombinedConstruct. Move
+//      AccEndCombinedConstruct into OpenACCCombinedConstruct if present.
+//      Compilation will not proceed in case of errors after this pass.
 namespace Fortran::semantics {
 
 using namespace parser::literals;
@@ -30,6 +33,16 @@ class CanonicalizationOfAcc {
     for (auto it{block.begin()}; it != block.end(); ++it) {
       if (auto *accLoop{parser::Unwrap<parser::OpenACCLoopConstruct>(*it)}) {
         RewriteOpenACCLoopConstruct(*accLoop, block, it);
+      } else if (auto *accCombined{
+                     parser::Unwrap<parser::OpenACCCombinedConstruct>(*it)}) {
+        RewriteOpenACCCombinedConstruct(*accCombined, block, it);
+      } else if (auto *endDir{
+                     parser::Unwrap<parser::AccEndCombinedDirective>(*it)}) {
+        // Unmatched AccEndCombinedDirective
+        messages_.Say(endDir->v.source,
+            "The %s directive must follow the DO loop associated with the "
+            "loop construct"_err_en_US,
+            parser::ToUpperCaseLetters(endDir->v.source.ToString()));
       }
     } // Block list
   }
@@ -73,6 +86,55 @@ class CanonicalizationOfAcc {
         parser::ToUpperCaseLetters(dir.source.ToString()));
   }
 
+  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)
+    parser::Block::iterator nextIt;
+    auto &beginDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
+    auto &dir{std::get<parser::AccCombinedDirective>(beginDir.t)};
+
+    nextIt = it;
+    if (++nextIt != block.end()) {
+      if (auto *doCons{parser::Unwrap<parser::DoConstruct>(*nextIt)}) {
+        if (doCons->GetLoopControl()) {
+          // move DoConstruct
+          std::get<std::optional<parser::DoConstruct>>(x.t) =
+              std::move(*doCons);
+          nextIt = block.erase(nextIt);
+          // try to match AccEndCombinedDirective
+          if (nextIt != block.end()) {
+            if (auto *endDir{
+                    parser::Unwrap<parser::AccEndCombinedDirective>(*nextIt)}) {
+              std::get<std::optional<parser::AccEndCombinedDirective>>(x.t) =
+                  std::move(*endDir);
+              block.erase(nextIt);
+            }
+          }
+        } else {
+          messages_.Say(dir.source,
+              "DO loop after the %s directive must have loop control"_err_en_US,
+              parser::ToUpperCaseLetters(dir.source.ToString()));
+        }
+        return; // found do-loop
+      }
+    }
+    messages_.Say(dir.source,
+        "A DO loop must follow the %s directive"_err_en_US,
+        parser::ToUpperCaseLetters(dir.source.ToString()));
+  }
+
   parser::Messages &messages_;
 };
 

diff  --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp
index 311a7c4d3328..4dcf5ed27f70 100644
--- a/flang/lib/Semantics/check-acc-structure.cpp
+++ b/flang/lib/Semantics/check-acc-structure.cpp
@@ -156,9 +156,17 @@ void AccStructureChecker::Leave(
 }
 
 void AccStructureChecker::Enter(const parser::OpenACCCombinedConstruct &x) {
-  const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
+  const auto &beginCombinedDir{
+      std::get<parser::AccBeginCombinedDirective>(x.t)};
   const auto &combinedDir{
-      std::get<parser::AccCombinedDirective>(beginBlockDir.t)};
+      std::get<parser::AccCombinedDirective>(beginCombinedDir.t)};
+
+  // check matching, End directive is optional
+  if (const auto &endCombinedDir{
+          std::get<std::optional<parser::AccEndCombinedDirective>>(x.t)}) {
+    CheckMatching<parser::AccCombinedDirective>(combinedDir, endCombinedDir->v);
+  }
+
   PushContextAndClauseSets(combinedDir.source, combinedDir.v);
 }
 

diff  --git a/flang/test/Lower/pre-fir-tree05.f90 b/flang/test/Lower/pre-fir-tree05.f90
index f635785e3274..98af5c2de944 100644
--- a/flang/test/Lower/pre-fir-tree05.f90
+++ b/flang/test/Lower/pre-fir-tree05.f90
@@ -31,3 +31,19 @@ subroutine foo()
 end subroutine
 ! CHECK-NEXT: EndSubroutine foo
 
+! CHECK: Subroutine foo
+subroutine foo2()
+  ! CHECK-NEXT: <<OpenACCConstruct>>
+  !$acc parallel loop
+  ! CHECK-NEXT: <<DoConstruct>>
+  ! CHECK-NEXT: NonLabelDoStmt
+  do i=1,5
+  ! CHECK-NEXT: EndDoStmt
+  ! CHECK-NEXT: <<End DoConstruct>>
+  end do
+  !$acc end parallel loop
+  ! CHECK-NEXT: <<End OpenACCConstruct>>
+  ! CHECK-NEXT: ContinueStmt
+end subroutine
+! CHECK-NEXT: EndSubroutine foo2
+

diff  --git a/flang/test/Semantics/acc-canonicalization-validity.f90 b/flang/test/Semantics/acc-canonicalization-validity.f90
new file mode 100644
index 000000000000..06c63ed25ddb
--- /dev/null
+++ b/flang/test/Semantics/acc-canonicalization-validity.f90
@@ -0,0 +1,95 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenacc
+
+! Check OpenACC canonalization validity for the construct defined below:
+!   2.9 Loop
+!   2.11 Parallel Loop
+!   2.11 Kernels Loop
+!   2.11 Serial Loop
+
+program openacc_clause_validity
+
+  implicit none
+
+  integer :: i, j
+  integer :: N = 256
+  real(8) :: a(256)
+
+  !ERROR: A DO loop must follow the LOOP directive
+  !$acc loop
+  i = 1
+
+  !ERROR: DO loop after the LOOP directive must have loop control
+  !$acc loop
+  do
+  end do
+
+  !ERROR: A DO loop must follow the PARALLEL LOOP directive
+  !$acc parallel loop
+  i = 1
+
+  !ERROR: A DO loop must follow the KERNELS LOOP directive
+  !$acc kernels loop
+  i = 1
+
+  !ERROR: A DO loop must follow the SERIAL LOOP directive
+  !$acc serial loop
+  i = 1
+
+  !ERROR: The END PARALLEL LOOP directive must follow the DO loop associated with the loop construct
+  !$acc end parallel loop
+
+  !ERROR: The END KERNELS LOOP directive must follow the DO loop associated with the loop construct
+  !$acc end kernels loop
+
+  !ERROR: The END SERIAL LOOP directive must follow the DO loop associated with the loop construct
+  !$acc end serial loop
+
+  !$acc parallel loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+
+  !$acc kernels loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+
+  !$acc serial loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+
+  !$acc parallel loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end parallel loop
+
+  !$acc kernels loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end kernels loop
+
+  !$acc serial loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end serial loop
+
+  !ERROR: DO loop after the PARALLEL LOOP directive must have loop control
+  !$acc parallel loop
+  do
+  end do
+
+  !ERROR: DO loop after the KERNELS LOOP directive must have loop control
+  !$acc kernels loop
+  do
+  end do
+
+  !ERROR: DO loop after the SERIAL LOOP directive must have loop control
+  !$acc serial loop
+  do
+  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
index 75a0efa87d35..207ca2ec72cd 100644
--- a/flang/test/Semantics/acc-clause-validity.f90
+++ b/flang/test/Semantics/acc-clause-validity.f90
@@ -5,6 +5,10 @@
 !   2.5.1 Parallel
 !   2.5.2 Kernels
 !   2.5.3 Serial
+!   2.9 Loop
+!   2.13 Declare
+!   2.14.3 Set
+!   2.14.4 Update
 !   2.15.1 Routine
 !   2.11 Parallel Loop
 !   2.11 Kernels Loop
@@ -162,6 +166,27 @@ program openacc_clause_validity
   end do
   !$acc end serial loop
 
+  !$acc parallel loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !ERROR: Unmatched END KERNELS LOOP directive
+  !$acc end kernels loop
+
+  !$acc kernels loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !ERROR: Unmatched END SERIAL LOOP directive
+  !$acc end serial loop
+
+  !$acc serial loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !ERROR: Unmatched END PARALLEL LOOP directive
+  !$acc end parallel loop
+
  contains
 
    subroutine sub1(a)


        


More information about the flang-commits mailing list