[Mlir-commits] [mlir] [mlir][openacc] Support terminators with results in wrapMultiBlockRegionWithSCFExecuteRegion (PR #185950)
Delaram Talaashrafi
llvmlistbot at llvm.org
Wed Mar 11 12:51:45 PDT 2026
https://github.com/delaram-talaashrafi updated https://github.com/llvm/llvm-project/pull/185950
>From 43500a798d770669b4494d05714ae9e461e15b45 Mon Sep 17 00:00:00 2001
From: Delaram Talaashrafi <dtalaashrafi at rome5.pgi.net>
Date: Wed, 11 Mar 2026 09:38:11 -0700
Subject: [PATCH 1/2] [mlir][openacc] Support terminators with results in
wrapMultiBlockRegionWithSCFExecuteRegion
When wrapping a multi-block region in `scf.execute_region`, this change gets the result types
from the operands of the terminators (`func.return` or `acc.yield`) and creates the `execute_region`
with those types. It then replaces each such terminator with `scf.yield(operands)`, ensuring that
multiple returns or yields with results are handled correctly.
---
.../OpenACC/Utils/OpenACCUtilsLoop.cpp | 42 +++++----
.../Dialect/OpenACC/OpenACCUtilsLoopTest.cpp | 88 ++++++++++++++-----
2 files changed, 90 insertions(+), 40 deletions(-)
diff --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
index de4f0a26a0f11..ab696deba2ff7 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsLoop.cpp
@@ -173,29 +173,33 @@ scf::ExecuteRegionOp
wrapMultiBlockRegionWithSCFExecuteRegion(Region ®ion, IRMapping &mapping,
Location loc, RewriterBase &rewriter,
bool convertFuncReturn) {
- auto exeRegionOp = scf::ExecuteRegionOp::create(rewriter, loc, TypeRange{});
+ 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))
+ terminators.push_back(term);
+ }
+ SmallVector<Type> resultTypes;
+ if (!terminators.empty())
+ for (Value operand : terminators.front()->getOperands())
+ resultTypes.push_back(operand.getType());
+
+ auto exeRegionOp =
+ scf::ExecuteRegionOp::create(rewriter, loc, TypeRange(resultTypes));
rewriter.cloneRegionBefore(region, exeRegionOp.getRegion(),
exeRegionOp.getRegion().end(), mapping);
- SmallVector<Block *, 8> blocks(
- llvm::make_pointer_range(exeRegionOp.getRegion().getBlocks()));
-
- for (Block *block : blocks) {
- if (block->empty())
- continue;
- Operation *blockTerminator = block->getTerminator();
- if ((convertFuncReturn && isa<func::ReturnOp>(*blockTerminator)) ||
- isa<acc::YieldOp>(*blockTerminator)) {
- if (blockTerminator->getNumOperands()) {
- region.getParentOp()->emitError(
- "region with results not yet supported");
- return nullptr;
- }
- rewriter.setInsertionPointToEnd(block);
- (void)scf::YieldOp::create(rewriter, blockTerminator->getLoc());
- rewriter.eraseOp(blockTerminator);
- }
+ for (Operation *term : terminators) {
+ Operation *blockTerminator = mapping.lookup(term);
+ assert(blockTerminator && "expected terminator to be in mapping");
+ rewriter.setInsertionPoint(blockTerminator);
+ (void)scf::YieldOp::create(rewriter, blockTerminator->getLoc(),
+ blockTerminator->getOperands());
+ rewriter.eraseOp(blockTerminator);
}
return exeRegionOp;
diff --git a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
index 3b1558e4f4146..307fc3a9b1633 100644
--- a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
@@ -803,19 +803,77 @@ TEST_F(OpenACCUtilsLoopTest,
EXPECT_EQ(mulCount, 1u);
}
-//===----------------------------------------------------------------------===//
-// Error Case Tests
-//===----------------------------------------------------------------------===//
+TEST_F(OpenACCUtilsLoopTest,
+ WrapMultiBlockRegionWithSCFExecuteRegionFuncMultipleReturnsWithResults) {
+ // Create a function with multiple blocks that each end with func.return
+ // with results. wrapMultiBlockRegionWithSCFExecuteRegion(..., true) should
+ // replace each func.return with scf.yield and produce an execute_region
+ // with the same result types.
+ OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+ b.setInsertionPointToStart(module->getBody());
+
+ Type i32 = b.getI32Type();
+ auto funcType = b.getFunctionType({}, {i32});
+ auto funcOp = func::FuncOp::create(b, loc, "test_func", funcType);
+ Block *entry = funcOp.addEntryBlock();
+ Block *thenBlock = b.createBlock(&funcOp.getBody(), funcOp.getBody().end());
+ Block *elseBlock = b.createBlock(&funcOp.getBody(), funcOp.getBody().end());
+
+ b.setInsertionPointToEnd(entry);
+ Value cond =
+ arith::ConstantOp::create(b, loc, b.getI1Type(), b.getBoolAttr(true));
+ cf::CondBranchOp::create(b, loc, cond, thenBlock, elseBlock);
+
+ b.setInsertionPointToEnd(thenBlock);
+ Value thenV = createI32Constant(1);
+ func::ReturnOp::create(b, loc, ValueRange{thenV});
+
+ b.setInsertionPointToEnd(elseBlock);
+ Value elseV = createI32Constant(3);
+ func::ReturnOp::create(b, loc, ValueRange{elseV});
+
+ Region ®ion = funcOp.getBody();
+ EXPECT_EQ(region.getBlocks().size(), 3u);
+
+ b.setInsertionPointAfter(funcOp);
+ IRMapping mapping;
+ scf::ExecuteRegionOp exeRegionOp = wrapMultiBlockRegionWithSCFExecuteRegion(
+ region, mapping, loc, b, /*convertFuncReturn=*/true);
+
+ ASSERT_TRUE(exeRegionOp);
+
+ // execute_region should have one result (same as func.return operands)
+ EXPECT_EQ(exeRegionOp.getNumResults(), 1u);
+ EXPECT_TRUE(exeRegionOp.getResult(0).getType().isSignlessInteger(32));
+
+ // Cloned region should have 3 blocks
+ EXPECT_EQ(exeRegionOp.getRegion().getBlocks().size(), 3u);
+
+ // Entry block: cond_br unchanged
+ Block &exeEntry = exeRegionOp.getRegion().front();
+ EXPECT_TRUE(isa<cf::CondBranchOp>(exeEntry.getTerminator()));
+
+ // Both then and else blocks should now have scf.yield with one operand
+ unsigned yieldCount = 0;
+ for (Block &block : exeRegionOp.getRegion().getBlocks()) {
+ if (isa<scf::YieldOp>(block.getTerminator())) {
+ EXPECT_EQ(block.getTerminator()->getNumOperands(), 1u);
+ yieldCount++;
+ }
+ }
+ EXPECT_EQ(yieldCount, 2u) << "both return blocks should be scf.yield";
+}
-TEST_F(OpenACCUtilsLoopTest, UnstructuredLoopWithYieldOperandsReturnsNullptr) {
+TEST_F(OpenACCUtilsLoopTest, UnstructuredLoopWithYieldOperandsSucceeds) {
auto [module, funcOp] = createModuleWithFunc();
Value c0 = createIndexConstant(0);
Value c10 = createIndexConstant(10);
Value c1 = createIndexConstant(1);
- // Create an unstructured loop where the yield has operands (simulating
- // a loop with results, which is not yet supported)
+ // Create an unstructured loop where the yield has operands (loop with
+ // results); conversion should succeed and produce execute_region with
+ // results.
auto loopOp = acc::LoopOp::create(b, loc, {c0}, {c10}, {c1},
acc::LoopParMode::loop_independent);
loopOp.setInclusiveUpperboundAttr(b.getDenseBoolArrayAttr({true}));
@@ -832,28 +890,16 @@ TEST_F(OpenACCUtilsLoopTest, UnstructuredLoopWithYieldOperandsReturnsNullptr) {
cf::BranchOp::create(b, loc, exitBlock);
b.setInsertionPointToEnd(exitBlock);
- // Create a yield with operands - this triggers the error
Value result = createI32Constant(42);
acc::YieldOp::create(b, loc, ValueRange{result});
}
- // InsertionGuard restores insertion point to after loopOp
-
- // Use a diagnostic handler to capture the error
- std::string errorMsg;
- ScopedDiagnosticHandler handler(&context, [&](Diagnostic &diag) {
- if (diag.getSeverity() == DiagnosticSeverity::Error) {
- llvm::raw_string_ostream os(errorMsg);
- os << diag;
- }
- return success();
- });
scf::ExecuteRegionOp exeRegionOp =
convertUnstructuredACCLoopToSCFExecuteRegion(loopOp, b);
- // Should return nullptr due to unsupported loop with results
- EXPECT_FALSE(exeRegionOp);
- EXPECT_TRUE(errorMsg.find("not yet supported") != std::string::npos);
+ ASSERT_TRUE(exeRegionOp);
+ EXPECT_EQ(exeRegionOp.getNumResults(), 1u);
+ EXPECT_TRUE(exeRegionOp.getResult(0).getType().isSignlessInteger(32));
}
//===----------------------------------------------------------------------===//
>From 9643746c3c8807dd212a5fa4da0d2a037e07c4da Mon Sep 17 00:00:00 2001
From: Delaram Talaashrafi <dtalaashrafi at rome5.pgi.net>
Date: Wed, 11 Mar 2026 09:40:22 -0700
Subject: [PATCH 2/2] Format
---
mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
index 307fc3a9b1633..3443ac7964bc2 100644
--- a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsLoopTest.cpp
@@ -839,7 +839,7 @@ TEST_F(OpenACCUtilsLoopTest,
IRMapping mapping;
scf::ExecuteRegionOp exeRegionOp = wrapMultiBlockRegionWithSCFExecuteRegion(
region, mapping, loc, b, /*convertFuncReturn=*/true);
-
+
ASSERT_TRUE(exeRegionOp);
// execute_region should have one result (same as func.return operands)
More information about the Mlir-commits
mailing list