[flang-commits] [flang] [flang][OpenACC] Don't emit unstructured-loop TODO for wrappable loops (PR #222260)
Kareem Ergawy via flang-commits
flang-commits at lists.llvm.org
Wed Sep 9 00:54:27 PDT 2026
https://github.com/ergawy created https://github.com/llvm/llvm-project/pull/222260
`genOpenACCLoopFromDoConstruct` raised an NYI for any unstructured DO inside `acc kernels`. That check ran before the wrapping in `genFIR(DoConstruct)`, so a loop whose CFG is self-contained aborted lowering even though the fall-back path would have wrapped it in an `scf.execute_region`.
Skip the TODO when `isWrappableConstruct()` accepts the loop. Such a loop is not attached to a directive; it is only nested inside the kernels region.
>From 500e119f4ba7fffe64e31667ddaa5fcf44e5872b Mon Sep 17 00:00:00 2001
From: ergawy <kareem.ergawy at gmail.com>
Date: Wed, 9 Sep 2026 00:41:02 -0700
Subject: [PATCH] [flang][OpenACC] Don't emit unstructured-loop TODO for
wrappable loops
`genOpenACCLoopFromDoConstruct` raised an NYI for any unstructured DO inside `acc kernels`. That check ran before the wrapping in `genFIR(DoConstruct)`, so a loop whose CFG is self-contained aborted lowering even though the fall-back path would have wrapped it in an `scf.execute_region`.
Skip the TODO when `isWrappableConstruct()` accepts the loop. Such a loop is not attached to a directive; it is only nested inside the kernels region.
---
flang/lib/Lower/OpenACC.cpp | 8 ++-
.../Todo/do-loops-to-acc-loops-todo.f90 | 48 ----------------
flang/test/Lower/OpenACC/acc-unstructured.f90 | 55 +++++++++++++++++++
3 files changed, 62 insertions(+), 49 deletions(-)
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index d883478e49375..fb5a84ac6aaef 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -5544,10 +5544,16 @@ mlir::Operation *Fortran::lower::genOpenACCLoopFromDoConstruct(
// privatizing the induction variable, the loop may not execute correctly.
// Only do this for `acc kernels` because in `acc parallel`, scalars end
// up as implicitly firstprivate.
+ //
+ // Unstructured constructs that are safe to wrap should not emit the TODO. A
+ // wrappable loop that reaches this condition is a loop that is NOT attached
+ // to any OpenACC directives (e.g. `kernels` ops), it is just nested inside
+ // the kernels region.
if (eval.lowerAsUnstructured()) {
if (mlir::isa_and_present<mlir::acc::KernelsOp>(
mlir::acc::getEnclosingComputeOp(
- converter.getFirOpBuilder().getRegion())))
+ converter.getFirOpBuilder().getRegion())) &&
+ !Fortran::lower::pft::isWrappableConstruct(eval, semanticsContext))
TODO(converter.getCurrentLocation(),
"unstructured do loop in acc kernels");
return nullptr;
diff --git a/flang/test/Lower/OpenACC/Todo/do-loops-to-acc-loops-todo.f90 b/flang/test/Lower/OpenACC/Todo/do-loops-to-acc-loops-todo.f90
index d59091a975822..8ebb1d28c079a 100644
--- a/flang/test/Lower/OpenACC/Todo/do-loops-to-acc-loops-todo.f90
+++ b/flang/test/Lower/OpenACC/Todo/do-loops-to-acc-loops-todo.f90
@@ -1,33 +1,9 @@
! RUN: split-file %s %t
-! RUN: %not_todo_cmd bbc -fopenacc -emit-hlfir %t/do_loop_with_cycle_goto.f90 -o - 2>&1 | FileCheck %s --check-prefix=CHECK2
! RUN: %not_todo_cmd bbc -fopenacc -emit-hlfir %t/nested_goto_loop.f90 -o - 2>&1 | FileCheck %s --check-prefix=CHECK3
-! RUN: %not_todo_cmd bbc -fopenacc -emit-hlfir %t/nested_loop_with_inner_goto.f90 -o - 2>&1 | FileCheck %s --check-prefix=CHECK4
! RUN: %not_todo_cmd bbc -fopenacc -emit-hlfir %t/collapse_lt.f90 -o - 2>&1 | FileCheck %s --check-prefix=CHECK7
! RUN: %not_todo_cmd bbc -fopenacc -emit-hlfir %t/collapse_gt.f90 -o - 2>&1 | FileCheck %s --check-prefix=CHECK8
! RUN: %not_todo_cmd bbc -fopenacc -emit-hlfir %t/collapse_nested.f90 -o - 2>&1 | FileCheck %s --check-prefix=CHECK6
-//--- do_loop_with_cycle_goto.f90
-
-subroutine do_loop_with_cycle_goto()
- integer :: i
- integer, parameter :: n = 10
- real, dimension(n) :: a, b
-
- ! Do loop with cycle and goto - unstructured control flow is not converted.
- !$acc kernels
- do i = 1, n
- if (i == 3) cycle
- a(i) = b(i) + 1.0
- if (i == 7) goto 200
- a(i) = a(i) * 2.0
- end do
-200 continue
- !$acc end kernels
-
-! CHECK2: not yet implemented: unstructured do loop in acc kernels
-
-end subroutine
-
//--- nested_goto_loop.f90
subroutine nested_goto_loop()
@@ -50,30 +26,6 @@ subroutine nested_goto_loop()
end subroutine
-//--- nested_loop_with_inner_goto.f90
-
-subroutine nested_loop_with_inner_goto()
- integer :: ii = 0, jj = 0
- integer, parameter :: nn = 3
- real, dimension(nn, nn) :: aa
-
- aa = -1
-
- ! Nested loop with goto from inner loop - unstructured control flow is not converted.
- !$acc kernels
- do ii = 1, nn
- do jj = 1, nn
- if (jj > 1) goto 300
- aa(jj, ii) = 1337
- end do
- 300 continue
- end do
- !$acc end kernels
-
-! CHECK4: not yet implemented: unstructured do loop in acc kernels
-
-end subroutine
-
//--- collapse_lt.f90
! collapse(2) over a 3-control do concurrent: collapse < control count (N < C).
diff --git a/flang/test/Lower/OpenACC/acc-unstructured.f90 b/flang/test/Lower/OpenACC/acc-unstructured.f90
index e4fb5b671f931..0c8d0859b8512 100644
--- a/flang/test/Lower/OpenACC/acc-unstructured.f90
+++ b/flang/test/Lower/OpenACC/acc-unstructured.f90
@@ -536,3 +536,58 @@ subroutine test_unstructured_parallel_loop_collapse3_stop(a)
! CHECK-LABEL: func.func @_QPtest_unstructured_parallel_loop_collapse3_stop
! CHECK: acc.parallel combined(loop)
! CHECK: acc.loop combined(parallel)
+
+! DO loop inside `!$acc kernels` whose body branches to the loop's own exit
+! (`goto 200`, plus a CYCLE). Previously flagged as "unstructured do loop in
+! acc kernels" (TODO). The branch targets the construct exit rather than
+! escaping it, so the construct is wrappable and the whole DO lowers inside an
+! scf.execute_region; no acc.loop is created for it.
+subroutine test_unstructured_kernels_do_goto_exit()
+ integer :: i
+ integer, parameter :: n = 10
+ real, dimension(n) :: a, b
+
+ !$acc kernels
+ do i = 1, n
+ if (i == 3) cycle
+ a(i) = b(i) + 1.0
+ if (i == 7) goto 200
+ a(i) = a(i) * 2.0
+ end do
+200 continue
+ !$acc end kernels
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_unstructured_kernels_do_goto_exit
+! CHECK: acc.kernels
+! CHECK: scf.execute_region
+! CHECK: scf.yield
+
+! Nested DO loops inside `!$acc kernels` where the inner loop branches to its
+! own exit (the `300 continue` between the two `end do`s). Previously flagged
+! as "unstructured do loop in acc kernels" (TODO). Only the inner loop is
+! unstructured, so the outer one still lowers as a structured acc.loop and the
+! inner one is wrapped.
+subroutine test_unstructured_kernels_inner_goto_exit()
+ integer :: ii = 0, jj = 0
+ integer, parameter :: nn = 3
+ real, dimension(nn, nn) :: aa
+
+ aa = -1
+
+ !$acc kernels
+ do ii = 1, nn
+ do jj = 1, nn
+ if (jj > 1) goto 300
+ aa(jj, ii) = 1337
+ end do
+ 300 continue
+ end do
+ !$acc end kernels
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_unstructured_kernels_inner_goto_exit
+! CHECK: acc.kernels
+! CHECK: acc.loop private({{.*}}) control({{.*}}) = ({{.*}}) to ({{.*}}) step ({{.*}}) {
+! CHECK: scf.execute_region
+! CHECK: scf.yield
More information about the flang-commits
mailing list