[flang-commits] [flang] [flang][openacc] Support labeled do loop in acc compute region (PR #217174)

Valentin Clement バレンタイン クレメン via flang-commits flang-commits at lists.llvm.org
Tue Aug 18 17:16:45 PDT 2026


https://github.com/clementval created https://github.com/llvm/llvm-project/pull/217174

None

>From 342e8f5993df4776844902955e7ee79d1cb97847 Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Tue, 18 Aug 2026 17:16:11 -0700
Subject: [PATCH] [flang][openacc] Support labeled do loop in acc compute
 region

---
 flang/lib/Parser/openacc-parsers.cpp | 75 +++++++++++++++++++++++++++-
 flang/test/Parser/acc-label-do.f90   | 33 ++++++++++++
 2 files changed, 106 insertions(+), 2 deletions(-)
 create mode 100644 flang/test/Parser/acc-label-do.f90

diff --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp
index 9ae917f3f8fff..738eea115020a 100644
--- a/flang/lib/Parser/openacc-parsers.cpp
+++ b/flang/lib/Parser/openacc-parsers.cpp
@@ -15,6 +15,10 @@
 #include "token-parsers.h"
 #include "type-parser-implementation.h"
 #include "flang/Parser/parse-tree.h"
+#include "flang/Parser/tools.h"
+#include "flang/Parser/user-state.h"
+
+#include <set>
 
 // OpenACC Directives and Clauses
 namespace Fortran::parser {
@@ -163,6 +167,72 @@ TYPE_PARSER(sourced(construct<AccStandaloneDirective>(
         "SET" >> pure(llvm::acc::Directive::ACCD_set),
         "UPDATE" >> pure(llvm::acc::Directive::ACCD_update)))))
 
+// A non-block DO construct, e.g.
+//   do 10 i = 1, n
+//   10 continue
+// is parsed as a flat sequence of statements and is only turned into a
+// DoConstruct later, when the DO loops are canonicalized.  The DO loop
+// associated with an OpenACC loop or combined construct has to be recognized
+// while parsing the construct, otherwise the end directive that follows the
+// loop cannot be attached to the construct.  Build the DoConstruct here, the
+// same way the canonicalization of the DO loops would have built it.
+struct AccNonBlockDoConstruct {
+  using resultType = DoConstruct;
+
+  std::optional<DoConstruct> Parse(ParseState &state) const {
+    auto doStmt{CapturedLabelDoStmt::Parse(state)};
+    if (!doStmt) {
+      return std::nullopt;
+    }
+
+    // Parse execution part constructs until every label DO statement that has
+    // been seen is terminated by a statement carrying its label.  Loops that
+    // share the same label are all terminated by the same statement.
+    std::set<Label> labels{std::get<Label>(doStmt->statement.value().t)};
+    Block body;
+    while (!labels.empty()) {
+      auto epc{executionPartConstruct.Parse(state)};
+      if (!epc) {
+        return std::nullopt;
+      }
+      if (std::optional<Label> label{GetStatementLabel(*epc)}) {
+        labels.erase(*label);
+      } else if (auto *acc{Unwrap<OpenACCConstruct>(*epc)}) {
+        if (std::optional<Label> label{GetFinalLabel(*acc)}) {
+          labels.erase(*label);
+        }
+      }
+      if (auto *labelDo{Unwrap<LabelDoStmt>(*epc)}) {
+        labels.insert(std::get<Label>(labelDo->t));
+      }
+      body.emplace_back(std::move(*epc));
+    }
+
+    // The terminating statement of the outermost loop may be an END DO
+    // statement; the DO construct built below has its own synthetic one, so
+    // turn it into a CONTINUE statement to keep its label.
+    if (Unwrap<EndDoStmt>(body.back())) {
+      std::get<ExecutableConstruct>(body.back().u).u =
+          Statement<ActionStmt>{GetStatementLabel(body.back()), ContinueStmt{}};
+    }
+
+    Statement<NonLabelDoStmt> nonLabelDoStmt{std::move(doStmt->label),
+        NonLabelDoStmt{
+            std::make_tuple(std::optional<Name>{}, std::optional<Label>{},
+                std::move(std::get<std::optional<LoopControl>>(
+                    doStmt->statement.value().t)))}};
+    nonLabelDoStmt.source = doStmt->source;
+    return DoConstruct{
+        std::make_tuple(std::move(nonLabelDoStmt), std::move(body),
+            Statement<EndDoStmt>{
+                std::optional<Label>{}, EndDoStmt{std::optional<Name>{}}})};
+  }
+};
+
+// The DO loop associated with a loop or combined construct.
+constexpr auto accAssociatedDoConstruct{
+    Parser<DoConstruct>{} || AccNonBlockDoConstruct{}};
+
 // Loop directives
 TYPE_PARSER(sourced(construct<AccLoopDirective>(
     first("LOOP" >> pure(llvm::acc::Directive::ACCD_loop)))))
@@ -173,7 +243,8 @@ TYPE_PARSER(sourced(construct<AccBeginLoopDirective>(
 TYPE_PARSER(construct<AccEndLoop>("END LOOP"_tok))
 
 TYPE_PARSER(construct<OpenACCLoopConstruct>(
-    Parser<AccBeginLoopDirective>{} / endAccLine, maybe(Parser<DoConstruct>{}),
+    Parser<AccBeginLoopDirective>{} / endAccLine,
+    maybe(accAssociatedDoConstruct),
     maybe(startAccLine >> Parser<AccEndLoop>{} / endAccLine)))
 
 // 2.15.1 Routine directive
@@ -301,7 +372,7 @@ TYPE_PARSER(startAccLine >>
 
 TYPE_PARSER(sourced(construct<OpenACCCombinedConstruct>(
     Parser<AccBeginCombinedDirective>{} / endAccLine,
-    maybe(Parser<DoConstruct>{}),
+    maybe(accAssociatedDoConstruct),
     maybe(Parser<AccEndCombinedDirective>{} / endAccLine))))
 
 } // namespace Fortran::parser
diff --git a/flang/test/Parser/acc-label-do.f90 b/flang/test/Parser/acc-label-do.f90
new file mode 100644
index 0000000000000..5bfe1f3de7ca2
--- /dev/null
+++ b/flang/test/Parser/acc-label-do.f90
@@ -0,0 +1,33 @@
+! RUN: %flang_fc1 -fopenacc -fdebug-unparse %s | FileCheck --ignore-case --check-prefix=UNPARSE %s
+! RUN: %flang_fc1 -fopenacc -fdebug-dump-parse-tree %s | FileCheck --check-prefix=PARSE-TREE %s
+
+! Combined constructs associated with a non-block (labeled) DO loop must still
+! accept an optional end directive that follows the terminating labeled
+! statement.
+
+subroutine s
+  integer :: i, n
+!$acc parallel loop
+  do 10 i = 1, n
+10 continue
+!$acc end parallel
+end
+
+!UNPARSE: SUBROUTINE s
+!UNPARSE:  INTEGER i, n
+!UNPARSE: !$ACC PARALLEL LOOP
+!UNPARSE:  DO i=1_4,n
+!UNPARSE:   10 CONTINUE
+!UNPARSE:  END DO
+!UNPARSE: !$ACC END PARALLEL LOOP
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OpenACCCombinedConstruct
+!PARSE-TREE: | AccBeginCombinedDirective
+!PARSE-TREE: | | AccCombinedDirective -> llvm::acc::Directive = parallel loop
+!PARSE-TREE: | DoConstruct
+!PARSE-TREE: | | NonLabelDoStmt
+!PARSE-TREE: | | Block
+!PARSE-TREE: | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> ContinueStmt
+!PARSE-TREE: | | EndDoStmt ->
+!PARSE-TREE: | AccEndCombinedDirective -> AccCombinedDirective -> llvm::acc::Directive = parallel loop



More information about the flang-commits mailing list