[Mlir-commits] [mlir] [mlir][scf] Sink ops into multi-block scf.execute_region (PR #216993)

Kunal Dubey llvmlistbot at llvm.org
Tue Aug 18 04:27:01 PDT 2026


https://github.com/xakep8 created https://github.com/llvm/llvm-project/pull/216993

Teach scf.execute_region to report its body is invoked exactly once via RegionBranchOpInterface. This make the execute_region eligible for sinking.

Also walk all blocks in a region instead of just the entry block so uses in non-entry blocks can trigger sinking.

Added test for the same.

Fixes #216733

>From 5304c1b740edab5f009a9e052a42a8f609c103e7 Mon Sep 17 00:00:00 2001
From: Kunal Dubey <xakep8 at protonmail.com>
Date: Tue, 18 Aug 2026 12:48:01 +0530
Subject: [PATCH] [mlir][scf] Sink ops into multi-block scf.execute_region

Teach scf.execute_region to report its body is invoked exactly once via
RegionBranchOpInterface. This make the execute_region eligible for
sinking.

Also walk all blocks in a region instead of just the entry block so uses
in non-entry blocks can trigger sinking.

Added test for the same.
---
 mlir/include/mlir/Dialect/SCF/IR/SCFOps.td    |  3 ++-
 mlir/lib/Dialect/SCF/IR/SCF.cpp               |  5 +++++
 .../Transforms/Utils/ControlFlowSinkUtils.cpp |  6 +++--
 mlir/test/Dialect/SCF/control-flow-sink.mlir  | 22 +++++++++++++++++++
 4 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/mlir/include/mlir/Dialect/SCF/IR/SCFOps.td b/mlir/include/mlir/Dialect/SCF/IR/SCFOps.td
index 1e7bba2cdad35..2fe8046a92463 100644
--- a/mlir/include/mlir/Dialect/SCF/IR/SCFOps.td
+++ b/mlir/include/mlir/Dialect/SCF/IR/SCFOps.td
@@ -79,7 +79,8 @@ def ConditionOp : SCF_Op<"condition", [
 //===----------------------------------------------------------------------===//
 
 def ExecuteRegionOp : SCF_Op<"execute_region", [
-    DeclareOpInterfaceMethods<RegionBranchOpInterface, ["getSuccessorInputs"]>,
+    DeclareOpInterfaceMethods<RegionBranchOpInterface, [
+      "getRegionInvocationBounds", "getSuccessorInputs"]>,
     DeclareOpInterfaceMethods<PromotableRegionOpInterface>,
     RecursiveMemoryEffects]> {
   let summary = "operation that executes its region exactly once";
diff --git a/mlir/lib/Dialect/SCF/IR/SCF.cpp b/mlir/lib/Dialect/SCF/IR/SCF.cpp
index 36990db4b7dc4..3388fa490f996 100644
--- a/mlir/lib/Dialect/SCF/IR/SCF.cpp
+++ b/mlir/lib/Dialect/SCF/IR/SCF.cpp
@@ -277,6 +277,11 @@ void ExecuteRegionOp::getSuccessorRegions(
   regions.push_back(RegionSuccessor(getOperation()));
 }
 
+void ExecuteRegionOp::getRegionInvocationBounds(
+    ArrayRef<Attribute>, SmallVectorImpl<InvocationBounds> &bounds) {
+  bounds.emplace_back(/*lb=*/1, /*ub=*/1);
+}
+
 ValueRange ExecuteRegionOp::getSuccessorInputs(RegionSuccessor successor) {
   return successor.isOperation() ? ValueRange(getOperation()->getResults())
                                  : ValueRange();
diff --git a/mlir/lib/Transforms/Utils/ControlFlowSinkUtils.cpp b/mlir/lib/Transforms/Utils/ControlFlowSinkUtils.cpp
index 19cf4646bddd4..b546d3adef08f 100644
--- a/mlir/lib/Transforms/Utils/ControlFlowSinkUtils.cpp
+++ b/mlir/lib/Transforms/Utils/ControlFlowSinkUtils.cpp
@@ -110,8 +110,10 @@ void Sinker::tryToSinkPredecessors(Operation *user, Region *region,
 void Sinker::sinkRegion(Region *region) {
   // Initialize the work queue with all the ops in the region.
   std::vector<Operation *> stack;
-  for (Operation &op : region->getOps())
-    stack.push_back(&op);
+  for (Block &block : *region)
+    // Seed from all block so that uses in non-entry blocks and trigger sinking
+    for (Operation &op : block)
+      stack.push_back(&op);
 
   // Process all the ops depth-first. This ensures that nodes of subgraphs are
   // sunk in the correct order.
diff --git a/mlir/test/Dialect/SCF/control-flow-sink.mlir b/mlir/test/Dialect/SCF/control-flow-sink.mlir
index 2eb888b378ba1..6a3e2b651ee8a 100644
--- a/mlir/test/Dialect/SCF/control-flow-sink.mlir
+++ b/mlir/test/Dialect/SCF/control-flow-sink.mlir
@@ -58,3 +58,25 @@ func.func @test_scf_if_double_sink(%arg0: i1, %arg1: i32) {
   }
   return
 }
+
+// -----
+
+func.func private @consume(i32) -> ()
+
+// CHECK-LABEL: @test_scf_execute_region_multiblock_sink
+// CHECK-SAME:  (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32)
+// CHECK: scf.execute_region
+// CHECK-NEXT:   %[[V0:.*]] = arith.muli %[[ARG0]], %[[ARG1]]
+// CHECK-NEXT:   cf.br ^bb1
+// CHECK-NEXT: ^bb1:
+// CHECK-NEXT:   call @consume(%[[V0]])
+func.func @test_scf_execute_region_multiblock_sink(%arg0: i32, %arg1: i32) {
+  %0 = arith.muli %arg0, %arg1 : i32
+  scf.execute_region {
+    cf.br ^bb1
+  ^bb1:
+    func.call @consume(%0) : (i32) -> ()
+    scf.yield
+  }
+  return
+}



More information about the Mlir-commits mailing list