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

Tom Eccles via flang-commits flang-commits at lists.llvm.org
Tue Aug 18 04:32:25 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/6] [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/6] [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)

>From a37698b04f1b77922912dc0a13acf9fba11e78b1 Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Mon, 17 Aug 2026 10:58:15 +0100
Subject: [PATCH 3/6] Diagnose eager array section reductions

Keep the taskloop reduction diagnostic for array sections when eager
privatization is selected. Eager lowering otherwise creates a reduction
for the whole base array instead of one reduction per section element.

Assisted-by: Codex
---
 flang/lib/Lower/OpenMP/OpenMP.cpp             | 43 +++++--------------
 ...ction-array-element-task-privatization.f90 | 28 +++++++++---
 2 files changed, 33 insertions(+), 38 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 9e130f4ba2ce2..19455b98b04c9 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -157,8 +157,7 @@ makeObjects(llvm::ArrayRef<const semantics::Symbol *> syms) {
 
 static bool hasPrivatizedArrayReductionObject(
     llvm::ArrayRef<Object> reductionObjects,
-    llvm::ArrayRef<const semantics::Symbol *> privatizedSymbols,
-    bool includeArraySections) {
+    llvm::ArrayRef<const semantics::Symbol *> privatizedSymbols) {
   for (const Object &object : reductionObjects) {
     if (!object.sym() || !object.ref())
       continue;
@@ -167,11 +166,7 @@ static bool hasPrivatizedArrayReductionObject(
     if (!dataRef)
       continue;
     const auto *arrayRef = std::get_if<evaluate::ArrayRef>(&dataRef->u);
-    if (!arrayRef ||
-        (!includeArraySections &&
-         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();
@@ -4302,8 +4297,7 @@ genTaskOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
   dsp.processStep1(&clauseOps);
 
   if (hasPrivatizedArrayReductionObject(inReductionObjects,
-                                        dsp.getDelayedPrivSymbols(),
-                                        /*includeArraySections=*/true))
+                                        dsp.getDelayedPrivSymbols()))
     TODO(loc, "TASK construct with IN_REDUCTION of an array element or section "
               "whose base array is privatized");
 
@@ -4928,29 +4922,14 @@ static mlir::omp::TaskloopContextOp genStandaloneTaskloop(
   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");
-  }
+  if (hasPrivatizedArrayReductionObject(inReductionObjects, privatizedSymbols))
+    TODO(loc,
+         "TASKLOOP construct with IN_REDUCTION of an array element or section "
+         "whose base array is privatized");
+  if (hasPrivatizedArrayReductionObject(reductionObjects, privatizedSymbols))
+    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 7cf176b1d64b2..fa9b6fbd38f1d 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
@@ -15,10 +15,12 @@
 ! 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
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o - %t/taskloop-in-section.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-IN-SECTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o - %t/taskloop-in-section.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-IN-SECTION
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o - %t/taskloop-reduction-section.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-REDUCTION-SECTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o - %t/taskloop-reduction-section.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-REDUCTION-SECTION
+! RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 --enable-delayed-privatization=false -o - %t/taskloop-udr-section.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-UDR-SECTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o - %t/taskloop-udr-section.f90 2>&1 | FileCheck %s --check-prefix=EAGER-TASKLOOP-UDR-SECTION
 
 ! An array element or section in a task reduction and the implicitly
 ! firstprivate base array are represented by separate block arguments. Reject
@@ -30,8 +32,11 @@
 ! 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
+! EAGER-TASKLOOP-IN: not yet implemented: TASKLOOP construct with IN_REDUCTION of an array element or section whose base array is privatized
+! EAGER-TASKLOOP-REDUCTION: not yet implemented: TASKLOOP construct with REDUCTION of an array element or section whose base array is privatized
+! EAGER-TASKLOOP-IN-SECTION: not yet implemented: TASKLOOP construct with IN_REDUCTION of an array element or section whose base array is privatized
+! EAGER-TASKLOOP-REDUCTION-SECTION: not yet implemented: TASKLOOP construct with REDUCTION of an array element or section whose base array is privatized
+! EAGER-TASKLOOP-UDR-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)
@@ -71,6 +76,17 @@ subroutine taskloop_reduction_section(a, n)
   end do
 end subroutine
 
+!--- taskloop-udr-section.f90
+subroutine taskloop_udr_section(a)
+  integer :: a(4), i
+  !$omp declare reduction(myred : integer : omp_out = omp_out + omp_in) &
+  !$omp& initializer(omp_priv = 1)
+  !$omp taskloop reduction(myred : a(2:3))
+  do i = 1, 1
+    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 e9cc76e7d2cc95ecc96627ad6f44a3e87d2b2ba2 Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Tue, 18 Aug 2026 10:45:11 +0100
Subject: [PATCH 4/6] Lower full array reduction sections

A full-extent array section such as a(:) uses the same descriptor as its
base array during reduction lowering. Data-sharing analysis nevertheless
marked the base as implicitly firstprivate. This produced a duplicate binding
or triggered the array-section TODO diagnostic.

Recognize omitted-bound, unit-stride sections on reduction clauses. Omit the
redundant implicit firstprivate capture while keeping element and partial
section handling unchanged. Cover task and taskloop reductions, including
user-defined reductions and both taskloop privatization modes.

Assisted-by: Codex
---
 .../lib/Lower/OpenMP/DataSharingProcessor.cpp | 47 ++++++++++
 flang/lib/Lower/OpenMP/DataSharingProcessor.h |  2 +
 ...-array-full-section-task-privatization.f90 | 87 +++++++++++++++++++
 3 files changed, 136 insertions(+)
 create mode 100644 flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90

diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index 1d39c1a8d4b77..6aae152a977b4 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -13,6 +13,8 @@
 #include "DataSharingProcessor.h"
 
 #include "Utils.h"
+#include "flang/Evaluate/fold.h"
+#include "flang/Evaluate/tools.h"
 #include "flang/Lower/ConvertVariable.h"
 #include "flang/Lower/PFTBuilder.h"
 #include "flang/Lower/Support/PrivateReductionUtils.h"
@@ -32,6 +34,29 @@
 #include "llvm/Frontend/OpenMP/OMP.h"
 #include <variant>
 
+namespace {
+static bool isWholeArraySection(const Fortran::lower::omp::Object &object) {
+  if (!object.ref())
+    return false;
+
+  std::optional<Fortran::evaluate::DataRef> dataRef =
+      Fortran::evaluate::ExtractDataRef(*object.ref());
+  if (!dataRef)
+    return false;
+
+  const auto *arrayRef = std::get_if<Fortran::evaluate::ArrayRef>(&dataRef->u);
+  if (!arrayRef)
+    return false;
+
+  return llvm::all_of(
+      arrayRef->subscript(), [](const Fortran::evaluate::Subscript &sub) {
+        const auto *triplet = std::get_if<Fortran::evaluate::Triplet>(&sub.u);
+        return triplet && !triplet->GetLower() && !triplet->GetUpper() &&
+               Fortran::evaluate::ToInt64(triplet->GetStride()) == 1;
+      });
+}
+} // namespace
+
 namespace Fortran {
 namespace lower {
 namespace omp {
@@ -264,6 +289,13 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
     return false;
   };
 
+  auto collectWholeArrayReductionSymbols = [&](const auto &reductionClause) {
+    const ObjectList &objects = std::get<ObjectList>(reductionClause.t);
+    for (const Object &object : objects)
+      if (object.sym() && isWholeArraySection(object))
+        wholeArrayReductionSymbols.insert(&object.sym()->GetUltimate());
+  };
+
   for (const omp::Clause &clause : clauses) {
     if (const auto &privateClause =
             std::get_if<omp::clause::Private>(&clause.u)) {
@@ -295,6 +327,15 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
       } else {
         collectOmpObjectListSymbol(objects, explicitlyPrivatizedSymbols);
       }
+    } else if (const auto *inReductionClause =
+                   std::get_if<omp::clause::InReduction>(&clause.u)) {
+      collectWholeArrayReductionSymbols(*inReductionClause);
+    } else if (const auto *reductionClause =
+                   std::get_if<omp::clause::Reduction>(&clause.u)) {
+      collectWholeArrayReductionSymbols(*reductionClause);
+    } else if (const auto *taskReductionClause =
+                   std::get_if<omp::clause::TaskReduction>(&clause.u)) {
+      collectWholeArrayReductionSymbols(*taskReductionClause);
     }
   }
 
@@ -538,6 +579,12 @@ void DataSharingProcessor::collectPrivatizedSymbols(
       return false;
 
     if (collectImplicit) {
+      // A full-extent section is lowered through the same descriptor as its
+      // base array. Do not create a second implicit firstprivate descriptor;
+      // the reduction region argument must be the binding used in the body.
+      if (wholeArrayReductionSymbols.contains(&sym->GetUltimate()))
+        return false;
+
       // If we're a combined construct with a target region, implicit
       // firstprivate captures, should only belong to the target region
       // and not be added/captured by later directives. Parallel regions
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.h b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
index 557584c21123f..dcb09c20c63f8 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.h
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
@@ -95,6 +95,8 @@ class DataSharingProcessor {
   llvm::SmallVector<mlir::Value> loopIVs;
   // Symbols in private, firstprivate, and/or lastprivate clauses.
   llvm::SetVector<const semantics::Symbol *> explicitlyPrivatizedSymbols;
+  // Base symbols of reduction objects written as full-extent sections.
+  llvm::SetVector<const semantics::Symbol *> wholeArrayReductionSymbols;
   llvm::SetVector<const semantics::Symbol *> defaultSymbols;
   llvm::SetVector<const semantics::Symbol *> allPrivatizedSymbols;
   llvm::SetVector<const semantics::Symbol *> conditionalLastPrivatizedSymbols;
diff --git a/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90 b/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90
new file mode 100644
index 0000000000000..948f9f9d8793c
--- /dev/null
+++ b/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90
@@ -0,0 +1,87 @@
+! RUN: split-file %s %t
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task.f90 | FileCheck %s --check-prefix=TASK --implicit-check-not=not\ yet\ implemented --implicit-check-not=Ea_firstprivate
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop.f90 | FileCheck %s --check-prefix=TASKLOOP --implicit-check-not=not\ yet\ implemented --implicit-check-not=Ea_firstprivate
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o - %t/taskloop.f90 | FileCheck %s --check-prefix=TASKLOOP --implicit-check-not=not\ yet\ implemented --implicit-check-not=Ea_firstprivate
+
+! A full-extent section uses the same descriptor as its base array. Check that
+! it is bound only to the reduction argument, rather than also being captured
+! as an implicit firstprivate object.
+
+! TASK-LABEL: func.func @_QPtask_full_section
+! TASK: omp.taskgroup task_reduction(byref @add_reduction_byref_box_4xi32 {{.*}} -> %[[TASKGROUP_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4xi32>>>)
+! TASK: %[[TASKGROUP_DECL:.*]]:2 = hlfir.declare %[[TASKGROUP_ARG]]
+! TASK: omp.task in_reduction(byref @add_reduction_byref_box_4xi32 %[[TASKGROUP_DECL]]#0 -> %[[TASK_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4xi32>>>)
+! TASK: %[[TASK_DECL:.*]]:2 = hlfir.declare %[[TASK_ARG]]
+! TASK: %[[TASK_BOX:.*]] = fir.load %[[TASK_DECL]]#0
+! TASK: %[[TASK_SECTION:.*]] = hlfir.designate %[[TASK_BOX]]
+! TASK: hlfir.elemental
+! TASK: %[[TASK_ELEMENT:.*]] = hlfir.designate %[[TASK_SECTION]]
+! TASK: %[[TASK_VALUE:.*]] = fir.load %[[TASK_ELEMENT]]
+! TASK: arith.addi %[[TASK_VALUE]]
+
+! TASKLOOP-LABEL: func.func @_QPtaskloop_in_full_section
+! TASKLOOP: omp.taskloop.context in_reduction(byref @add_reduction_byref_box_4xi32 {{.*}} -> %[[IN_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4xi32>>>)
+! TASKLOOP: %[[IN_DECL:.*]]:2 = hlfir.declare %[[IN_ARG]]
+! TASKLOOP: %[[IN_BOX:.*]] = fir.load %[[IN_DECL]]#0
+! TASKLOOP: %[[IN_SECTION:.*]] = hlfir.designate %[[IN_BOX]]
+! TASKLOOP: hlfir.elemental
+! TASKLOOP: %[[IN_ELEMENT:.*]] = hlfir.designate %[[IN_SECTION]]
+! TASKLOOP: %[[IN_VALUE:.*]] = fir.load %[[IN_ELEMENT]]
+! TASKLOOP: arith.addi %[[IN_VALUE]]
+
+! TASKLOOP-LABEL: func.func @_QPtaskloop_reduction_full_section
+! TASKLOOP: omp.taskloop.context {{.*}}reduction(byref @add_reduction_byref_box_4xi32 {{.*}} -> %[[RED_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4xi32>>>)
+! TASKLOOP: %[[RED_DECL:.*]]:2 = hlfir.declare %[[RED_ARG]]
+! TASKLOOP: %[[RED_BOX:.*]] = fir.load %[[RED_DECL]]#0
+! TASKLOOP: %[[RED_SECTION:.*]] = hlfir.designate %[[RED_BOX]]
+! TASKLOOP: hlfir.elemental
+! TASKLOOP: %[[RED_ELEMENT:.*]] = hlfir.designate %[[RED_SECTION]]
+! TASKLOOP: %[[RED_VALUE:.*]] = fir.load %[[RED_ELEMENT]]
+! TASKLOOP: arith.addi %[[RED_VALUE]]
+
+! TASKLOOP-LABEL: func.func @_QPtaskloop_udr_full_section
+! TASKLOOP: omp.taskloop.context {{.*}}reduction(byref @_QQFtaskloop_udr_full_sectionmyred_byref_box_4xi32 {{.*}} -> %[[UDR_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4xi32>>>)
+! TASKLOOP: %[[UDR_DECL:.*]]:2 = hlfir.declare %[[UDR_ARG]]
+! TASKLOOP: %[[UDR_BOX:.*]] = fir.load %[[UDR_DECL]]#0
+! TASKLOOP: %[[UDR_SECTION:.*]] = hlfir.designate %[[UDR_BOX]]
+! TASKLOOP: hlfir.elemental
+! TASKLOOP: %[[UDR_ELEMENT:.*]] = hlfir.designate %[[UDR_SECTION]]
+! TASKLOOP: %[[UDR_VALUE:.*]] = fir.load %[[UDR_ELEMENT]]
+! TASKLOOP: arith.addi %[[UDR_VALUE]]
+
+!--- task.f90
+subroutine task_full_section(a)
+  integer :: a(-2:1)
+  !$omp taskgroup task_reduction(+: a(:))
+  !$omp task in_reduction(+: a(:))
+  a(:) = a(:) + 1
+  !$omp end task
+  !$omp end taskgroup
+end subroutine
+
+!--- taskloop.f90
+subroutine taskloop_in_full_section(a, n)
+  integer :: a(-2:1), n
+  !$omp taskloop in_reduction(+: a(:))
+  do i = 1, n
+    a(:) = a(:) + i
+  end do
+end subroutine
+
+subroutine taskloop_reduction_full_section(a, n)
+  integer :: a(-2:1), n
+  !$omp taskloop reduction(+: a(:))
+  do i = 1, n
+    a(:) = a(:) + i
+  end do
+end subroutine
+
+subroutine taskloop_udr_full_section(a)
+  integer :: a(-2:1), i
+  !$omp declare reduction(myred : integer : omp_out = omp_out + omp_in) &
+  !$omp& initializer(omp_priv = 1)
+  !$omp taskloop reduction(myred : a(:))
+  do i = 1, 1
+    a(:) = a(:) + i
+  end do
+end subroutine

>From 1ccac374d59e4027eab245b142efb9edd0b52037 Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Tue, 18 Aug 2026 11:33:41 +0100
Subject: [PATCH 5/6] Handle default DSA for full sections

Full-extent reduction sections use the base array descriptor, but the
data-sharing exception only covered ordinary implicit captures. A task
default(private) or default(firstprivate) therefore still created a
competing private descriptor and reached the task reduction TODO.

Apply the exception to default-selected private symbols as well, while
leaving explicit private clauses on their existing path. Cover both default
forms and verify that body expressions use the declared reduction argument.

Assisted-by: Codex
---
 .../lib/Lower/OpenMP/DataSharingProcessor.cpp | 18 ++++++---
 ...-array-full-section-task-privatization.f90 | 40 +++++++++++++++++++
 2 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index 6aae152a977b4..d5414b81e64f8 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -558,10 +558,13 @@ void DataSharingProcessor::collectPrivatizedSymbols(
     const llvm::SetVector<const semantics::Symbol *> &symbolsInNestedRegions,
     llvm::SetVector<const semantics::Symbol *> *symbols) {
   // Filter-out symbols that must not be privatized.
+  bool collectDefaultPrivate = false;
   bool collectImplicit = false;
   bool collectPreDetermined = false;
   bool collectIndirectRefs = !flag.has_value();
   if (!collectIndirectRefs) {
+    collectDefaultPrivate = *flag == semantics::Symbol::Flag::OmpPrivate ||
+                            *flag == semantics::Symbol::Flag::OmpFirstPrivate;
     collectImplicit = *flag == semantics::Symbol::Flag::OmpImplicit;
     collectPreDetermined = *flag == semantics::Symbol::Flag::OmpPreDetermined;
   }
@@ -578,13 +581,16 @@ void DataSharingProcessor::collectPrivatizedSymbols(
     if (sym->test(semantics::Symbol::Flag::OmpLinear) && !inTarget)
       return false;
 
-    if (collectImplicit) {
-      // A full-extent section is lowered through the same descriptor as its
-      // base array. Do not create a second implicit firstprivate descriptor;
-      // the reduction region argument must be the binding used in the body.
-      if (wholeArrayReductionSymbols.contains(&sym->GetUltimate()))
-        return false;
+    // A full-extent section is lowered through the same descriptor as its base
+    // array. Do not create a second private descriptor when privatization is
+    // selected implicitly or by a default clause; the reduction region
+    // argument must be the binding used in the body. Explicit private clauses
+    // are collected separately in collectSymbolsForPrivatization().
+    if ((collectImplicit || collectDefaultPrivate) &&
+        wholeArrayReductionSymbols.contains(&sym->GetUltimate()))
+      return false;
 
+    if (collectImplicit) {
       // If we're a combined construct with a target region, implicit
       // firstprivate captures, should only belong to the target region
       // and not be added/captured by later directives. Parallel regions
diff --git a/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90 b/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90
index 948f9f9d8793c..89f7868432dc3 100644
--- a/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90
+++ b/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90
@@ -1,5 +1,6 @@
 ! RUN: split-file %s %t
 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task.f90 | FileCheck %s --check-prefix=TASK --implicit-check-not=not\ yet\ implemented --implicit-check-not=Ea_firstprivate
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task-default.f90 | FileCheck %s --check-prefix=TASK-DEFAULT --implicit-check-not=not\ yet\ implemented --implicit-check-not=Ea_firstprivate --implicit-check-not=Ea_private
 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/taskloop.f90 | FileCheck %s --check-prefix=TASKLOOP --implicit-check-not=not\ yet\ implemented --implicit-check-not=Ea_firstprivate
 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -mmlir --enable-delayed-privatization=false -o - %t/taskloop.f90 | FileCheck %s --check-prefix=TASKLOOP --implicit-check-not=not\ yet\ implemented --implicit-check-not=Ea_firstprivate
 
@@ -19,6 +20,26 @@
 ! TASK: %[[TASK_VALUE:.*]] = fir.load %[[TASK_ELEMENT]]
 ! TASK: arith.addi %[[TASK_VALUE]]
 
+! TASK-DEFAULT-LABEL: func.func @_QPtask_default_firstprivate_full_section
+! TASK-DEFAULT: omp.task in_reduction(byref @add_reduction_byref_box_4xi32 {{.*}} -> %[[FIRSTPRIVATE_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4xi32>>>)
+! TASK-DEFAULT: %[[FIRSTPRIVATE_DECL:.*]]:2 = hlfir.declare %[[FIRSTPRIVATE_ARG]]
+! TASK-DEFAULT: %[[FIRSTPRIVATE_BOX:.*]] = fir.load %[[FIRSTPRIVATE_DECL]]#0
+! TASK-DEFAULT: %[[FIRSTPRIVATE_SECTION:.*]] = hlfir.designate %[[FIRSTPRIVATE_BOX]]
+! TASK-DEFAULT: hlfir.elemental
+! TASK-DEFAULT: %[[FIRSTPRIVATE_ELEMENT:.*]] = hlfir.designate %[[FIRSTPRIVATE_SECTION]]
+! TASK-DEFAULT: %[[FIRSTPRIVATE_VALUE:.*]] = fir.load %[[FIRSTPRIVATE_ELEMENT]]
+! TASK-DEFAULT: arith.addi %[[FIRSTPRIVATE_VALUE]]
+
+! TASK-DEFAULT-LABEL: func.func @_QPtask_default_private_full_section
+! TASK-DEFAULT: omp.task in_reduction(byref @add_reduction_byref_box_4xi32 {{.*}} -> %[[PRIVATE_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4xi32>>>)
+! TASK-DEFAULT: %[[PRIVATE_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_ARG]]
+! TASK-DEFAULT: %[[PRIVATE_BOX:.*]] = fir.load %[[PRIVATE_DECL]]#0
+! TASK-DEFAULT: %[[PRIVATE_SECTION:.*]] = hlfir.designate %[[PRIVATE_BOX]]
+! TASK-DEFAULT: hlfir.elemental
+! TASK-DEFAULT: %[[PRIVATE_ELEMENT:.*]] = hlfir.designate %[[PRIVATE_SECTION]]
+! TASK-DEFAULT: %[[PRIVATE_VALUE:.*]] = fir.load %[[PRIVATE_ELEMENT]]
+! TASK-DEFAULT: arith.addi %[[PRIVATE_VALUE]]
+
 ! TASKLOOP-LABEL: func.func @_QPtaskloop_in_full_section
 ! TASKLOOP: omp.taskloop.context in_reduction(byref @add_reduction_byref_box_4xi32 {{.*}} -> %[[IN_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4xi32>>>)
 ! TASKLOOP: %[[IN_DECL:.*]]:2 = hlfir.declare %[[IN_ARG]]
@@ -59,6 +80,25 @@ subroutine task_full_section(a)
   !$omp end taskgroup
 end subroutine
 
+!--- task-default.f90
+subroutine task_default_firstprivate_full_section(a)
+  integer :: a(-2:1)
+  !$omp taskgroup task_reduction(+: a(:))
+  !$omp task default(firstprivate) in_reduction(+: a(:))
+  a(:) = a(:) + 1
+  !$omp end task
+  !$omp end taskgroup
+end subroutine
+
+subroutine task_default_private_full_section(a)
+  integer :: a(-2:1)
+  !$omp taskgroup task_reduction(+: a(:))
+  !$omp task default(private) in_reduction(+: a(:))
+  a(:) = a(:) + 1
+  !$omp end task
+  !$omp end taskgroup
+end subroutine
+
 !--- taskloop.f90
 subroutine taskloop_in_full_section(a, n)
   integer :: a(-2:1), n

>From e6781dcc8e59b5edb2e75ae9841c3ed43ccb50fc Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Tue, 18 Aug 2026 11:54:24 +0100
Subject: [PATCH 6/6] Test multidimensional reduction sections

Add rank-two full and mixed array section task reductions. This protects the
all-dimensions whole-section classification from regressions while preserving
the TODO for partial sections.

Assisted-by: Codex
---
 ...ction-array-element-task-privatization.f90 | 13 ++++++++++++
 ...-array-full-section-task-privatization.f90 | 21 +++++++++++++++++++
 2 files changed, 34 insertions(+)

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 fa9b6fbd38f1d..3b498ebcd9cab 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
@@ -7,6 +7,8 @@
 ! 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/task-rank-two-section.f90 2>&1 | FileCheck %s --check-prefix=TASK-RANK-TWO-SECTION
+! RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %t/task-rank-two-section.f90 2>&1 | FileCheck %s --check-prefix=TASK-RANK-TWO-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
@@ -30,6 +32,7 @@
 ! 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
+! TASK-RANK-TWO-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 or section whose base array is privatized
@@ -58,6 +61,16 @@ subroutine task_reduction_section(a)
   !$omp end taskgroup
 end subroutine
 
+!--- task-rank-two-section.f90
+subroutine task_reduction_rank_two_section(a)
+  integer :: a(4, 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-section.f90
 subroutine taskloop_in_reduction_section(a, n)
   integer :: a(4), n
diff --git a/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90 b/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90
index 89f7868432dc3..b1927ec049fe5 100644
--- a/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90
+++ b/flang/test/Lower/OpenMP/reduction-array-full-section-task-privatization.f90
@@ -20,6 +20,18 @@
 ! TASK: %[[TASK_VALUE:.*]] = fir.load %[[TASK_ELEMENT]]
 ! TASK: arith.addi %[[TASK_VALUE]]
 
+! TASK-LABEL: func.func @_QPtask_rank_two_full_section
+! TASK: omp.taskgroup task_reduction(byref @add_reduction_byref_box_4x4xi32 {{.*}} -> %[[RANK_TWO_TASKGROUP_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4x4xi32>>>)
+! TASK: %[[RANK_TWO_TASKGROUP_DECL:.*]]:2 = hlfir.declare %[[RANK_TWO_TASKGROUP_ARG]]
+! TASK: omp.task in_reduction(byref @add_reduction_byref_box_4x4xi32 %[[RANK_TWO_TASKGROUP_DECL]]#0 -> %[[RANK_TWO_TASK_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4x4xi32>>>)
+! TASK: %[[RANK_TWO_TASK_DECL:.*]]:2 = hlfir.declare %[[RANK_TWO_TASK_ARG]]
+! TASK: %[[RANK_TWO_TASK_BOX:.*]] = fir.load %[[RANK_TWO_TASK_DECL]]#0
+! TASK: %[[RANK_TWO_TASK_SECTION:.*]] = hlfir.designate %[[RANK_TWO_TASK_BOX]]
+! TASK: hlfir.elemental
+! TASK: %[[RANK_TWO_TASK_ELEMENT:.*]] = hlfir.designate %[[RANK_TWO_TASK_SECTION]]
+! TASK: %[[RANK_TWO_TASK_VALUE:.*]] = fir.load %[[RANK_TWO_TASK_ELEMENT]]
+! TASK: arith.addi %[[RANK_TWO_TASK_VALUE]]
+
 ! TASK-DEFAULT-LABEL: func.func @_QPtask_default_firstprivate_full_section
 ! TASK-DEFAULT: omp.task in_reduction(byref @add_reduction_byref_box_4xi32 {{.*}} -> %[[FIRSTPRIVATE_ARG:arg[0-9]+]] : !fir.ref<!fir.box<!fir.array<4xi32>>>)
 ! TASK-DEFAULT: %[[FIRSTPRIVATE_DECL:.*]]:2 = hlfir.declare %[[FIRSTPRIVATE_ARG]]
@@ -80,6 +92,15 @@ subroutine task_full_section(a)
   !$omp end taskgroup
 end subroutine
 
+subroutine task_rank_two_full_section(a)
+  integer :: a(-2:1, -1:2)
+  !$omp taskgroup task_reduction(+: a(:, :))
+  !$omp task in_reduction(+: a(:, :))
+  a(:, :) = a(:, :) + 1
+  !$omp end task
+  !$omp end taskgroup
+end subroutine
+
 !--- task-default.f90
 subroutine task_default_firstprivate_full_section(a)
   integer :: a(-2:1)



More information about the flang-commits mailing list