[flang-commits] [flang] [flang][acc] fix array-section reductions on boxed arrays (PR #211648)

Susan Tan ス-ザン タン via flang-commits flang-commits at lists.llvm.org
Thu Jul 23 12:56:34 PDT 2026


https://github.com/SusanTan updated https://github.com/llvm/llvm-project/pull/211648

>From 6166df44597b6a091a9c4da779c6962a51cbd2fc Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Thu, 23 Jul 2026 08:02:38 -0700
Subject: [PATCH 1/6] tweak

---
 flang/lib/Lower/OpenACC.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 0767511118d4f..d2eb330dbdf20 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -1148,8 +1148,6 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
     Fortran::semantics::Symbol &symbol = getSymbolFromAccObject(accObject);
     Fortran::semantics::MaybeExpr designator = Fortran::common::visit(
         [&](auto &&s) { return ea.Analyze(s); }, accObject.u);
-    bool isWholeSymbol =
-        !designator || Fortran::evaluate::UnwrapWholeSymbolDataRef(*designator);
     fir::factory::AddrAndBoundsInfo info =
         Fortran::lower::gatherDataOperandAddrAndBounds<
             mlir::acc::DataBoundsOp, mlir::acc::DataBoundsType>(
@@ -1195,7 +1193,10 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
     reductionOperands.push_back(op.getAccVar());
     // Track the symbol and its corresponding mlir::Value if requested so that
     // accesses inside the compute/loop regions use the acc.reduction variable.
-    if (dataMap && isWholeSymbol)
+    // Remap even for array-section reductions: otherwise element accesses
+    // inside the region keep referring to the original array instead of the
+    // private reduction copy.
+    if (dataMap)
       dataMap->emplaceSymbol(op.getAccVar(),
                              Fortran::semantics::SymbolRef(symbol));
   }

>From dd7e5cfa213ec190dc724a4bb3fff6ca61bd0b30 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Thu, 23 Jul 2026 12:29:53 -0700
Subject: [PATCH 2/6]  add test

---
 .../Lower/OpenACC/acc-reduction-remapping.f90 | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/flang/test/Lower/OpenACC/acc-reduction-remapping.f90 b/flang/test/Lower/OpenACC/acc-reduction-remapping.f90
index 8c69efe7e8de6..fba244be829c1 100644
--- a/flang/test/Lower/OpenACC/acc-reduction-remapping.f90
+++ b/flang/test/Lower/OpenACC/acc-reduction-remapping.f90
@@ -50,6 +50,22 @@ subroutine array_split(x, y, n)
   !$acc end parallel
 end subroutine
 
+! Array-section reduction on a dynamic-extent array: element accesses inside
+! the region must remap to the acc.reduction result rather than to the
+! original (host) declare, otherwise the private reduction copy is silently
+! bypassed and the wrong memory gets updated.
+subroutine array_section_combined(a, mm, nn)
+  integer :: mm, nn
+  real :: a(mm)
+  integer :: i, k
+  !$acc parallel loop reduction(+:a(1:16))
+  do i = 1, nn
+    do k = 1, mm
+      a(k) = a(k) + 1.0
+    end do
+  end do
+end subroutine
+
 ! CHECK-LABEL:   func.func @_QPscalar_combined(
 ! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
 ! CHECK:           %[[DECLARE_Y:.*]]:2 = hlfir.declare %{{.*}} dummy_scope %[[DUMMY_SCOPE_0]] arg 2 {uniq_name = "_QFscalar_combinedEy"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
@@ -158,3 +174,31 @@ subroutine array_split(x, y, n)
 ! CHECK:           }
 ! CHECK:           return
 ! CHECK:         }
+
+
+! CHECK-LABEL:   func.func @_QParray_section_combined(
+! CHECK:           %[[DECLARE_A:.*]]:2 = hlfir.declare %{{.*}}({{.*}}) dummy_scope {{.*}} arg 1 {uniq_name = "_QFarray_section_combinedEa"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>)
+! CHECK:           %[[BOUND0:.*]] = acc.bounds {{.*}}
+! CHECK:           %[[COPYIN:.*]] = acc.copyin var(%[[DECLARE_A]]#0 : !fir.box<!fir.array<?xf32>>) bounds(%[[BOUND0]]) -> !fir.box<!fir.array<?xf32>> {dataClause = #acc<data_clause acc_reduction>, implicit = true, name = "a(1:16)"}
+! CHECK:           acc.parallel combined(loop) dataOperands(%[[COPYIN]] : !fir.box<!fir.array<?xf32>>) {
+! CHECK:             %[[BOX_ADDR_PAR:.*]] = fir.box_addr %[[COPYIN]] : (!fir.box<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
+! CHECK:             %[[DECLARE_A_PAR:.*]]:2 = hlfir.declare %[[BOX_ADDR_PAR]]({{.*}}) dummy_scope {{.*}} arg 1 {uniq_name = "_QFarray_section_combinedEa"}
+! CHECK:             %[[BOUND1:.*]] = acc.bounds {{.*}}
+! CHECK:             %[[RED:.*]] = acc.reduction var(%[[DECLARE_A_PAR]]#0 : !fir.box<!fir.array<?xf32>>) bounds(%[[BOUND1]]) recipe(@reduction_add_section_lb0.ub15_box_Uxf32) -> !fir.box<!fir.array<?xf32>> {name = "a(1:16)"}
+! CHECK:             acc.loop combined(parallel) {{.*}} reduction(%[[RED]] : !fir.box<!fir.array<?xf32>>) {{.*}} {
+! CHECK:               %[[BOX_ADDR_RED:.*]] = fir.box_addr %[[RED]] : (!fir.box<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
+! CHECK:               %[[DECLARE_A_RED:.*]]:2 = hlfir.declare %[[BOX_ADDR_RED]]({{.*}}) dummy_scope {{.*}} arg 1 {uniq_name = "_QFarray_section_combinedEa"}
+! CHECK:               acc.loop {{.*}} {
+! CHECK:                 %[[DESIGNATE_READ:.*]] = hlfir.designate %[[DECLARE_A_RED]]#0 ({{.*}}) : (!fir.box<!fir.array<?xf32>>, i64) -> !fir.ref<f32>
+! CHECK:                 {{.*}} = fir.load %[[DESIGNATE_READ]] : !fir.ref<f32>
+! CHECK:                 %[[DESIGNATE_WRITE:.*]] = hlfir.designate %[[DECLARE_A_RED]]#0 ({{.*}}) : (!fir.box<!fir.array<?xf32>>, i64) -> !fir.ref<f32>
+! CHECK:                 hlfir.assign {{.*}} to %[[DESIGNATE_WRITE]] : f32, !fir.ref<f32>
+! CHECK:                 acc.yield
+! CHECK:               }
+! CHECK:               acc.yield
+! CHECK:             }
+! CHECK:             acc.yield
+! CHECK:           }
+! CHECK:           acc.copyout accVar(%[[COPYIN]] : !fir.box<!fir.array<?xf32>>) bounds(%[[BOUND0]]) to var(%[[DECLARE_A]]#0 : !fir.box<!fir.array<?xf32>>) {dataClause = #acc<data_clause acc_reduction>, implicit = true, name = "a(1:16)"}
+! CHECK:           return
+! CHECK:         }

>From 5a2e8f716dda5cbe87727336c1ab0aebad4c18a1 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Thu, 23 Jul 2026 12:36:43 -0700
Subject: [PATCH 3/6] add test

---
 .../Lower/OpenACC/acc-reduction-remapping.f90 | 43 +++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/flang/test/Lower/OpenACC/acc-reduction-remapping.f90 b/flang/test/Lower/OpenACC/acc-reduction-remapping.f90
index fba244be829c1..659547e8b09f1 100644
--- a/flang/test/Lower/OpenACC/acc-reduction-remapping.f90
+++ b/flang/test/Lower/OpenACC/acc-reduction-remapping.f90
@@ -66,6 +66,21 @@ subroutine array_section_combined(a, mm, nn)
   end do
 end subroutine
 
+! Same as above, but the section's lower bound (11) does not coincide with
+! the array's own lower bound (1): a "shift". The reduction recipe absorbs
+! this via a base-pointer offset, so remapping must still work.
+subroutine array_section_shifted(a, mm, nn)
+  integer :: mm, nn
+  real :: a(mm)
+  integer :: i, k
+  !$acc parallel loop reduction(+:a(11:20))
+  do i = 1, nn
+    do k = 11, 20
+      a(k) = a(k) + 1.0
+    end do
+  end do
+end subroutine
+
 ! CHECK-LABEL:   func.func @_QPscalar_combined(
 ! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
 ! CHECK:           %[[DECLARE_Y:.*]]:2 = hlfir.declare %{{.*}} dummy_scope %[[DUMMY_SCOPE_0]] arg 2 {uniq_name = "_QFscalar_combinedEy"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
@@ -202,3 +217,31 @@ subroutine array_section_combined(a, mm, nn)
 ! CHECK:           acc.copyout accVar(%[[COPYIN]] : !fir.box<!fir.array<?xf32>>) bounds(%[[BOUND0]]) to var(%[[DECLARE_A]]#0 : !fir.box<!fir.array<?xf32>>) {dataClause = #acc<data_clause acc_reduction>, implicit = true, name = "a(1:16)"}
 ! CHECK:           return
 ! CHECK:         }
+
+
+! CHECK-LABEL:   func.func @_QParray_section_shifted(
+! CHECK:           %[[DECLARE_A:.*]]:2 = hlfir.declare %{{.*}}({{.*}}) dummy_scope {{.*}} arg 1 {uniq_name = "_QFarray_section_shiftedEa"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>)
+! CHECK:           %[[BOUND0:.*]] = acc.bounds lowerbound(%c10{{.*}} : index) upperbound(%c19{{.*}} : index) {{.*}}
+! CHECK:           %[[COPYIN:.*]] = acc.copyin var(%[[DECLARE_A]]#0 : !fir.box<!fir.array<?xf32>>) bounds(%[[BOUND0]]) -> !fir.box<!fir.array<?xf32>> {dataClause = #acc<data_clause acc_reduction>, implicit = true, name = "a(11:20)"}
+! CHECK:           acc.parallel combined(loop) dataOperands(%[[COPYIN]] : !fir.box<!fir.array<?xf32>>) {
+! CHECK:             %[[BOX_ADDR_PAR:.*]] = fir.box_addr %[[COPYIN]] : (!fir.box<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
+! CHECK:             %[[DECLARE_A_PAR:.*]]:2 = hlfir.declare %[[BOX_ADDR_PAR]]({{.*}}) dummy_scope {{.*}} arg 1 {uniq_name = "_QFarray_section_shiftedEa"}
+! CHECK:             %[[BOUND1:.*]] = acc.bounds lowerbound(%c10{{.*}} : index) upperbound(%c19{{.*}} : index) {{.*}}
+! CHECK:             %[[RED:.*]] = acc.reduction var(%[[DECLARE_A_PAR]]#0 : !fir.box<!fir.array<?xf32>>) bounds(%[[BOUND1]]) recipe(@reduction_add_section_lb10.ub19_box_Uxf32) -> !fir.box<!fir.array<?xf32>> {name = "a(11:20)"}
+! CHECK:             acc.loop combined(parallel) {{.*}} reduction(%[[RED]] : !fir.box<!fir.array<?xf32>>) {{.*}} {
+! CHECK:               %[[BOX_ADDR_RED:.*]] = fir.box_addr %[[RED]] : (!fir.box<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
+! CHECK:               %[[DECLARE_A_RED:.*]]:2 = hlfir.declare %[[BOX_ADDR_RED]]({{.*}}) dummy_scope {{.*}} arg 1 {uniq_name = "_QFarray_section_shiftedEa"}
+! CHECK:               acc.loop {{.*}} control(%{{.*}} : i32) = (%c11{{.*}} : i32) to (%c20{{.*}} : i32) {{.*}} {
+! CHECK:                 %[[DESIGNATE_READ:.*]] = hlfir.designate %[[DECLARE_A_RED]]#0 ({{.*}}) : (!fir.box<!fir.array<?xf32>>, i64) -> !fir.ref<f32>
+! CHECK:                 {{.*}} = fir.load %[[DESIGNATE_READ]] : !fir.ref<f32>
+! CHECK:                 %[[DESIGNATE_WRITE:.*]] = hlfir.designate %[[DECLARE_A_RED]]#0 ({{.*}}) : (!fir.box<!fir.array<?xf32>>, i64) -> !fir.ref<f32>
+! CHECK:                 hlfir.assign {{.*}} to %[[DESIGNATE_WRITE]] : f32, !fir.ref<f32>
+! CHECK:                 acc.yield
+! CHECK:               }
+! CHECK:               acc.yield
+! CHECK:             }
+! CHECK:             acc.yield
+! CHECK:           }
+! CHECK:           acc.copyout accVar(%[[COPYIN]] : !fir.box<!fir.array<?xf32>>) bounds(%[[BOUND0]]) to var(%[[DECLARE_A]]#0 : !fir.box<!fir.array<?xf32>>) {dataClause = #acc<data_clause acc_reduction>, implicit = true, name = "a(11:20)"}
+! CHECK:           return
+! CHECK:         }

>From ff59ade8b77629f6af95d1a3d93cfdb2ec7f5734 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Thu, 23 Jul 2026 12:46:26 -0700
Subject: [PATCH 4/6] add nyi

---
 flang/lib/Lower/OpenACC.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index d2eb330dbdf20..7b2b6a49e788f 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -1169,13 +1169,13 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
     mlir::acc::ReductionOperator mlirOp =
         getReductionOperator(op, reductionTy, converter);
 
-    if (designator) {
-      Fortran::semantics::SomeExpr someExpr = *designator;
-      if (Fortran::lower::detail::getRef<Fortran::evaluate::Component>(
-              someExpr)) {
-        TODO(operandLocation,
-             "OpenACC reduction with component reference not yet supported");
-      }
+    // getRef<Component> only matches a bare component reference (e.g. x%s).
+    // For a component array section (e.g. x%a(1:16)) the DataRef is an
+    // ArrayRef whose base is the Component, so use the same helper
+    // genDataOperandOperations relies on to detect both shapes.
+    if (extractComponentFromDesignator(designator)) {
+      TODO(operandLocation,
+           "OpenACC reduction with component reference not yet supported");
     }
 
     auto op = createDataEntryOp<mlir::acc::ReductionOp>(

>From 29283460344ce20bafcc19c48bff326f28214d48 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Thu, 23 Jul 2026 12:46:59 -0700
Subject: [PATCH 5/6] tweak

---
 flang/lib/Lower/OpenACC.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 7b2b6a49e788f..67ac4fe87265f 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -1169,10 +1169,6 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
     mlir::acc::ReductionOperator mlirOp =
         getReductionOperator(op, reductionTy, converter);
 
-    // getRef<Component> only matches a bare component reference (e.g. x%s).
-    // For a component array section (e.g. x%a(1:16)) the DataRef is an
-    // ArrayRef whose base is the Component, so use the same helper
-    // genDataOperandOperations relies on to detect both shapes.
     if (extractComponentFromDesignator(designator)) {
       TODO(operandLocation,
            "OpenACC reduction with component reference not yet supported");

>From e05288faae584200724663ceb14596a998d0cc34 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Thu, 23 Jul 2026 12:56:19 -0700
Subject: [PATCH 6/6] add test

---
 .../OpenACC/Todo/acc-reduction-component.f90  | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 flang/test/Lower/OpenACC/Todo/acc-reduction-component.f90

diff --git a/flang/test/Lower/OpenACC/Todo/acc-reduction-component.f90 b/flang/test/Lower/OpenACC/Todo/acc-reduction-component.f90
new file mode 100644
index 0000000000000..8d6dca174cdc3
--- /dev/null
+++ b/flang/test/Lower/OpenACC/Todo/acc-reduction-component.f90
@@ -0,0 +1,22 @@
+! RUN: %not_todo_cmd bbc -fopenacc -emit-hlfir %s -o - 2>&1 | FileCheck %s
+
+! CHECK: not yet implemented: OpenACC reduction with component reference not yet supported
+
+module m_reduction_component
+  type :: t
+    real :: a(20)
+  end type
+contains
+  subroutine component_array_section_reduction(x, nn)
+    integer, intent(in) :: nn
+    type(t), intent(inout) :: x
+    integer :: i, k
+
+    !$acc parallel loop reduction(+:x%a(1:16))
+    do i = 1, nn
+      do k = 1, 16
+        x%a(k) = x%a(k) + 1.0
+      end do
+    end do
+  end subroutine component_array_section_reduction
+end module m_reduction_component



More information about the flang-commits mailing list