[Mlir-commits] [mlir] 8342bf9 - [mlir][acc] Add acc.predicate_region for redundant/single semantics (#203011)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Jun 10 08:54:16 PDT 2026
Author: Razvan Lupusoru
Date: 2026-06-10T08:54:10-07:00
New Revision: 8342bf926db0436f0a64f69b4b38238e4fa78ae9
URL: https://github.com/llvm/llvm-project/commit/8342bf926db0436f0a64f69b4b38238e4fa78ae9
DIFF: https://github.com/llvm/llvm-project/commit/8342bf926db0436f0a64f69b4b38238e4fa78ae9.diff
LOG: [mlir][acc] Add acc.predicate_region for redundant/single semantics (#203011)
Add acc.predicate_region, an intermediate codegen operation that groups
statements at intermediate points in a loop nest within
acc.compute_region. OpenACC distinguishes partitioned loop execution
from single and redundant execution at nest transitions: for example,
gang-redundant code runs on all gangs but not as partitioned gang-loop
iterations, and worker-single or vector-single code runs on one worker
or vector lane rather than across the full worker or vector partition.
This grouping marks code whose execution scope differs from surrounding
partitioned loops, so predication and synchronization can be applied
correctly during lowering.
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 71c764aa5675b..26fb6c10e51e6 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
@@ -527,4 +527,59 @@ def OpenACC_ComputeRegionOp
let hasCustomAssemblyFormat = 1;
}
+//===----------------------------------------------------------------------===//
+// acc.predicate_region
+//===----------------------------------------------------------------------===//
+
+def OpenACC_PredicateRegionOp
+ : OpenACC_Op<"predicate_region", [RecursiveMemoryEffects, NoTerminator]> {
+ let summary = "Groups operations at intermediate loop-nest points";
+ let description = [{
+ Groups statements within an `acc.compute_region` that sit at an
+ intermediate point in a loop nest (outside a partitioned loop body,
+ between or around nested loops). This grouping marks code whose execution
+ scope
diff ers from that of surrounding partitioned loops, so predication
+ and synchronization can be applied correctly during lowering. Corresponds
+ to OpenACC single or redundant execution at nest transitions.
+
+ Example:
+ ```mlir
+ // !$acc parallel num_gangs(NG) vector_length(VL)
+ // !$acc loop gang
+ // !$acc atomic update
+ // !$acc loop vector
+ // !$acc atomic update
+ %w_gang = acc.par_width %cNG {par_dim = #acc.par_dim<block_x>}
+ %w_vector = acc.par_width %cVL {par_dim = #acc.par_dim<thread_x>}
+ acc.compute_region launch(%ng = %w_gang, %vl = %w_vector)
+ ins(%arg_c1 = %c1, %arg_c2 = %c2) : (memref<i32>, memref<i32>) {
+ scf.parallel (%i) = (%c1) to (%cN) step (%c1) {
+ acc.predicate_region {
+ acc.atomic.update %arg_c1 : memref<i32> {
+ ^bb0(%old: i32):
+ %one = arith.constant 1 : i32
+ %sum = arith.addi %old, %one : i32
+ acc.yield %sum : i32
+ }
+ }
+ scf.parallel (%j) = (%c1) to (%cN) step (%c1) {
+ acc.atomic.update %arg_c2 : memref<i32> {
+ ^bb0(%old: i32):
+ %one = arith.constant 1 : i32
+ %sum = arith.addi %old, %one : i32
+ acc.yield %sum : i32
+ }
+ scf.reduce
+ } {acc.par_dims = #acc<par_dims[thread_x]>}
+ scf.reduce
+ } {acc.par_dims = #acc<par_dims[block_x]>}
+ acc.yield
+ } {origin = "acc.parallel"}
+ ```
+ }];
+ let regions = (region AnyRegion:$region);
+ let assemblyFormat = "$region attr-dict";
+ let hasVerifier = 1;
+}
+
#endif // OPENACC_CG_OPS
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
index c0c2bb7654830..060680681299b 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
@@ -782,6 +782,20 @@ ParseResult ComputeRegionOp::parse(OpAsmParser &parser,
return success();
}
+//===----------------------------------------------------------------------===//
+// PredicateRegionOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult PredicateRegionOp::verify() {
+ if (getRegion().empty())
+ return emitOpError("region needs to have at least one block");
+ if (getRegion().front().getNumArguments() > 0)
+ return emitOpError("region cannot have any arguments");
+ if (!getOperation()->getParentOfType<ComputeRegionOp>())
+ return emitOpError("must be nested within an acc.compute_region operation");
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// GPUParallelDimAttr
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/OpenACC/invalid-cg.mlir b/mlir/test/Dialect/OpenACC/invalid-cg.mlir
index 16393fd77bfc9..da280bda8ea91 100644
--- a/mlir/test/Dialect/OpenACC/invalid-cg.mlir
+++ b/mlir/test/Dialect/OpenACC/invalid-cg.mlir
@@ -72,3 +72,39 @@ func.func @reduction_accumulate_empty_par_dims() {
: i32 -> memref<i32> {par_dims = #acc<par_dims[]>}
return
}
+
+// -----
+
+func.func @predicate_region_empty() {
+ acc.compute_region {
+ // expected-error at +1 {{region needs to have at least one block}}
+ acc.predicate_region {
+ }
+ acc.yield
+ } {origin = "acc.parallel"}
+ return
+}
+
+// -----
+
+func.func @predicate_region_with_args() {
+ acc.compute_region {
+ // expected-error at +1 {{region cannot have any arguments}}
+ acc.predicate_region {
+ ^bb0(%arg0: index):
+ %c0 = arith.constant 0 : index
+ }
+ acc.yield
+ } {origin = "acc.parallel"}
+ return
+}
+
+// -----
+
+func.func @predicate_region_outside_compute_region() {
+ // expected-error at +1 {{must be nested within an acc.compute_region operation}}
+ acc.predicate_region {
+ %c0 = arith.constant 0 : i32
+ }
+ return
+}
diff --git a/mlir/test/Dialect/OpenACC/ops-cg.mlir b/mlir/test/Dialect/OpenACC/ops-cg.mlir
index e424bf7bd5eab..52ca1a38ebb73 100644
--- a/mlir/test/Dialect/OpenACC/ops-cg.mlir
+++ b/mlir/test/Dialect/OpenACC/ops-cg.mlir
@@ -333,3 +333,89 @@ func.func @compute_region_with_results() -> i32 {
// CHECK: {{.*}} = acc.compute_region launch(%{{.*}} = %[[W]]) -> i32 {
// CHECK: acc.yield
// CHECK: } {origin = "acc.parallel"}
+
+// -----
+
+// CHECK-LABEL: func @predicate_region_gang_vector_atomics
+func.func @predicate_region_gang_vector_atomics(%c1: memref<i32>, %c2: memref<i32>) {
+ %c3 = arith.constant 3 : index
+ %c16 = arith.constant 16 : index
+ %copy_c1 = acc.copyin varPtr(%c1 : memref<i32>) -> memref<i32> {dataClause = #acc<data_clause acc_copy>}
+ %copy_c2 = acc.copyin varPtr(%c2 : memref<i32>) -> memref<i32> {dataClause = #acc<data_clause acc_copy>}
+ acc.kernel_environment dataOperands(%copy_c1, %copy_c2 : memref<i32>, memref<i32>) {
+ %w_gang = acc.par_width %c3 {par_dim = #acc.par_dim<block_x>}
+ %w_vector = acc.par_width %c16 {par_dim = #acc.par_dim<thread_x>}
+ acc.compute_region launch(%arg0 = %w_gang, %arg1 = %w_vector)
+ ins(%arg2 = %copy_c1, %arg3 = %copy_c2) : (memref<i32>, memref<i32>) {
+ %c1_idx = arith.constant 1 : index
+ %c10 = arith.constant 10 : index
+ scf.parallel (%i) = (%c1_idx) to (%c10) step (%c1_idx) {
+ acc.predicate_region {
+ acc.atomic.update %arg2 : memref<i32> {
+ ^bb0(%old: i32):
+ %one = arith.constant 1 : i32
+ %sum = arith.addi %old, %one : i32
+ acc.yield %sum : i32
+ }
+ }
+ scf.parallel (%j) = (%c1_idx) to (%c10) step (%c1_idx) {
+ acc.atomic.update %arg3 : memref<i32> {
+ ^bb0(%old: i32):
+ %one = arith.constant 1 : i32
+ %sum = arith.addi %old, %one : i32
+ acc.yield %sum : i32
+ }
+ scf.reduce
+ } {acc.par_dims = #acc<par_dims[thread_x]>}
+ scf.reduce
+ } {acc.par_dims = #acc<par_dims[block_x]>}
+ acc.yield
+ } {origin = "acc.parallel"}
+ }
+ acc.copyout accPtr(%copy_c1 : memref<i32>) to varPtr(%c1 : memref<i32>) {dataClause = #acc<data_clause acc_copy>}
+ acc.copyout accPtr(%copy_c2 : memref<i32>) to varPtr(%c2 : memref<i32>) {dataClause = #acc<data_clause acc_copy>}
+ return
+}
+// CHECK: acc.predicate_region {
+// CHECK: acc.atomic.update
+// CHECK: }
+
+// -----
+
+// CHECK-LABEL: func @predicate_region_gang_redundant_setup
+func.func @predicate_region_gang_redundant_setup(%idx: memref<i32>, %table: memref<10xi32>) {
+ %c3 = arith.constant 3 : index
+ %c16 = arith.constant 16 : index
+ %copy_idx = acc.copyin varPtr(%idx : memref<i32>) -> memref<i32> {dataClause = #acc<data_clause acc_copy>}
+ %copy_table = acc.copyin varPtr(%table : memref<10xi32>) -> memref<10xi32>
+ acc.kernel_environment dataOperands(%copy_idx, %copy_table : memref<i32>, memref<10xi32>) {
+ %w_gang = acc.par_width %c3 {par_dim = #acc.par_dim<block_x>}
+ %w_vector = acc.par_width %c16 {par_dim = #acc.par_dim<thread_x>}
+ acc.compute_region launch(%arg0 = %w_gang, %arg1 = %w_vector)
+ ins(%arg2 = %copy_idx, %arg3 = %copy_table) : (memref<i32>, memref<10xi32>) {
+ %c0 = arith.constant 0 : index
+ %c1 = arith.constant 1 : index
+ %c10 = arith.constant 10 : index
+ %v = memref.load %arg3[%c0] : memref<10xi32>
+ acc.predicate_region {
+ memref.store %v, %arg2[] : memref<i32>
+ }
+ scf.parallel (%i) = (%c1) to (%c10) step (%c1) {
+ %i_val = memref.load %arg2[] : memref<i32>
+ %twice = arith.addi %i_val, %i_val : i32
+ memref.store %twice, %arg2[] : memref<i32>
+ scf.parallel (%j) = (%c1) to (%c10) step (%c1) {
+ scf.reduce
+ } {acc.par_dims = #acc<par_dims[thread_x]>}
+ scf.reduce
+ } {acc.par_dims = #acc<par_dims[block_x]>}
+ acc.yield
+ } {origin = "acc.kernels"}
+ }
+ acc.copyout accPtr(%copy_idx : memref<i32>) to varPtr(%idx : memref<i32>) {dataClause = #acc<data_clause acc_copy>}
+ acc.delete accPtr(%copy_table : memref<10xi32>)
+ return
+}
+// CHECK: acc.predicate_region {
+// CHECK: memref.store
+// CHECK: }
More information about the Mlir-commits
mailing list