[Mlir-commits] [mlir] [mlir][OpenACC] Support dynamic multi-rank array reductions (PR #211336)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Jul 22 10:59:05 PDT 2026
https://github.com/khaki3 created https://github.com/llvm/llvm-project/pull/211336
Example:
```fortran
integer :: r(:,:)
!$acc parallel loop reduction(+:r)
```
In this code, the reduction accumulator has dynamic dimensions and rank greater than one.
Fix: use runtime dimension sizes to delinearize flattened array-reduction indices.
>From 7e8a8a0c197a2a15a4c7d7997bedbca889b84769 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Wed, 22 Jul 2026 10:09:13 -0700
Subject: [PATCH] [mlir][OpenACC] Support dynamic multi-rank array reductions
---
.../Dialect/OpenACC/Transforms/ACCCGToGPU.cpp | 16 +++++------
.../acc-cg-to-gpu-reduction-array.mlir | 27 ++++++++++++-------
2 files changed, 24 insertions(+), 19 deletions(-)
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCCGToGPU.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCCGToGPU.cpp
index f0fd7ae96ad4f..92f9cc90dc73f 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCCGToGPU.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCCGToGPU.cpp
@@ -3259,12 +3259,6 @@ void ACCCGToGPULowering::processAccumulateArrayOp(
(void)accSupport.emitNYI(loc, "reduction: non-MemRefTy accumulate array");
return;
}
- if (memrefTy.getRank() > 1 && !memrefTy.hasStaticShape()) {
- (void)accSupport.emitNYI(loc,
- "reduction: dynamic multi-rank accumulate array");
- return;
- }
-
FailureOr<arith::AtomicRMWKind> kindOr = getReductionKind(
op.getReductionOperator(), memrefTy.getElementType(), loc);
if (failed(kindOr))
@@ -3373,13 +3367,15 @@ void ACCCGToGPULowering::processAccumulateArrayOp(
Value iv = forOp.getInductionVar();
SmallVector<Value> indices{iv};
if (memrefTy.getRank() > 1) {
- assert(memrefTy.hasStaticShape() &&
- "multi-rank array reduction accumulator must be static");
indices.resize(memrefTy.getRank());
Value linearIndex = iv;
for (int64_t dim = memrefTy.getRank() - 1; dim >= 0; --dim) {
- Value dimSize = arith::ConstantIndexOp::create(
- rewriter, loc, memrefTy.getDimSize(dim));
+ Value dimSize =
+ memrefTy.isDynamicDim(dim)
+ ? memref::DimOp::create(rewriter, loc, memref, dim).getResult()
+ : arith::ConstantIndexOp::create(rewriter, loc,
+ memrefTy.getDimSize(dim))
+ .getResult();
indices[dim] =
arith::RemUIOp::create(rewriter, loc, linearIndex, dimSize);
if (dim != 0)
diff --git a/mlir/test/Dialect/OpenACC/acc-cg-to-gpu-reduction-array.mlir b/mlir/test/Dialect/OpenACC/acc-cg-to-gpu-reduction-array.mlir
index ace560d869792..422e172e1ec5b 100644
--- a/mlir/test/Dialect/OpenACC/acc-cg-to-gpu-reduction-array.mlir
+++ b/mlir/test/Dialect/OpenACC/acc-cg-to-gpu-reduction-array.mlir
@@ -196,20 +196,29 @@ func.func @rank_three_array_reduction() {
return
}
-// Unsupported dynamic multi-rank accumulators must not generate invalid
-// indexing operations.
// CHECK-LABEL: func.func @dynamic_rank_two_array_reduction
-// CHECK: gpu.launch
-// CHECK-NOT: memref.load
-// CHECK: gpu.terminator
-func.func @dynamic_rank_two_array_reduction(%local: memref<?x?xi32>, %extent: index) {
+// CHECK: scf.for %[[LINEAR:.*]] =
+// CHECK: %[[DIM1:.*]] = memref.dim %{{.*}}, %{{.*}} : memref<2x?xi32>
+// CHECK: %[[IDX1:.*]] = arith.remui %[[LINEAR]], %[[DIM1]] : index
+// CHECK: %[[ROW:.*]] = arith.divui %[[LINEAR]], %[[DIM1]] : index
+// CHECK: %[[C2:.*]] = arith.constant 2 : index
+// CHECK: %[[IDX0:.*]] = arith.remui %[[ROW]], %[[C2]] : index
+// CHECK: %[[ELEM:.*]] = memref.load %{{.*}}[%[[IDX0]], %[[IDX1]]] : memref<2x?xi32>
+// CHECK: %[[RESULT:.*]] = gpu.all_reduce add %[[ELEM]]
+// CHECK: memref.store %[[RESULT]], %{{.*}}[%[[IDX0]], %[[IDX1]]] : memref<2x?xi32>
+func.func @dynamic_rank_two_array_reduction(
+ %local: memref<2x?xi32>, %n: index) {
%c1 = arith.constant 1 : index
%c128 = arith.constant 128 : index
%bx = acc.par_width %c1 {par_dim = #acc.par_dim<block_x>}
%tx = acc.par_width %c128 {par_dim = #acc.par_dim<thread_x>}
- acc.compute_region launch(%kbx = %bx, %ktx = %tx) ins(%arg0 = %local, %ext = %extent) : (memref<?x?xi32>, index) {
- %bounds = acc.bounds extent(%ext : index)
- acc.reduction_accumulate_array %arg0 bounds(%bounds) <add> : memref<?x?xi32> {par_dims = #acc<par_dims[block_x, thread_x]>}
+ acc.compute_region launch(%kbx = %bx, %ktx = %tx)
+ ins(%arg0 = %local, %arg1 = %n)
+ : (memref<2x?xi32>, index) {
+ %c2 = arith.constant 2 : index
+ %extent = arith.muli %c2, %arg1 : index
+ %bounds = acc.bounds extent(%extent : index)
+ acc.reduction_accumulate_array %arg0 bounds(%bounds) <add> : memref<2x?xi32> {par_dims = #acc<par_dims[block_x, thread_x]>}
acc.yield
} {origin = "acc.parallel"}
return
More information about the Mlir-commits
mailing list