[Mlir-commits] [mlir] [OpenACC] Replace terminators with scf.yield in wrapMultiBlockRegionWithSCFExecuteRegion (PR #183758)

Delaram Talaashrafi llvmlistbot at llvm.org
Fri Feb 27 09:58:19 PST 2026


https://github.com/delaram-talaashrafi updated https://github.com/llvm/llvm-project/pull/183758

>From 31cc38e62112a3126093cd0f2e03de6031551728 Mon Sep 17 00:00:00 2001
From: Delaram Talaashrafi <dtalaashrafi at rome5.pgi.net>
Date: Fri, 27 Feb 2026 07:49:14 -0800
Subject: [PATCH 1/3] [OpenACC] Replace terminators with scf.yield in
 wrapMultiBlockRegionWithSCFExecuteRegion

When wrapping a multi-block region in `scf.execute_region`, replace both
`func::ReturnOp` and `acc::YieldOp` in all the blocks with `scf.yield` so the region has a
valid SCF terminator.
---
 .../OpenACC/Utils/OpenACCUtilsLoop.cpp        | 29 ++++---
 .../Dialect/OpenACC/OpenACCUtilsLoopTest.cpp  | 78 +++++++++++++++++++
 2 files changed, 95 insertions(+), 12 deletions(-)

diff --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
index b76d3f338924c..65471d2f40867 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
@@ -14,6 +14,7 @@
 
 #include "mlir/Dialect/Arith/IR/Arith.h"
 #include "mlir/Dialect/Arith/Utils/Utils.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
 #include "mlir/Dialect/OpenACC/OpenACC.h"
 #include "mlir/Dialect/SCF/IR/SCF.h"
 #include "mlir/Dialect/SCF/Utils/Utils.h"
@@ -157,21 +158,25 @@ wrapMultiBlockRegionWithSCFExecuteRegion(Region &region, IRMapping &mapping,
   rewriter.cloneRegionBefore(region, exeRegionOp.getRegion(),
                              exeRegionOp.getRegion().end(), mapping);
 
-  // Find and replace the ACC terminator with scf.yield
-  Operation *terminator = exeRegionOp.getRegion().back().getTerminator();
-  if (auto yieldOp = dyn_cast<acc::YieldOp>(terminator)) {
-    if (yieldOp.getNumOperands() > 0) {
-      region.getParentOp()->emitError(
-          "acc.loop with results not yet supported");
-      return nullptr;
+  // Find and replace the ACC terminators with scf.yield in each block
+  for (Block &block : exeRegionOp.getRegion().getBlocks()) {
+    if (block.empty()) {
+      continue;
     }
-  } else if (!isa<acc::TerminatorOp>(terminator)) {
-    llvm_unreachable("unexpected terminator in ACC region");
+    Operation *blockTerminator = block.getTerminator();
+    if (isa<func::ReturnOp>(*blockTerminator) ||
+        isa<acc::YieldOp>(*blockTerminator)) {
+      if (blockTerminator->getNumOperands()) {
+        region.getParentOp()->emitError(
+            "acc.loop with results not yet supported");
+        return nullptr;
+      }
+      rewriter.setInsertionPointToEnd(&block);
+      (void)scf::YieldOp::create(rewriter, blockTerminator->getLoc());
+      blockTerminator->erase();
+    } 
   }
 
-  rewriter.eraseOp(terminator);
-  rewriter.setInsertionPointToEnd(&exeRegionOp.getRegion().back());
-  scf::YieldOp::create(rewriter, loc);
   return exeRegionOp;
 }
 
diff --git a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
index 83c162e32dedc..b9aad42c44b7b 100644
--- a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
@@ -649,6 +649,84 @@ TEST_F(OpenACCUtilsLoopTest,
   EXPECT_EQ(mulCount, 1u);
 }
 
+// Exact pattern from issue2257/all.mlir: entry -> header (2 preds: entry, body);
+// header cond_br to exit or body; exit has return; body branches back to header.
+TEST_F(OpenACCUtilsLoopTest,
+       WrapMultiBlockRegionWithSCFExecuteRegionIssue2257LoopPattern) {
+  auto [module, funcOp] = createModuleWithFunc();
+
+  OwningOpRef<acc::ParallelOp> parallelOp =
+      acc::ParallelOp::create(b, loc, TypeRange{}, ValueRange{});
+  Region &region = parallelOp->getRegion();
+  // Block order as in all.mlir: ^bb0 entry, ^bb1 header, ^bb2 exit, ^bb3 body
+  Block *entry = b.createBlock(&region, region.begin());
+  Block *header = b.createBlock(&region, region.end());
+  Block *exitBlock = b.createBlock(&region, region.end());
+  Block *bodyBlock = b.createBlock(&region, region.end());
+
+  // ^bb0 (entry): setup then cf.br ^bb1
+  b.setInsertionPointToEnd(entry);
+  Value c1 =
+      arith::ConstantOp::create(b, loc, b.getIndexType(), b.getIndexAttr(1));
+  arith::AddIOp::create(b, loc, c1, c1); // some op like fir.store in all.mlir
+  cf::BranchOp::create(b, loc, header);
+
+  // ^bb1 (header): 2 preds (entry, body). cond_br to exit or body
+  b.setInsertionPointToEnd(header);
+  Value cond =
+      arith::ConstantOp::create(b, loc, b.getI1Type(), b.getBoolAttr(false));
+  cf::CondBranchOp::create(b, loc, cond, exitBlock, bodyBlock);
+
+  // ^bb2 (exit): return — use acc.yield (replaced with scf.yield by the util)
+  b.setInsertionPointToEnd(exitBlock);
+  acc::YieldOp::create(b, loc);
+
+  // ^bb3 (body): body ops then cf.br ^bb1
+  b.setInsertionPointToEnd(bodyBlock);
+  Value c2 =
+      arith::ConstantOp::create(b, loc, b.getIndexType(), b.getIndexAttr(2));
+  Value c3 =
+      arith::ConstantOp::create(b, loc, b.getIndexType(), b.getIndexAttr(3));
+  arith::MulIOp::create(b, loc, c2, c3);
+  cf::BranchOp::create(b, loc, header);
+
+  EXPECT_EQ(region.getBlocks().size(), 4u);
+
+  b.setInsertionPointAfter(parallelOp.get());
+  IRMapping mapping;
+  scf::ExecuteRegionOp exeRegionOp =
+      wrapMultiBlockRegionWithSCFExecuteRegion(region, mapping, loc, b);
+
+  ASSERT_TRUE(exeRegionOp);
+
+  EXPECT_EQ(exeRegionOp.getRegion().getBlocks().size(), 4u);
+
+  // First block (entry): branch to header
+  Block &exeEntry = exeRegionOp.getRegion().front();
+  EXPECT_TRUE(isa<cf::BranchOp>(exeEntry.getTerminator()));
+
+  // Second block (header): cond_br, 2 predecessors (entry and body)
+  Block &exeHeader = *std::next(exeRegionOp.getRegion().begin());
+  EXPECT_TRUE(isa<cf::CondBranchOp>(exeHeader.getTerminator()));
+
+  // Third block (exit): scf.yield
+  Block &exeExit = *std::next(exeRegionOp.getRegion().begin(), 2);
+  EXPECT_TRUE(isa<scf::YieldOp>(exeExit.getTerminator()));
+
+  // Fourth block (body): branch back to header
+  Block &exeBody = exeRegionOp.getRegion().back();
+  EXPECT_TRUE(isa<cf::BranchOp>(exeBody.getTerminator()));
+  EXPECT_EQ(exeBody.getTerminator()->getSuccessor(0), &exeHeader);
+
+  // Body ops preserved: one addi (entry), one muli (body)
+  unsigned addCount = 0;
+  unsigned mulCount = 0;
+  exeRegionOp.getRegion().walk([&](arith::AddIOp) { ++addCount; });
+  exeRegionOp.getRegion().walk([&](arith::MulIOp) { ++mulCount; });
+  EXPECT_EQ(addCount, 1u);
+  EXPECT_EQ(mulCount, 1u);
+}
+
 //===----------------------------------------------------------------------===//
 // Error Case Tests
 //===----------------------------------------------------------------------===//

>From 1c10c289fdf98aa58cdb7931ef50510d35cc32a0 Mon Sep 17 00:00:00 2001
From: Delaram Talaashrafi <dtalaashrafi at rome5.pgi.net>
Date: Fri, 27 Feb 2026 07:57:48 -0800
Subject: [PATCH 2/3] Fix formating

---
 mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
index b9aad42c44b7b..69b3dd11e47db 100644
--- a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
@@ -649,8 +649,6 @@ TEST_F(OpenACCUtilsLoopTest,
   EXPECT_EQ(mulCount, 1u);
 }
 
-// Exact pattern from issue2257/all.mlir: entry -> header (2 preds: entry, body);
-// header cond_br to exit or body; exit has return; body branches back to header.
 TEST_F(OpenACCUtilsLoopTest,
        WrapMultiBlockRegionWithSCFExecuteRegionIssue2257LoopPattern) {
   auto [module, funcOp] = createModuleWithFunc();

>From 448ca8d69ea3f80da4002a2a6172decb94a7366f Mon Sep 17 00:00:00 2001
From: Delaram Talaashrafi <dtalaashrafi at rome5.pgi.net>
Date: Fri, 27 Feb 2026 09:55:19 -0800
Subject: [PATCH 3/3] Add a flag for func return

---
 .../mlir/Dialect/OpenACC/OpenACCUtilsLoop.h      | 16 ++++++++++------
 .../Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp   | 12 ++++++------
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsLoop.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsLoop.h
index c7d73f74ce8aa..c6c08acbc53bb 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsLoop.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsLoop.h
@@ -27,20 +27,24 @@ namespace acc {
 class LoopOp;
 
 /// Wrap a multi-block region in an scf.execute_region.
-/// Clones the given region into a new scf.execute_region, replacing
-/// acc.yield/acc.terminator with scf.yield. Use this to convert unstructured
-/// control flow (e.g. multiple blocks with branches) into a single SCF region.
+/// Clones the given region into a new scf.execute_region. Replaces acc.yield
+/// with scf.yield; when convertFuncReturn is true, also replaces func.return
+/// with scf.yield. Use this to convert unstructured control flow (e.g. multiple
+/// blocks with branches) into a single SCF region.
 /// @param region The region to wrap (cloned into the execute_region; not
 /// modified).
 /// @param mapping IR mapping for the clone; updated with block and value
 /// mappings.
 /// @param loc Location for the created execute_region op.
 /// @param rewriter RewriterBase for creating and erasing operations.
-/// @return The created scf.execute_region operation, or nullptr if the region
-///         has an acc.yield with operands (results not yet supported).
+/// @param convertFuncReturn When true, replace func.return with scf.yield in
+///        addition to acc.yield. Default is false.
+/// @return The created scf.execute_region operation, or nullptr if any replaced
+///         terminator has operands (results not yet supported).
 scf::ExecuteRegionOp
 wrapMultiBlockRegionWithSCFExecuteRegion(Region &region, IRMapping &mapping,
-                                         Location loc, RewriterBase &rewriter);
+                                         Location loc, RewriterBase &rewriter,
+                                         bool convertFuncReturn = false);
 /// Convert a structured acc.loop to scf.for.
 /// The loop arguments are converted to index type. If enableCollapse is true,
 /// nested loops are collapsed into a single loop.
diff --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
index 65471d2f40867..37171cae342dc 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
@@ -152,7 +152,8 @@ namespace acc {
 /// Wrap a multi-block region with scf.execute_region.
 scf::ExecuteRegionOp
 wrapMultiBlockRegionWithSCFExecuteRegion(Region &region, IRMapping &mapping,
-                                         Location loc, RewriterBase &rewriter) {
+                                         Location loc, RewriterBase &rewriter,
+                                         bool convertFuncReturn) {
   auto exeRegionOp = scf::ExecuteRegionOp::create(rewriter, loc, TypeRange{});
 
   rewriter.cloneRegionBefore(region, exeRegionOp.getRegion(),
@@ -160,21 +161,20 @@ wrapMultiBlockRegionWithSCFExecuteRegion(Region &region, IRMapping &mapping,
 
   // Find and replace the ACC terminators with scf.yield in each block
   for (Block &block : exeRegionOp.getRegion().getBlocks()) {
-    if (block.empty()) {
+    if (block.empty())
       continue;
-    }
     Operation *blockTerminator = block.getTerminator();
-    if (isa<func::ReturnOp>(*blockTerminator) ||
+    if ((convertFuncReturn && isa<func::ReturnOp>(*blockTerminator)) ||
         isa<acc::YieldOp>(*blockTerminator)) {
       if (blockTerminator->getNumOperands()) {
         region.getParentOp()->emitError(
-            "acc.loop with results not yet supported");
+            "region with results not yet supported");
         return nullptr;
       }
       rewriter.setInsertionPointToEnd(&block);
       (void)scf::YieldOp::create(rewriter, blockTerminator->getLoc());
       blockTerminator->erase();
-    } 
+    }
   }
 
   return exeRegionOp;



More information about the Mlir-commits mailing list