[llvm-branch-commits] [flang] 75415b1 - Diagnose privatized array element reductions

Douglas Yung via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Aug 20 13:45:57 PDT 2026


Author: Tom Eccles
Date: 2026-08-20T20:43:21Z
New Revision: 75415b1b18022c56f31262c7538660101e6830e1

URL: https://github.com/llvm/llvm-project/commit/75415b1b18022c56f31262c7538660101e6830e1
DIFF: https://github.com/llvm/llvm-project/commit/75415b1b18022c56f31262c7538660101e6830e1.diff

LOG: Diagnose privatized array element reductions

Task and taskloop array-element reductions can introduce both a
reduction block argument and an implicit firstprivate block argument for
the base array. Sequential symbol binding can then select the wrong
argument for references in the construct body.

Reject these cases until lowering can distinguish the reduction element
from other uses of the base array. Keep supported array-element reduction
coverage in the existing test and move the unsupported task forms to
focused TODO tests.

Assisted-by: Codex

Added: 
    flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90

Modified: 
    flang/lib/Lower/OpenMP/OpenMP.cpp
    flang/test/Lower/OpenMP/reduction-array-element.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index eb1c0d7be5f67..376b600ea1369 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -100,6 +100,33 @@ makeObjects(llvm::ArrayRef<const semantics::Symbol *> syms) {
   return objects;
 }
 
+static bool hasPrivatizedArrayElementReduction(
+    llvm::ArrayRef<Object> reductionObjects,
+    const llvm::SetVector<const semantics::Symbol *> &privatizedSymbols) {
+  for (const Object &object : reductionObjects) {
+    if (!object.sym() || !object.ref())
+      continue;
+    std::optional<evaluate::DataRef> dataRef =
+        evaluate::ExtractDataRef(*object.ref());
+    if (!dataRef)
+      continue;
+    const auto *arrayRef = std::get_if<evaluate::ArrayRef>(&dataRef->u);
+    if (!arrayRef ||
+        llvm::any_of(arrayRef->subscript(), [](const auto &subscript) {
+          return std::holds_alternative<evaluate::Triplet>(subscript.u);
+        }))
+      continue;
+
+    const semantics::Symbol &ultimate = object.sym()->GetUltimate();
+    if (llvm::any_of(privatizedSymbols,
+                     [&](const semantics::Symbol *privatizedSymbol) {
+                       return privatizedSymbol->GetUltimate() == ultimate;
+                     }))
+      return true;
+  }
+  return false;
+}
+
 /// Structure holding the information needed to create and bind entry block
 /// arguments associated to a single clause during OpenMP lowering.
 struct ObjectEntryBlockArgsEntry {
@@ -3594,6 +3621,11 @@ genTaskOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
                            /*useDelayedPrivatization=*/true, symTable);
   dsp.processStep1(&clauseOps);
 
+  if (hasPrivatizedArrayElementReduction(inReductionObjects,
+                                         dsp.getAllSymbolsToPrivatize()))
+    TODO(loc, "TASK construct with IN_REDUCTION of an array element whose "
+              "base array is privatized");
+
   ObjectEntryBlockArgs taskArgs;
   taskArgs.priv.objects = makeObjects(dsp.getDelayedPrivSymbols());
   taskArgs.priv.vars = clauseOps.privateVars;
@@ -3859,6 +3891,15 @@ static mlir::omp::TaskloopContextOp genStandaloneTaskloop(
                            enableDelayedPrivatization, symTable);
   dsp.processStep1(&taskloopClauseOps);
 
+  if (hasPrivatizedArrayElementReduction(inReductionObjects,
+                                         dsp.getAllSymbolsToPrivatize()))
+    TODO(loc, "TASKLOOP construct with IN_REDUCTION of an array element whose "
+              "base array is privatized");
+  if (hasPrivatizedArrayElementReduction(reductionObjects,
+                                         dsp.getAllSymbolsToPrivatize()))
+    TODO(loc, "TASKLOOP construct with REDUCTION of an array element whose "
+              "base array is privatized");
+
   mlir::omp::LoopNestOperands loopNestClauseOps;
   llvm::SmallVector<const semantics::Symbol *> iv;
   genLoopNestClauses(converter, semaCtx, eval, item->clauses, loc,

diff  --git a/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90 b/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90
new file mode 100644
index 0000000000000..770f309d1d160
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90
@@ -0,0 +1,43 @@
+! RUN: split-file %s %t
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task.f90 2>&1 | FileCheck %s --check-prefix=TASK
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task.f90 2>&1 | FileCheck %s --check-prefix=TASK
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-in.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-IN
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-in.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-IN
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-reduction.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-REDUCTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-reduction.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-REDUCTION
+
+! An array element in a task reduction and the implicitly firstprivate base
+! array are represented by separate block arguments. Reject these constructs
+! until lowering can bind references to the correct argument.
+
+! TASK: not yet implemented: TASK construct with IN_REDUCTION of an array element whose base array is privatized
+! TASKLOOP-IN: not yet implemented: TASKLOOP construct with IN_REDUCTION of an array element whose base array is privatized
+! TASKLOOP-REDUCTION: not yet implemented: TASKLOOP construct with REDUCTION of an array element whose base array is privatized
+
+!--- task.f90
+subroutine task_reduction_element(a)
+  integer :: a(4)
+  !$omp taskgroup task_reduction(+: a(2))
+  !$omp task in_reduction(+: a(2))
+  a(2) = a(2) + 1
+  !$omp end task
+  !$omp end taskgroup
+end subroutine
+
+!--- taskloop-in.f90
+subroutine taskloop_in_reduction_element(a, n)
+  integer :: a(4), n
+  !$omp taskloop in_reduction(+: a(2))
+  do i = 1, n
+    a(2) = a(2) + i
+  end do
+end subroutine
+
+!--- taskloop-reduction.f90
+subroutine taskloop_reduction_element(a, n)
+  integer :: a(4), n
+  !$omp taskloop reduction(+: a(2))
+  do i = 1, n
+    a(2) = a(2) + i
+  end do
+end subroutine

diff  --git a/flang/test/Lower/OpenMP/reduction-array-element.f90 b/flang/test/Lower/OpenMP/reduction-array-element.f90
index f62f91a457735..acb24a2aecc7b 100644
--- a/flang/test/Lower/OpenMP/reduction-array-element.f90
+++ b/flang/test/Lower/OpenMP/reduction-array-element.f90
@@ -1,8 +1,8 @@
 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s --implicit-check-not=omp.reduction.element
 
 ! Array-element reductions currently use the whole-array boxed reduction path.
-! Keep lowering coverage for these constructs so that this limitation does not
-! hide failures to compile them.
+! Keep lowering coverage for the supported constructs so that this limitation
+! does not hide failures to compile them.
 
 ! CHECK: omp.declare_reduction @[[BOX_RED:add_reduction_byref_box_4xi32]] : !fir.ref<!fir.box<!fir.array<4xi32>>>
 
@@ -73,69 +73,3 @@ subroutine reduction_do_simd(a, n)
 ! CHECK: omp.wsloop reduction(byref @[[BOX_RED]] {{.*}} -> %[[WSARG:.*]] : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
 ! CHECK: omp.simd {{.*}} reduction(byref @[[BOX_RED]] %[[WSARG]] -> %{{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
 ! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
-
-subroutine task_reduction_element(a)
-  integer :: a(4)
-!$omp taskgroup task_reduction(+: a(2))
-!$omp task in_reduction(+: a(2))
-  a(2) = a(2) + 1
-!$omp end task
-!$omp end taskgroup
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtask_reduction_element
-! CHECK: omp.taskgroup task_reduction(byref @[[BOX_RED]] {{.*}} -> %{{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
-! CHECK: omp.task in_reduction(byref @[[BOX_RED]] {{.*}} -> %{{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) private({{.*}}_firstprivate_box_4xi32
-! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
-
-subroutine taskloop_in_reduction_element(a, n)
-  integer :: a(4), n
-!$omp taskloop in_reduction(+: a(2))
-  do i = 1, n
-    a(2) = a(2) + i
-  end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtaskloop_in_reduction_element
-! CHECK: omp.taskloop.context in_reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) private({{.*}}_firstprivate_box_4xi32
-! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
-
-subroutine taskloop_reduction_element(a, n)
-  integer :: a(4), n
-!$omp taskloop reduction(+: a(2))
-  do i = 1, n
-    a(2) = a(2) + i
-  end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtaskloop_reduction_element
-! CHECK: omp.taskloop.context private({{.*}}_firstprivate_box_4xi32{{.*}}) reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
-! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
-
-subroutine taskloop_reduction_mixed_use(a, n)
-  integer :: a(4), n
-!$omp taskloop reduction(+: a(2))
-  do i = 1, n
-    a(2) = a(2) + i
-    a(1) = a(1) + 1
-  end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtaskloop_reduction_mixed_use
-! CHECK: omp.taskloop.context private({{.*}}_firstprivate_box_4xi32{{.*}}) reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
-! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
-! CHECK: hlfir.designate %{{.*}} (%c1) {{.*}} -> !fir.ref<i32>
-
-subroutine taskloop_reduction_nested_index_use(a, b, n)
-  integer :: a(4), b(4), n
-!$omp taskloop reduction(+: a(2))
-  do i = 1, n
-    a(2) = a(2) + i
-    b(a(1)) = b(a(1)) + 1
-  end do
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtaskloop_reduction_nested_index_use
-! CHECK: omp.taskloop.context private({{.*}}_firstprivate_box_4xi32{{.*}}) reduction(byref @[[BOX_RED]] {{.*}} : !fir.ref<!fir.box<!fir.array<4xi32>>>) {
-! CHECK: hlfir.designate %{{.*}} (%c2) {{.*}} -> !fir.ref<i32>
-! CHECK: hlfir.designate %{{.*}} (%{{.*}}) {{.*}} -> !fir.ref<i32>


        


More information about the llvm-branch-commits mailing list