[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