[flang-commits] [flang] [flang][openacc] Fix nested labeled DO loops sharing a terminator (PR #217705)
Valentin Clement バレンタイン クレメン via flang-commits
flang-commits at lists.llvm.org
Thu Aug 20 10:31:11 PDT 2026
https://github.com/clementval created https://github.com/llvm/llvm-project/pull/217705
When an OpenACC loop construct is associated with a non-block labeled
DO, GetFinalLabel() did not look through that construct. Nested DO
statements that share a terminating label then failed with "Label is
not in DO loop scope".
Walk the associated loop of OpenACC loop and combined constructs so the
shared label still closes the outer DO.
>From 024c3ddcc21c575d2bf7bd07dd3abbb188a44616 Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Thu, 20 Aug 2026 10:30:09 -0700
Subject: [PATCH] [flang][openacc] Fix nested labeled DO loops sharing a
terminator
---
flang/lib/Parser/tools.cpp | 19 ++++++++++++
flang/test/Parser/acc-label-do.f90 | 50 ++++++++++++++++++++++++++++++
2 files changed, 69 insertions(+)
diff --git a/flang/lib/Parser/tools.cpp b/flang/lib/Parser/tools.cpp
index ff8ab11352a72..d0c919d07f917 100644
--- a/flang/lib/Parser/tools.cpp
+++ b/flang/lib/Parser/tools.cpp
@@ -256,12 +256,31 @@ std::optional<Label> GetFinalLabel(const OpenMPConstruct &x) {
x.u);
}
+// The DO loop associated with a loop or combined construct is only terminated
+// by a labeled statement when the construct has no end directive.
+template <typename END, typename C>
+static std::optional<Label> GetFinalLabelOfAssociatedLoop(const C &x) {
+ if (std::get<std::optional<END>>(x.t)) {
+ return std::nullopt;
+ }
+ if (const auto &doLoop{std::get<std::optional<DoConstruct>>(x.t)}) {
+ return GetFinalLabel(std::get<Block>(doLoop->t));
+ }
+ return std::nullopt;
+}
+
std::optional<Label> GetFinalLabel(const OpenACCConstruct &x) {
return common::visit(
common::visitors{
[](const OpenACCBlockConstruct &x) -> std::optional<Label> {
return GetFinalLabel(std::get<Block>(x.t));
},
+ [](const OpenACCLoopConstruct &x) -> std::optional<Label> {
+ return GetFinalLabelOfAssociatedLoop<AccEndLoop>(x);
+ },
+ [](const OpenACCCombinedConstruct &x) -> std::optional<Label> {
+ return GetFinalLabelOfAssociatedLoop<AccEndCombinedDirective>(x);
+ },
[](const OpenACCAtomicConstruct &x) -> std::optional<Label> {
return common::visit(
common::visitors{
diff --git a/flang/test/Parser/acc-label-do.f90 b/flang/test/Parser/acc-label-do.f90
index 5bfe1f3de7ca2..e9de2fe59d9b2 100644
--- a/flang/test/Parser/acc-label-do.f90
+++ b/flang/test/Parser/acc-label-do.f90
@@ -31,3 +31,53 @@ subroutine s
!PARSE-TREE: | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> ContinueStmt
!PARSE-TREE: | | EndDoStmt ->
!PARSE-TREE: | AccEndCombinedDirective -> AccCombinedDirective -> llvm::acc::Directive = parallel loop
+
+! Nested labeled DO loops that share a terminating label, with an OpenACC LOOP
+! construct associated with the inner loop. The shared label must still close
+! both loops.
+
+subroutine nested_shared_label(a, n)
+ integer :: i, j, n
+ real :: a(n)
+!$acc kernels
+!$acc loop independent
+ do 10 j = 1, n
+!$acc loop gang vector
+ do 10 i = 1, n
+10 a(i) = 0.
+!$acc end kernels
+end
+
+!UNPARSE: SUBROUTINE nested_shared_label (a, n)
+!UNPARSE: !$ACC KERNELS
+!UNPARSE: !$ACC LOOP INDEPENDENT
+!UNPARSE: DO j=1_4,n
+!UNPARSE: !$ACC LOOP GANG VECTOR
+!UNPARSE: DO i=1_4,n
+!UNPARSE: 10
+!UNPARSE: END DO
+!UNPARSE: END DO
+!UNPARSE: !$ACC END KERNELS
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OpenACCBlockConstruct
+!PARSE-TREE: | AccBeginBlockDirective
+!PARSE-TREE: | | AccBlockDirective -> llvm::acc::Directive = kernels
+!PARSE-TREE: | Block
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenACCConstruct -> OpenACCLoopConstruct
+!PARSE-TREE: | | | AccBeginLoopDirective
+!PARSE-TREE: | | | | AccLoopDirective -> llvm::acc::Directive = loop
+!PARSE-TREE: | | | | AccClauseList -> AccClause -> Independent
+!PARSE-TREE: | | | DoConstruct
+!PARSE-TREE: | | | | NonLabelDoStmt
+!PARSE-TREE: | | | | Block
+!PARSE-TREE: | | | | | ExecutionPartConstruct -> ExecutableConstruct -> OpenACCConstruct -> OpenACCLoopConstruct
+!PARSE-TREE: | | | | | | AccBeginLoopDirective
+!PARSE-TREE: | | | | | | | AccLoopDirective -> llvm::acc::Directive = loop
+!PARSE-TREE: | | | | | | DoConstruct
+!PARSE-TREE: | | | | | | | NonLabelDoStmt
+!PARSE-TREE: | | | | | | | Block
+!PARSE-TREE: | | | | | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt
+!PARSE-TREE: | | | | | | | EndDoStmt ->
+!PARSE-TREE: | | | | EndDoStmt ->
+!PARSE-TREE: | AccEndBlockDirective -> AccBlockDirective -> llvm::acc::Directive = kernels
More information about the flang-commits
mailing list