[Mlir-commits] [mlir] [OpenACC][NFC] Generalize wrapMultiBlockRegionWithSCFExecuteRegion with variadic template (PR #187359)
Zhen Wang
llvmlistbot at llvm.org
Wed Mar 18 12:06:10 PDT 2026
https://github.com/wangzpgi created https://github.com/llvm/llvm-project/pull/187359
Generalize wrapMultiBlockRegionWithSCFExecuteRegion to accept terminator types as template arguments instead of hardcoding acc::YieldOp / func::ReturnOp.
This replaces the bool convertFuncReturn parameter with a variadic template <typename... TerminatorOps> wrapper over a function_ref-based implementation, enabling downstream dialects (e.g., CUF with fir::FirEndOp) to reuse the utility without modifying it.
```
// Before:
wrapMultiBlockRegionWithSCFExecuteRegion(region, mapping, loc, rewriter);
wrapMultiBlockRegionWithSCFExecuteRegion(region, mapping, loc, rewriter, /*convertFuncReturn=*/true);
// After:
wrapMultiBlockRegionWithSCFExecuteRegion<acc::YieldOp>(region, mapping, loc, rewriter);
wrapMultiBlockRegionWithSCFExecuteRegion<acc::YieldOp, func::ReturnOp>(region, mapping, loc, rewriter);
```
>From e29dca0fe390c9ce1b40b300c183c49847edaf79 Mon Sep 17 00:00:00 2001
From: Zhen Wang <zhenw at nvidia.com>
Date: Wed, 18 Mar 2026 10:40:43 -0700
Subject: [PATCH] refactor wrapMultiBlockRegionWithSCFExecuteRegion
---
.../mlir/Dialect/OpenACC/OpenACCUtilsLoop.h | 25 +++++++++++++------
.../Dialect/OpenACC/Utils/OpenACCUtilsCG.cpp | 7 ++++--
.../OpenACC/Utils/OpenACCUtilsLoop.cpp | 20 +++++++--------
.../Dialect/OpenACC/OpenACCUtilsLoopTest.cpp | 16 +++++++-----
4 files changed, 41 insertions(+), 27 deletions(-)
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsLoop.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsLoop.h
index e0428bec620ca..b26d576bcd47c 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsLoop.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsLoop.h
@@ -30,25 +30,34 @@ std::pair<llvm::SmallVector<Value>, Block::iterator>
cloneACCRegionInto(Region *src, Block *dest, Block::iterator inlinePoint,
IRMapping &mapping, ValueRange resultsToReplace);
+/// Implementation detail for wrapMultiBlockRegionWithSCFExecuteRegion.
+scf::ExecuteRegionOp wrapMultiBlockRegionWithSCFExecuteRegionImpl(
+ Region ®ion, IRMapping &mapping, Location loc, RewriterBase &rewriter,
+ llvm::function_ref<bool(Operation *)> isTerminatorToReplace);
+
/// Wrap a multi-block region in an scf.execute_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.
+/// Clones the given region into a new scf.execute_region. Terminators matching
+/// any of the \p TerminatorOps types are replaced 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.
-/// @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).
+template <typename... TerminatorOps>
scf::ExecuteRegionOp
wrapMultiBlockRegionWithSCFExecuteRegion(Region ®ion, IRMapping &mapping,
- Location loc, RewriterBase &rewriter,
- bool convertFuncReturn = false);
+ Location loc,
+ RewriterBase &rewriter) {
+ return wrapMultiBlockRegionWithSCFExecuteRegionImpl(
+ region, mapping, loc, rewriter,
+ [](Operation *op) { return isa<TerminatorOps...>(op); });
+}
+
/// 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/OpenACCUtilsCG.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsCG.cpp
index 661074444a055..73d837e8c5002 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsCG.cpp
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsCG.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/OpenACC/OpenACCUtilsCG.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/Dialect/OpenACC/OpenACCUtilsLoop.h"
#include "mlir/IR/BuiltinOps.h"
@@ -99,8 +100,10 @@ ComputeRegionOp buildComputeRegion(Location loc, ValueRange launchArgs,
rewriter.setInsertionPointToEnd(entryBlock);
YieldOp::create(rewriter, loc, yieldOperands);
} else {
- auto exeRegion = mlir::acc::wrapMultiBlockRegionWithSCFExecuteRegion(
- regionToClone, mapping, loc, rewriter, /*convertFuncReturn=*/true);
+ auto exeRegion =
+ mlir::acc::wrapMultiBlockRegionWithSCFExecuteRegion<acc::YieldOp,
+ func::ReturnOp>(
+ regionToClone, mapping, loc, rewriter);
if (!exeRegion) {
rewriter.eraseOp(computeRegion);
return nullptr;
diff --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
index 307d0afb8f697..f11fe2baca019 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
@@ -14,7 +14,6 @@
#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"
@@ -147,17 +146,15 @@ cloneACCRegionInto(Region *src, Block *dest, Block::iterator inlinePoint,
}
/// Wrap a multi-block region with scf.execute_region.
-scf::ExecuteRegionOp
-wrapMultiBlockRegionWithSCFExecuteRegion(Region ®ion, IRMapping &mapping,
- Location loc, RewriterBase &rewriter,
- bool convertFuncReturn) {
+scf::ExecuteRegionOp wrapMultiBlockRegionWithSCFExecuteRegionImpl(
+ Region ®ion, IRMapping &mapping, Location loc, RewriterBase &rewriter,
+ function_ref<bool(Operation *)> isTerminatorToReplace) {
SmallVector<Operation *> terminators;
for (Block &block : region.getBlocks()) {
if (block.empty())
continue;
Operation *term = block.getTerminator();
- if ((convertFuncReturn && isa<func::ReturnOp>(*term)) ||
- isa<acc::YieldOp>(*term))
+ if (isTerminatorToReplace(term))
terminators.push_back(term);
}
SmallVector<Type> resultTypes;
@@ -301,8 +298,9 @@ scf::ParallelOp convertACCLoopToSCFParallel(LoopOp loopOp,
mapping);
if (!loopOp.getRegion().hasOneBlock()) {
- auto exeRegion = wrapMultiBlockRegionWithSCFExecuteRegion(
- loopOp.getRegion(), mapping, loc, rewriter);
+ auto exeRegion =
+ wrapMultiBlockRegionWithSCFExecuteRegion<acc::YieldOp>(
+ loopOp.getRegion(), mapping, loc, rewriter);
if (!exeRegion) {
rewriter.eraseOp(parallelOp);
return nullptr;
@@ -333,8 +331,8 @@ convertUnstructuredACCLoopToSCFExecuteRegion(LoopOp loopOp,
"builder insertion point must not be inside the loop being converted");
IRMapping mapping;
- return wrapMultiBlockRegionWithSCFExecuteRegion(loopOp.getRegion(), mapping,
- loopOp->getLoc(), rewriter);
+ return wrapMultiBlockRegionWithSCFExecuteRegion<acc::YieldOp>(
+ loopOp.getRegion(), mapping, loopOp->getLoc(), rewriter);
}
} // namespace acc
diff --git a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
index f2b7295f68aec..d8720955cc82c 100644
--- a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
@@ -661,7 +661,8 @@ TEST_F(OpenACCUtilsLoopTest,
b.setInsertionPointAfter(parallelOp.get());
IRMapping mapping;
scf::ExecuteRegionOp exeRegionOp =
- wrapMultiBlockRegionWithSCFExecuteRegion(region, mapping, loc, b);
+ wrapMultiBlockRegionWithSCFExecuteRegion<acc::YieldOp>(region, mapping,
+ loc, b);
ASSERT_TRUE(exeRegionOp);
@@ -729,7 +730,8 @@ TEST_F(OpenACCUtilsLoopTest,
b.setInsertionPointAfter(parallelOp.get());
IRMapping mapping;
scf::ExecuteRegionOp exeRegionOp =
- wrapMultiBlockRegionWithSCFExecuteRegion(region, mapping, loc, b);
+ wrapMultiBlockRegionWithSCFExecuteRegion<acc::YieldOp>(region, mapping,
+ loc, b);
ASSERT_TRUE(exeRegionOp);
@@ -806,8 +808,9 @@ TEST_F(OpenACCUtilsLoopTest,
b.setInsertionPointAfter(funcOp);
IRMapping mapping;
- scf::ExecuteRegionOp exeRegionOp = wrapMultiBlockRegionWithSCFExecuteRegion(
- region, mapping, loc, b, /*convertFuncReturn=*/true);
+ scf::ExecuteRegionOp exeRegionOp =
+ wrapMultiBlockRegionWithSCFExecuteRegion<acc::YieldOp, func::ReturnOp>(
+ region, mapping, loc, b);
ASSERT_TRUE(exeRegionOp);
@@ -873,8 +876,9 @@ TEST_F(OpenACCUtilsLoopTest,
b.setInsertionPointAfter(funcOp);
IRMapping mapping;
- scf::ExecuteRegionOp exeRegionOp = wrapMultiBlockRegionWithSCFExecuteRegion(
- region, mapping, loc, b, /*convertFuncReturn=*/true);
+ scf::ExecuteRegionOp exeRegionOp =
+ wrapMultiBlockRegionWithSCFExecuteRegion<acc::YieldOp, func::ReturnOp>(
+ region, mapping, loc, b);
ASSERT_TRUE(exeRegionOp);
More information about the Mlir-commits
mailing list