[flang-commits] [flang] [flang] Fix crash when GoTo exits acc.loop region (PR #187613)

via flang-commits flang-commits at lists.llvm.org
Thu Mar 19 22:16:36 PDT 2026


https://github.com/khaki3 updated https://github.com/llvm/llvm-project/pull/187613

>From dcdad97b8f4b60d55f32f07d7eeba95d63426bbb Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Thu, 19 Mar 2026 17:14:13 -0700
Subject: [PATCH 1/4] [flang] Fix crash when GoTo exits acc.loop region

When a GoTo inside an $Acc Loop Seq targets a label outside the
acc.loop's MLIR region, the lowering generated an illegal cross-region
cf.br. This caused runRegionDCE's recursive propagateLiveness to enter
a cyclic traversal through the dangling reference, overflowing the
compiler stack.

Fix by generating acc.yield (proper region exit) instead of cf.br when
the GoTo target block is in a different region than the current one.
This reuses the existing early-exit mechanism already used for RETURN
statements inside acc.loop.

Made-with: Cursor
---
 flang/lib/Lower/Bridge.cpp                    | 11 ++++++++-
 .../test/Lower/OpenACC/acc-loop-goto-exit.f90 | 24 +++++++++++++++++++
 2 files changed, 34 insertions(+), 1 deletion(-)
 create mode 100644 flang/test/Lower/OpenACC/acc-loop-goto-exit.f90

diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 7459f814a0d4d..e14912017ae7d 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -6239,7 +6239,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     genConstructExitBranch(*getEval().controlSuccessor);
   }
   void genFIR(const Fortran::parser::GotoStmt &) {
-    genConstructExitBranch(*getEval().controlSuccessor);
+    auto &targetEval = *getEval().controlSuccessor;
+    if (Fortran::lower::isInOpenACCLoop(*builder)) {
+      mlir::Block *targetBlock = targetEval.block;
+      mlir::Region *currentRegion = &builder->getRegion();
+      if (targetBlock && targetBlock->getParent() != currentRegion) {
+        mlir::acc::YieldOp::create(*builder, toLocation());
+        return;
+      }
+    }
+    genConstructExitBranch(targetEval);
   }
 
   // Nop statements - No code, or code is generated at the construct level.
diff --git a/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90 b/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
new file mode 100644
index 0000000000000..88fc30d79c3d1
--- /dev/null
+++ b/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
@@ -0,0 +1,24 @@
+! Test that GoTo exiting an acc.loop seq region generates acc.yield
+! instead of an illegal cross-region cf.br that would crash the compiler.
+! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: func.func @_QPfoo
+subroutine foo(N, A, B)
+  implicit real*8 (a-h, o-z)
+  !$acc routine gang
+  dimension A(*), B(*)
+  !$acc loop gang vector
+  do 100 i = 1, N
+  ! CHECK: acc.loop gang vector
+  ! CHECK: acc.loop
+  !$acc loop seq
+    do 10 j = 1, 1000
+      if (A(i) .gt. B(i)) goto 20
+10  continue
+  ! The GoTo crossing the acc.loop region boundary must generate
+  ! acc.yield (not cf.br) to properly exit the inner acc.loop.
+  ! CHECK: acc.yield
+  ! CHECK: acc.yield
+20  B(i) = A(i)
+100 continue
+end subroutine

>From 3cf4d749406a8c2a153a65157d94d1505aaa4fa0 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Thu, 19 Mar 2026 22:03:36 -0700
Subject: [PATCH 2/4] [flang] Update lit test: use -emit-hlfir and fix CHECK
 lines

Made-with: Cursor
---
 flang/test/Lower/OpenACC/acc-loop-goto-exit.f90 | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90 b/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
index 88fc30d79c3d1..fc7b036b0cef1 100644
--- a/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
+++ b/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
@@ -1,6 +1,6 @@
 ! Test that GoTo exiting an acc.loop seq region generates acc.yield
 ! instead of an illegal cross-region cf.br that would crash the compiler.
-! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s
+! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s
 
 ! CHECK-LABEL: func.func @_QPfoo
 subroutine foo(N, A, B)
@@ -10,15 +10,17 @@ subroutine foo(N, A, B)
   !$acc loop gang vector
   do 100 i = 1, N
   ! CHECK: acc.loop gang vector
-  ! CHECK: acc.loop
+  ! CHECK: acc.loop {{.*}} {
   !$acc loop seq
     do 10 j = 1, 1000
       if (A(i) .gt. B(i)) goto 20
 10  continue
   ! The GoTo crossing the acc.loop region boundary must generate
-  ! acc.yield (not cf.br) to properly exit the inner acc.loop.
+  ! acc.yield to properly exit the inner acc.loop, not an illegal
+  ! cross-region cf.br that would crash the compiler.
   ! CHECK: acc.yield
   ! CHECK: acc.yield
+  ! CHECK: }
 20  B(i) = A(i)
 100 continue
 end subroutine

>From 17b8cc322a7b5680b42779134c79def31fb10957 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Thu, 19 Mar 2026 22:10:45 -0700
Subject: [PATCH 3/4] [flang] Improve lit test: use -emit-hlfir, check
 seq+unstructured attrs

Made-with: Cursor
---
 flang/test/Lower/OpenACC/acc-loop-goto-exit.f90 | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90 b/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
index fc7b036b0cef1..ff6d7ca4aef25 100644
--- a/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
+++ b/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
@@ -9,18 +9,18 @@ subroutine foo(N, A, B)
   dimension A(*), B(*)
   !$acc loop gang vector
   do 100 i = 1, N
-  ! CHECK: acc.loop gang vector
-  ! CHECK: acc.loop {{.*}} {
   !$acc loop seq
     do 10 j = 1, 1000
       if (A(i) .gt. B(i)) goto 20
 10  continue
-  ! The GoTo crossing the acc.loop region boundary must generate
-  ! acc.yield to properly exit the inner acc.loop, not an illegal
-  ! cross-region cf.br that would crash the compiler.
-  ! CHECK: acc.yield
-  ! CHECK: acc.yield
-  ! CHECK: }
 20  B(i) = A(i)
 100 continue
 end subroutine
+
+! Verify the inner acc.loop has seq and unstructured attributes,
+! and that it contains acc.yield (from the GoTo cross-region exit).
+! CHECK: acc.loop gang vector
+! CHECK: acc.loop
+! CHECK: acc.yield
+! CHECK: acc.yield
+! CHECK: } attributes {seq = [#acc.device_type<none>], unstructured}

>From 5db6701c4765f9eb8d4c627830e87fcf25377349 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Thu, 19 Mar 2026 22:16:23 -0700
Subject: [PATCH 4/4] [flang] Use CHECK-NEXT in lit test for precise matching

Made-with: Cursor
---
 flang/test/Lower/OpenACC/acc-loop-goto-exit.f90 | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90 b/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
index ff6d7ca4aef25..696051b9bb534 100644
--- a/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
+++ b/flang/test/Lower/OpenACC/acc-loop-goto-exit.f90
@@ -17,10 +17,17 @@ subroutine foo(N, A, B)
 100 continue
 end subroutine
 
-! Verify the inner acc.loop has seq and unstructured attributes,
-! and that it contains acc.yield (from the GoTo cross-region exit).
+! Verify the inner acc.loop (seq) contains acc.yield for the GoTo exit.
+! The GoTo target is outside the acc.loop region, so it must yield
+! instead of generating an illegal cross-region cf.br.
+
 ! CHECK: acc.loop gang vector
 ! CHECK: acc.loop
+! The GoTo comparison and branch:
+! CHECK: arith.cmpf ogt
+! CHECK-NEXT: cf.cond_br %{{.*}}, ^[[EXIT:bb[0-9]+]], ^
+! CHECK-NEXT: ^[[EXIT]]:
+! CHECK-NEXT: acc.yield
+! Normal loop end yield and closing:
 ! CHECK: acc.yield
-! CHECK: acc.yield
-! CHECK: } attributes {seq = [#acc.device_type<none>], unstructured}
+! CHECK-NEXT: } attributes {seq = [#acc.device_type<none>], unstructured}



More information about the flang-commits mailing list