[Mlir-commits] [mlir] fcd7026 - [acc] add RegionBranchOpInterface to acc.loop (#172940)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Dec 19 10:47:09 PST 2025
Author: Susan Tan (ス-ザン タン)
Date: 2025-12-19T13:47:04-05:00
New Revision: fcd70266609f07ee210e011d676748262b5cd782
URL: https://github.com/llvm/llvm-project/commit/fcd70266609f07ee210e011d676748262b5cd782
DIFF: https://github.com/llvm/llvm-project/commit/fcd70266609f07ee210e011d676748262b5cd782.diff
LOG: [acc] add RegionBranchOpInterface to acc.loop (#172940)
Add RegionBranchOpInterface to acc.loop so that dataflow analysis can
propagate properly.
Added:
Modified:
mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 349dc8bb858b5..14902730ba165 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -2576,6 +2576,7 @@ def OpenACC_LoopOp
RecursiveMemoryEffects,
DeclareOpInterfaceMethods<ComputeRegionOpInterface>,
DeclareOpInterfaceMethods<LoopLikeOpInterface>,
+ DeclareOpInterfaceMethods<RegionBranchOpInterface>,
MemoryEffects<[MemWrite<OpenACC_ConstructResource>]>]> {
let summary = "loop construct";
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index 3dea621003a75..7f9f2a59f83be 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -391,7 +391,7 @@ void OpenACCDialect::initialize() {
//===----------------------------------------------------------------------===//
// RegionBranchOpInterface for acc.kernels / acc.parallel / acc.serial /
-// acc.kernel_environment / acc.data / acc.host_data
+// acc.kernel_environment / acc.data / acc.host_data / acc.loop
//===----------------------------------------------------------------------===//
/// Generic helper for single-region OpenACC ops that execute their body once
@@ -444,6 +444,25 @@ void HostDataOp::getSuccessorRegions(
regions);
}
+void LoopOp::getSuccessorRegions(RegionBranchPoint point,
+ SmallVectorImpl<RegionSuccessor> ®ions) {
+ // Unstructured loops: the body may contain arbitrary CFG and early exits.
+ // At the RegionBranch level, only model entry into the body and exit to the
+ // parent; any backedges are represented inside the region CFG.
+ if (getUnstructured()) {
+ if (point.isParent()) {
+ regions.push_back(RegionSuccessor(&getRegion()));
+ return;
+ }
+ regions.push_back(RegionSuccessor(getOperation(), getResults()));
+ return;
+ }
+
+ // Structured loops: model a loop-shaped region graph similar to scf.for.
+ regions.push_back(RegionSuccessor(&getRegion()));
+ regions.push_back(RegionSuccessor(getOperation(), getResults()));
+}
+
//===----------------------------------------------------------------------===//
// device_type support helpers
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir b/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
index a97fdb7d78ad1..28789868fdef9 100644
--- a/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
+++ b/mlir/test/Dialect/OpenACC/region-branchop-interface.mlir
@@ -142,4 +142,92 @@ func.func @last_mod_openacc_host_data(%arg0: memref<f32>, %mapped: memref<f32>)
return %arg0 : memref<f32>
}
+// -----
+
+// structured acc.loop: the RegionBranch is modeled
+// as scf.for with a backedge to the parent op.
+// CHECK-LABEL: test_tag: acc_loop_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_loop_inside:
+// CHECK: operand #0
+// CHECK-NEXT: - loop_region
+// CHECK-LABEL: test_tag: acc_loop_after:
+// CHECK: operand #0
+// CHECK-DAG: - pre
+// CHECK-DAG: - loop_region
+// the last writer is either the pre-loop store or
+// the store in the loop depending on the iteration count
+// CHECK-LABEL: test_tag: acc_loop_post:
+// CHECK: operand #0
+// CHECK-NEXT: - post_loop
+// CHECK-LABEL: test_tag: acc_loop_return:
+// CHECK: operand #0
+// CHECK-NEXT: - post_loop
+func.func @last_mod_openacc_loop(%arg0: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_loop_before"} : memref<f32>
+ %one = arith.constant 1.0 : f32
+ %c1_i32 = arith.constant 1 : i32
+ %c10_i32 = arith.constant 10 : i32
+ acc.loop control(%iv : i32) = (%c1_i32 : i32) to (%c10_i32 : i32)
+ step (%c1_i32 : i32) {
+ memref.store %one, %arg0[] {tag_name = "loop_region"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_loop_inside"} : memref<f32>
+ acc.yield
+ } attributes {auto_ = [#acc.device_type<none>]}
+ memref.load %arg0[] {tag = "acc_loop_after"} : memref<f32>
+ memref.store %zero, %arg0[] {tag_name = "post_loop"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_loop_post"} : memref<f32>
+ return {tag = "acc_loop_return"} %arg0 : memref<f32>
+}
+
+// -----
+
+// Unstructured acc.loop: the RegionBranch is modeled with explicit CFG and early
+// exits, and the RegionBranch graph only exposes a single entry and single
+// exit edge (no region backedge).
+//
+// CHECK-LABEL: test_tag: acc_loop_unstructured_before:
+// CHECK: operand #0
+// CHECK-NEXT: - pre
+// CHECK-LABEL: test_tag: acc_loop_unstructured_after:
+// CHECK: operand #0
+// CHECK-DAG: - loop_unstructured_early
+// CHECK-DAG: - loop_unstructured_normal
+// the last writer can be either of the two stores in the loop
+func.func @last_mod_openacc_loop_unstructured(%arg0: memref<f32>) -> memref<f32> {
+ %zero = arith.constant 0.0 : f32
+ %one = arith.constant 1.0 : f32
+ memref.store %zero, %arg0[] {tag_name = "pre"} : memref<f32>
+ memref.load %arg0[] {tag = "acc_loop_unstructured_before"} : memref<f32>
+ %c0_i32 = arith.constant 0 : i32
+ %c1_i32 = arith.constant 1 : i32
+ %c5_i32 = arith.constant 5 : i32
+ acc.loop {
+ ^entry:
+ cf.br ^header(%c0_i32 : i32)
+
+ ^header(%iv: i32):
+ %is_early = arith.cmpi eq, %iv, %c1_i32 : i32
+ cf.cond_br %is_early, ^early_exit, ^cont
+
+ ^cont:
+ // Normal loop increment and exit when iv reaches 5.
+ %iv_next = arith.addi %iv, %c1_i32 : i32
+ %is_done = arith.cmpi eq, %iv_next, %c5_i32 : i32
+ cf.cond_br %is_done, ^normal_exit, ^header(%iv_next : i32)
+
+ ^early_exit:
+ memref.store %one, %arg0[] {tag_name = "loop_unstructured_early"} : memref<f32>
+ acc.yield
+
+ ^normal_exit:
+ memref.store %one, %arg0[] {tag_name = "loop_unstructured_normal"} : memref<f32>
+ acc.yield
+ } attributes {auto_ = [#acc.device_type<none>], unstructured}
+ memref.load %arg0[] {tag = "acc_loop_unstructured_after"} : memref<f32>
+ return %arg0 : memref<f32>
+}
More information about the Mlir-commits
mailing list