[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