[flang-commits] [flang] [flang][OpenACC] Don't emit unstructured-loop TODO for wrappable loops (PR #222260)

via flang-commits flang-commits at lists.llvm.org
Wed Sep 9 00:55:02 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Kareem Ergawy (ergawy)

<details>
<summary>Changes</summary>

`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.

---
Full diff: https://github.com/llvm/llvm-project/pull/222260.diff


3 Files Affected:

- (modified) flang/lib/Lower/OpenACC.cpp (+7-1) 
- (modified) flang/test/Lower/OpenACC/Todo/do-loops-to-acc-loops-todo.f90 (-48) 
- (modified) flang/test/Lower/OpenACC/acc-unstructured.f90 (+55) 


``````````diff
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

``````````

</details>


https://github.com/llvm/llvm-project/pull/222260


More information about the flang-commits mailing list