[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> &regions) {
+  // 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