[flang-commits] [flang] [flang][OpenMP] Diagnose privatized array section reductions (PR #215997)

Tom Eccles via flang-commits flang-commits at lists.llvm.org
Fri Aug 14 09:47:31 PDT 2026


https://github.com/tblah updated https://github.com/llvm/llvm-project/pull/215997

>From f98b50693c3c70f8576961fefcfc3878d436456d Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Wed, 12 Aug 2026 15:27:01 +0100
Subject: [PATCH 1/2] [flang][OpenMP] Diagnose privatized array section
 reductions

Contiguous array sections can hit the same task and taskloop
base-symbol rebinding problem as array elements. Diagnose these
cases until reduction object identity is preserved through region
binding.

Check only symbols that become delayed-private block arguments so
eager taskloop privatization remains supported. Cover task and
taskloop section diagnostics.

This issue was previously reported here:
https://github.com/llvm/llvm-project/pull/215617#discussion_r3766204295

Assisted-by: Codex
---
 flang/lib/Lower/OpenMP/OpenMP.cpp             | 35 ++++++------
 ...ction-array-element-task-privatization.f90 | 53 ++++++++++++++++---
 2 files changed, 64 insertions(+), 24 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 52edfdfdd738f..cec5d8ed24899 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -155,9 +155,9 @@ makeObjects(llvm::ArrayRef<const semantics::Symbol *> syms) {
   return objects;
 }
 
-static bool hasPrivatizedArrayElementReduction(
+static bool hasPrivatizedArrayReductionObject(
     llvm::ArrayRef<Object> reductionObjects,
-    const llvm::SetVector<const semantics::Symbol *> &privatizedSymbols) {
+    llvm::ArrayRef<const semantics::Symbol *> privatizedSymbols) {
   for (const Object &object : reductionObjects) {
     if (!object.sym() || !object.ref())
       continue;
@@ -166,10 +166,7 @@ static bool hasPrivatizedArrayElementReduction(
     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);
-        }))
+    if (!arrayRef)
       continue;
 
     const semantics::Symbol &ultimate = object.sym()->GetUltimate();
@@ -4299,10 +4296,10 @@ 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");
+  if (hasPrivatizedArrayReductionObject(inReductionObjects,
+                                        dsp.getDelayedPrivSymbols()))
+    TODO(loc, "TASK construct with IN_REDUCTION of an array element or section "
+              "whose base array is privatized");
 
   ObjectEntryBlockArgs taskArgs;
   taskArgs.priv.objects = makeObjects(dsp.getDelayedPrivSymbols());
@@ -4922,14 +4919,16 @@ 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");
+  if (hasPrivatizedArrayReductionObject(inReductionObjects,
+                                        dsp.getDelayedPrivSymbols()))
+    TODO(loc,
+         "TASKLOOP construct with IN_REDUCTION of an array element or section "
+         "whose base array is privatized");
+  if (hasPrivatizedArrayReductionObject(reductionObjects,
+                                        dsp.getDelayedPrivSymbols()))
+    TODO(loc,
+         "TASKLOOP construct with REDUCTION of an array element or section "
+         "whose base array is privatized");
 
   mlir::omp::LoopNestOperands loopNestClauseOps;
   llvm::SmallVector<const semantics::Symbol *> iv;
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
index 770f309d1d160..bdce803fed4d5 100644
--- a/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90
+++ b/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90
@@ -5,14 +5,27 @@
 ! 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
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task-section.f90 2>&1 | FileCheck %s --check-prefix=TASK-SECTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task-section.f90 2>&1 | FileCheck %s --check-prefix=TASK-SECTION
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-in-section.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-IN-SECTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-in-section.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-IN-SECTION
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-reduction-section.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-REDUCTION-SECTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-reduction-section.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-REDUCTION-SECTION
+! RUN: bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o %t/eager-in-bbc.mlir %t/taskloop-in.f90
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o %t/eager-in-fc1.mlir %t/taskloop-in.f90
+! RUN: bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o %t/eager-section-bbc.mlir %t/taskloop-reduction-section.f90
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o %t/eager-section-fc1.mlir %t/taskloop-reduction-section.f90
 
-! 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.
+! An array element or section 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: not yet implemented: TASK construct with IN_REDUCTION of an array element or section whose base array is privatized
+! TASKLOOP-IN: not yet implemented: TASKLOOP construct with IN_REDUCTION of an array element or section whose base array is privatized
+! TASKLOOP-REDUCTION: not yet implemented: TASKLOOP construct with REDUCTION of an array element or section whose base array is privatized
+! TASK-SECTION: not yet implemented: TASK construct with IN_REDUCTION of an array element or section whose base array is privatized
+! TASKLOOP-IN-SECTION: not yet implemented: TASKLOOP construct with IN_REDUCTION of an array element or section whose base array is privatized
+! TASKLOOP-REDUCTION-SECTION: not yet implemented: TASKLOOP construct with REDUCTION of an array element or section whose base array is privatized
 
 !--- task.f90
 subroutine task_reduction_element(a)
@@ -24,6 +37,34 @@ subroutine task_reduction_element(a)
   !$omp end taskgroup
 end subroutine
 
+!--- task-section.f90
+subroutine task_reduction_section(a)
+  integer :: a(4)
+  !$omp taskgroup task_reduction(+: a(2:3))
+  !$omp task in_reduction(+: a(2:3))
+  a(2:3) = a(2:3) + 1
+  !$omp end task
+  !$omp end taskgroup
+end subroutine
+
+!--- taskloop-in-section.f90
+subroutine taskloop_in_reduction_section(a, n)
+  integer :: a(4), n
+  !$omp taskloop in_reduction(+: a(2:3))
+  do i = 1, n
+    a(2:3) = a(2:3) + i
+  end do
+end subroutine
+
+!--- taskloop-reduction-section.f90
+subroutine taskloop_reduction_section(a, n)
+  integer :: a(4), n
+  !$omp taskloop reduction(+: a(2:3))
+  do i = 1, n
+    a(2:3) = a(2:3) + i
+  end do
+end subroutine
+
 !--- taskloop-in.f90
 subroutine taskloop_in_reduction_element(a, n)
   integer :: a(4), n

>From e25954558ad876d886b95bd7d0505ce71d9a4757 Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Fri, 14 Aug 2026 17:43:52 +0100
Subject: [PATCH 2/2] [flang][OpenMP] Preserve eager reduction diagnostics

Keep diagnosing taskloop array-element reductions when eager
privatization is selected. Restrict the relaxed eager behavior to array
sections while delayed privatization continues to diagnose both elements
and sections.

Extend the regression matrix to cover both taskloop reduction clause
forms in eager mode and retain positive eager array-section coverage.

Assisted-by: Codex
---
 flang/lib/Lower/OpenMP/OpenMP.cpp             | 48 ++++++++++++++-----
 ...ction-array-element-task-privatization.f90 | 14 ++++--
 2 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index cec5d8ed24899..9e130f4ba2ce2 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -157,7 +157,8 @@ makeObjects(llvm::ArrayRef<const semantics::Symbol *> syms) {
 
 static bool hasPrivatizedArrayReductionObject(
     llvm::ArrayRef<Object> reductionObjects,
-    llvm::ArrayRef<const semantics::Symbol *> privatizedSymbols) {
+    llvm::ArrayRef<const semantics::Symbol *> privatizedSymbols,
+    bool includeArraySections) {
   for (const Object &object : reductionObjects) {
     if (!object.sym() || !object.ref())
       continue;
@@ -166,7 +167,11 @@ static bool hasPrivatizedArrayReductionObject(
     if (!dataRef)
       continue;
     const auto *arrayRef = std::get_if<evaluate::ArrayRef>(&dataRef->u);
-    if (!arrayRef)
+    if (!arrayRef ||
+        (!includeArraySections &&
+         llvm::any_of(arrayRef->subscript(), [](const auto &subscript) {
+           return std::holds_alternative<evaluate::Triplet>(subscript.u);
+         })))
       continue;
 
     const semantics::Symbol &ultimate = object.sym()->GetUltimate();
@@ -4297,7 +4302,8 @@ genTaskOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
   dsp.processStep1(&clauseOps);
 
   if (hasPrivatizedArrayReductionObject(inReductionObjects,
-                                        dsp.getDelayedPrivSymbols()))
+                                        dsp.getDelayedPrivSymbols(),
+                                        /*includeArraySections=*/true))
     TODO(loc, "TASK construct with IN_REDUCTION of an array element or section "
               "whose base array is privatized");
 
@@ -4919,16 +4925,32 @@ static mlir::omp::TaskloopContextOp genStandaloneTaskloop(
                            enableDelayedPrivatization, symTable);
   dsp.processStep1(&taskloopClauseOps);
 
-  if (hasPrivatizedArrayReductionObject(inReductionObjects,
-                                        dsp.getDelayedPrivSymbols()))
-    TODO(loc,
-         "TASKLOOP construct with IN_REDUCTION of an array element or section "
-         "whose base array is privatized");
-  if (hasPrivatizedArrayReductionObject(reductionObjects,
-                                        dsp.getDelayedPrivSymbols()))
-    TODO(loc,
-         "TASKLOOP construct with REDUCTION of an array element or section "
-         "whose base array is privatized");
+  llvm::ArrayRef<const semantics::Symbol *> privatizedSymbols =
+      enableDelayedPrivatization ? dsp.getDelayedPrivSymbols()
+                                 : dsp.getAllSymbolsToPrivatize().getArrayRef();
+  if (hasPrivatizedArrayReductionObject(
+          inReductionObjects, privatizedSymbols,
+          /*includeArraySections=*/enableDelayedPrivatization)) {
+    if (enableDelayedPrivatization)
+      TODO(loc, "TASKLOOP construct with IN_REDUCTION of an array element or "
+                "section whose base array is privatized");
+    else
+      TODO(loc,
+           "TASKLOOP construct with IN_REDUCTION of an array element whose "
+           "base array is privatized");
+  }
+  if (hasPrivatizedArrayReductionObject(
+          reductionObjects, privatizedSymbols,
+          /*includeArraySections=*/enableDelayedPrivatization)) {
+    if (enableDelayedPrivatization)
+      TODO(loc,
+           "TASKLOOP construct with REDUCTION of an array element or section "
+           "whose base array is privatized");
+    else
+      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;
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
index bdce803fed4d5..7cf176b1d64b2 100644
--- a/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90
+++ b/flang/test/Lower/OpenMP/Todo/reduction-array-element-task-privatization.f90
@@ -11,10 +11,14 @@
 ! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-in-section.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-IN-SECTION
 ! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-reduction-section.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-REDUCTION-SECTION
 ! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop-reduction-section.f90 2>&1 | FileCheck %s --check-prefix=TASKLOOP-REDUCTION-SECTION
-! RUN: bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o %t/eager-in-bbc.mlir %t/taskloop-in.f90
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o %t/eager-in-fc1.mlir %t/taskloop-in.f90
-! RUN: bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o %t/eager-section-bbc.mlir %t/taskloop-reduction-section.f90
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o %t/eager-section-fc1.mlir %t/taskloop-reduction-section.f90
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o - %t/taskloop-in.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-IN
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o - %t/taskloop-in.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-IN
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o - %t/taskloop-reduction.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-REDUCTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o - %t/taskloop-reduction.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-REDUCTION
+! RUN: bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o %t/eager-in-section-bbc.mlir %t/taskloop-in-section.f90
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o %t/eager-in-section-fc1.mlir %t/taskloop-in-section.f90
+! RUN: bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o %t/eager-reduction-section-bbc.mlir %t/taskloop-reduction-section.f90
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o %t/eager-reduction-section-fc1.mlir %t/taskloop-reduction-section.f90
 
 ! An array element or section in a task reduction and the implicitly
 ! firstprivate base array are represented by separate block arguments. Reject
@@ -26,6 +30,8 @@
 ! TASK-SECTION: not yet implemented: TASK construct with IN_REDUCTION of an array element or section whose base array is privatized
 ! TASKLOOP-IN-SECTION: not yet implemented: TASKLOOP construct with IN_REDUCTION of an array element or section whose base array is privatized
 ! TASKLOOP-REDUCTION-SECTION: not yet implemented: TASKLOOP construct with REDUCTION of an array element or section whose base array is privatized
+! EAGER-TASKLOOP-IN: not yet implemented: TASKLOOP construct with IN_REDUCTION of an array element whose base array is privatized
+! EAGER-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)



More information about the flang-commits mailing list