[Mlir-commits] [mlir] 43a128f - [mlir][acc] Add reduction accumulate operation (#201954)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Jun 8 08:22:57 PDT 2026


Author: Razvan Lupusoru
Date: 2026-06-08T08:22:51-07:00
New Revision: 43a128fe790286a53e9a5b1c2b9173eb0c0b2261

URL: https://github.com/llvm/llvm-project/commit/43a128fe790286a53e9a5b1c2b9173eb0c0b2261
DIFF: https://github.com/llvm/llvm-project/commit/43a128fe790286a53e9a5b1c2b9173eb0c0b2261.diff

LOG: [mlir][acc] Add reduction accumulate operation (#201954)

Introduce `acc.reduction_accumulate` to represent merging an SSA result
into storage (typically the private memory storage) which will then be
used to combine into the final destination storage.

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
    mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
    mlir/test/Dialect/OpenACC/invalid-cg.mlir
    mlir/test/Dialect/OpenACC/ops-cg.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
index 13969f9fc9c65..8cf1a66ee59f7 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
@@ -18,6 +18,7 @@
 
 include "mlir/Interfaces/InferTypeOpInterface.td"
 include "mlir/Interfaces/ViewLikeInterface.td"
+include "mlir/IR/CommonAttrConstraints.td"
 
 // This file is intended to be included from OpenACCOps.td, which provides
 // the necessary includes and definitions. The operations defined here use
@@ -129,6 +130,46 @@ def OpenACC_ReductionCombineOp: OpenACC_Op<"reduction_combine",
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// acc.reduction_accumulate
+//===----------------------------------------------------------------------===//
+
+def OpenACC_ReductionAccumulateOp
+    : OpenACC_Op<"reduction_accumulate", []> {
+  let summary = "Accumulate an SSA value into a reduction variable";
+  let description = [{
+    Accumulates a scalar SSA value into a pointer-like reduction variable.
+
+    Example:
+    ```mlir
+    %private = memref.alloca() {acc.par_dims = #acc<par_dims[thread_x]>} : memref<i32>
+    memref.store %c0, %private[] : memref<i32>
+    %partial = scf.parallel (%iv) = (%c0) to (%cN) step (%c1) init (%c0) -> i32 {
+      %v = memref.load %data[%iv] : memref<Nxi32>
+      scf.reduce(%v : i32) {
+      ^bb0(%lhs: i32, %rhs: i32):
+        %sum = arith.addi %lhs, %rhs : i32
+        scf.reduce.return %sum : i32
+      }
+    } {acc.par_dims = #acc<par_dims[thread_x]>}
+    acc.reduction_accumulate (%partial) to (%private) <add>
+        : (i32) -> (memref<i32>) {par_dims = #acc<par_dims[thread_x]>}
+    acc.reduction_combine %private into %shared <add> : memref<i32>
+        {acc.par_dims = #acc<par_dims[thread_x]>}
+    ```
+  }];
+  let arguments = (ins AnyTypeOf<[AnyInteger, AnyFloat, AnyComplex]>:$value,
+                       Arg<OpenACC_PointerLikeType,
+                           "Reduction variable to update",
+                           [MemRead, MemWrite]>:$memref,
+                       OpenACC_ReductionOperatorAttr:$reductionOperator,
+                       OpenACC_GPUParallelDimsAttr:$par_dims);
+  let assemblyFormat = [{
+    `(` $value `)` `to` `(` $memref `)` $reductionOperator `:` `(` type($value) `)` `->` `(` type($memref) `)` attr-dict
+  }];
+  let hasVerifier = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // acc.kernel_environment
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
index fcad2c884b338..c0c2bb7654830 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
@@ -468,6 +468,23 @@ LogicalResult ReductionCombineRegionOp::verify() {
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// ReductionAccumulateOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult ReductionAccumulateOp::verify() {
+  Type valueType = getValue().getType();
+  auto ptrLikeTy = cast<PointerLikeType>(getMemref().getType());
+  Type elementType = ptrLikeTy.getElementType();
+  if (!elementType)
+    return emitOpError("pointer-like destination must have an element type");
+  if (elementType != valueType)
+    return emitOpError("pointer-like element type must match value type");
+  if (getParDims().getArray().empty())
+    return emitOpError("par_dims must specify at least one parallel dimension");
+  return success();
+}
+
 //===----------------------------------------------------------------------===//
 // ReductionCombineOp
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/test/Dialect/OpenACC/invalid-cg.mlir b/mlir/test/Dialect/OpenACC/invalid-cg.mlir
index d218bc505a5ea..4f05c487367ce 100644
--- a/mlir/test/Dialect/OpenACC/invalid-cg.mlir
+++ b/mlir/test/Dialect/OpenACC/invalid-cg.mlir
@@ -38,3 +38,37 @@ acc.compute_region launch(%arg0 = %c32) {
 ^bb0(%arg0: index, %extra: index):
   "acc.yield"() : () -> ()
 }) {origin = "acc.parallel"} : (index) -> ()
+
+// -----
+
+func.func @reduction_accumulate_invalid_operator() {
+  %partial = arith.constant 1.0 : f32
+  %private = memref.alloca() : memref<f32>
+  acc.reduction_accumulate (%partial) to (%private) <addi>
+      : (f32) -> (memref<f32>) {par_dims = #acc<par_dims[thread_x]>}
+  // expected-error at -2 {{expected ::mlir::acc::ReductionOperator to be one of}}
+  // expected-error at -3 {{failed to parse OpenACC_ReductionOperatorAttr}}
+  return
+}
+
+// -----
+
+func.func @reduction_accumulate_type_mismatch() {
+  %wrong_ty = arith.constant 3.0 : f32
+  %private_i32 = memref.alloca() : memref<i32>
+  // expected-error at +1 {{pointer-like element type must match value type}}
+  acc.reduction_accumulate (%wrong_ty) to (%private_i32) <add>
+      : (f32) -> (memref<i32>) {par_dims = #acc<par_dims[thread_x]>}
+  return
+}
+
+// -----
+
+func.func @reduction_accumulate_empty_par_dims() {
+  %partial3 = arith.constant 4 : i32
+  %private4 = memref.alloca() : memref<i32>
+  // expected-error at +1 {{par_dims must specify at least one parallel dimension}}
+  acc.reduction_accumulate (%partial3) to (%private4) <add>
+      : (i32) -> (memref<i32>) {par_dims = #acc<par_dims[]>}
+  return
+}

diff  --git a/mlir/test/Dialect/OpenACC/ops-cg.mlir b/mlir/test/Dialect/OpenACC/ops-cg.mlir
index cdd50f21419f0..6353169944382 100644
--- a/mlir/test/Dialect/OpenACC/ops-cg.mlir
+++ b/mlir/test/Dialect/OpenACC/ops-cg.mlir
@@ -270,6 +270,56 @@ func.func @compute_region_all_fields(%data: memref<1024xf32>,
 
 // -----
 
+// CHECK-LABEL: func @parallel_reduction_pattern
+func.func @parallel_reduction_pattern(%data: memref<8xi32>, %shared: memref<i32>) {
+  %c0 = arith.constant 0 : index
+  %c8 = arith.constant 8 : index
+  %c1 = arith.constant 1 : index
+  %c0_i32 = arith.constant 0 : i32
+  %private = memref.alloca() {acc.par_dims = #acc<par_dims[thread_x]>} : memref<i32>
+  memref.store %c0_i32, %private[] : memref<i32>
+  %partial = scf.parallel (%iv) = (%c0) to (%c8) step (%c1) init (%c0_i32) -> i32 {
+    %v = memref.load %data[%iv] : memref<8xi32>
+    scf.reduce(%v : i32) {
+    ^bb0(%lhs: i32, %rhs: i32):
+      %sum = arith.addi %lhs, %rhs : i32
+      scf.reduce.return %sum : i32
+    }
+  } {acc.par_dims = #acc<par_dims[thread_x]>}
+  acc.reduction_accumulate (%partial) to (%private) <add>
+      : (i32) -> (memref<i32>) {par_dims = #acc<par_dims[thread_x]>}
+  acc.reduction_combine %private into %shared <add> : memref<i32>
+      {acc.par_dims = #acc<par_dims[thread_x]>}
+  return
+}
+// CHECK: memref.alloca() {acc.par_dims = #acc<par_dims[thread_x]>}
+// CHECK: scf.parallel
+// CHECK: scf.reduce
+// CHECK: acc.reduction_accumulate(%{{.*}}) to(%{{.*}}) <add> : (i32) -> (memref<i32>) {par_dims = #acc<par_dims[thread_x]>}
+// CHECK: acc.reduction_combine %{{.*}} into %{{.*}} <add> : memref<i32> {acc.par_dims = #acc<par_dims[thread_x]>}
+
+// -----
+
+// CHECK-LABEL: func @reduction_accumulate_thread_x
+func.func @reduction_accumulate_thread_x(%partial: f32, %private: memref<f32>) {
+  acc.reduction_accumulate (%partial) to (%private) <add>
+      : (f32) -> (memref<f32>) {par_dims = #acc<par_dims[thread_x]>}
+  return
+}
+// CHECK: acc.reduction_accumulate(%{{.*}}) to(%{{.*}}) <add> : (f32) -> (memref<f32>) {par_dims = #acc<par_dims[thread_x]>}
+
+// -----
+
+// CHECK-LABEL: func @reduction_accumulate_block_thread
+func.func @reduction_accumulate_block_thread(%partial: i32, %private: memref<i32>) {
+  acc.reduction_accumulate (%partial) to (%private) <add>
+      : (i32) -> (memref<i32>) {par_dims = #acc<par_dims[block_x, thread_x]>}
+  return
+}
+// CHECK: acc.reduction_accumulate(%{{.*}}) to(%{{.*}}) <add> : (i32) -> (memref<i32>) {par_dims = #acc<par_dims[block_x, thread_x]>}
+
+// -----
+
 // CHECK-LABEL: func @compute_region_with_results
 func.func @compute_region_with_results() -> i32 {
   %w0 = acc.par_width {par_dim = #acc.par_dim<thread_x>}


        


More information about the Mlir-commits mailing list