[Mlir-commits] [mlir] 2263210 - [mlir][acc] Add destroy region to reduction recipes (#155480)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Tue Aug 26 13:17:49 PDT 2025


Author: Razvan Lupusoru
Date: 2025-08-26T13:17:46-07:00
New Revision: 2263210d9e2b56bf910bde57a2bfc013450e131a

URL: https://github.com/llvm/llvm-project/commit/2263210d9e2b56bf910bde57a2bfc013450e131a
DIFF: https://github.com/llvm/llvm-project/commit/2263210d9e2b56bf910bde57a2bfc013450e131a.diff

LOG: [mlir][acc] Add destroy region to reduction recipes (#155480)

Reduction recipes capture how a private copy is created. In some
languages, like C++ class variables with destructors - that private copy
also must be properly destroyed. Thus update the reduction recipe to
contain a `destroy` region similarly to the private recipes.

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
    mlir/test/Dialect/OpenACC/ops.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 0db11aa9af683..cfe73d81953db 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -1302,7 +1302,7 @@ def OpenACC_ReductionRecipeOp
 
   let description = [{
     Declares an OpenACC reduction recipe. The operation requires two
-    mandatory regions.
+    mandatory regions and one optional region.
 
       1. The initializer region specifies how to initialize the local reduction
          value. The region has a first argument that contains the value of the
@@ -1313,6 +1313,8 @@ def OpenACC_ReductionRecipeOp
          values of the reduction type into one. It has at least two arguments
          and it is expected to `acc.yield` the combined value. Extra arguments
          can be added to deal with dynamic arrays.
+      3. The optional destroy region specifies how to destruct the value when it
+         reaches its end of life. It takes the reduction value as argument.
 
     Example:
 
@@ -1329,6 +1331,10 @@ def OpenACC_ReductionRecipeOp
       // two values into one.
       %2 = arith.addi %0, %1 : i64
       acc.yield %2 : i64
+    } destroy {
+    ^bb0(%0: i64)
+      // destroy region contains a sequence of operations to destruct the
+      // created copy.
     }
 
     // The reduction symbol is then used in the corresponding operation.
@@ -1362,12 +1368,14 @@ def OpenACC_ReductionRecipeOp
                        OpenACC_ReductionOperatorAttr:$reductionOperator);
 
   let regions = (region AnyRegion:$initRegion,
-                        AnyRegion:$combinerRegion);
+                        AnyRegion:$combinerRegion,
+                        AnyRegion:$destroyRegion);
 
   let assemblyFormat = [{
     $sym_name `:` $type attr-dict-with-keyword
     `reduction_operator` $reductionOperator
     `init` $initRegion `combiner` $combinerRegion
+    (`destroy` $destroyRegion^)?
   }];
 
   let hasRegionVerifier = 1;

diff  --git a/mlir/test/Dialect/OpenACC/ops.mlir b/mlir/test/Dialect/OpenACC/ops.mlir
index 7bb6cf43e49a7..5a3bbaf4252db 100644
--- a/mlir/test/Dialect/OpenACC/ops.mlir
+++ b/mlir/test/Dialect/OpenACC/ops.mlir
@@ -1954,6 +1954,70 @@ acc.reduction.recipe @reduction_add_memref_i32 : memref<i32> reduction_operator
 // CHECK-LABEL: acc.reduction.recipe @reduction_add_memref_i32
 // CHECK:       memref.alloca
 
+// -----
+
+// Test reduction recipe with destroy region using dynamic memory allocation
+acc.reduction.recipe @reduction_add_with_destroy : memref<?xf32> reduction_operator<add> init {
+^bb0(%arg0: memref<?xf32>):
+  %cst = arith.constant 0.000000e+00 : f32
+  %c0 = arith.constant 0 : index
+  %size = memref.dim %arg0, %c0 : memref<?xf32>
+  %alloc = memref.alloc(%size) : memref<?xf32>
+  %c1 = arith.constant 1 : index
+  scf.for %i = %c0 to %size step %c1 {
+    memref.store %cst, %alloc[%i] : memref<?xf32>
+  }
+  acc.yield %alloc : memref<?xf32>
+} combiner {
+^bb0(%arg0: memref<?xf32>, %arg1: memref<?xf32>):
+  %c0 = arith.constant 0 : index
+  %c1 = arith.constant 1 : index
+  %size = memref.dim %arg0, %c0 : memref<?xf32>
+  scf.for %i = %c0 to %size step %c1 {
+    %val0 = memref.load %arg0[%i] : memref<?xf32>
+    %val1 = memref.load %arg1[%i] : memref<?xf32>
+    %sum = arith.addf %val0, %val1 : f32
+    memref.store %sum, %arg0[%i] : memref<?xf32>
+  }
+  acc.yield %arg0 : memref<?xf32>
+} destroy {
+^bb0(%arg0: memref<?xf32>):
+  // destroy region to deallocate dynamically allocated memory
+  memref.dealloc %arg0 : memref<?xf32>
+  acc.yield
+}
+
+// CHECK-LABEL: acc.reduction.recipe @reduction_add_with_destroy : memref<?xf32> reduction_operator <add> init {
+// CHECK:       ^bb0(%[[ARG:.*]]: memref<?xf32>):
+// CHECK:         %[[CST:.*]] = arith.constant 0.000000e+00 : f32
+// CHECK:         %[[C0:.*]] = arith.constant 0 : index
+// CHECK:         %[[SIZE:.*]] = memref.dim %[[ARG]], %[[C0]] : memref<?xf32>
+// CHECK:         %[[ALLOC:.*]] = memref.alloc(%[[SIZE]]) : memref<?xf32>
+// CHECK:         %[[C1:.*]] = arith.constant 1 : index
+// CHECK:         scf.for %[[I:.*]] = %[[C0]] to %[[SIZE]] step %[[C1]] {
+// CHECK:           memref.store %[[CST]], %[[ALLOC]][%[[I]]] : memref<?xf32>
+// CHECK:         }
+// CHECK:         acc.yield %[[ALLOC]] : memref<?xf32>
+// CHECK:       } combiner {
+// CHECK:       ^bb0(%[[ARG0:.*]]: memref<?xf32>, %[[ARG1:.*]]: memref<?xf32>):
+// CHECK:         %[[C0_1:.*]] = arith.constant 0 : index
+// CHECK:         %[[C1_1:.*]] = arith.constant 1 : index
+// CHECK:         %[[SIZE_1:.*]] = memref.dim %[[ARG0]], %[[C0_1]] : memref<?xf32>
+// CHECK:         scf.for %[[I_1:.*]] = %[[C0_1]] to %[[SIZE_1]] step %[[C1_1]] {
+// CHECK:           %{{.*}} = memref.load %[[ARG0]][%[[I_1]]] : memref<?xf32>
+// CHECK:           %{{.*}} = memref.load %[[ARG1]][%[[I_1]]] : memref<?xf32>
+// CHECK:           %[[SUM:.*]] = arith.addf %{{.*}}, %{{.*}} : f32
+// CHECK:           memref.store %[[SUM]], %[[ARG0]][%[[I_1]]] : memref<?xf32>
+// CHECK:         }
+// CHECK:         acc.yield %[[ARG0]] : memref<?xf32>
+// CHECK:       } destroy {
+// CHECK:       ^bb0(%[[ARG_DESTROY:.*]]: memref<?xf32>):
+// CHECK:         memref.dealloc %[[ARG_DESTROY]] : memref<?xf32>
+// CHECK:         acc.yield
+// CHECK:       }
+
+// -----
+
 acc.private.recipe @privatization_memref_i32 : memref<i32> init {
 ^bb0(%arg0: memref<i32>):
   %alloca = memref.alloca() : memref<i32>


        


More information about the Mlir-commits mailing list