[Mlir-commits] [mlir] 35e9540 - [mlir][SCF] Improve `ForOp::getSuccessorRegions` (#177116)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Jan 21 10:11:26 PST 2026
Author: Matthias Springer
Date: 2026-01-21T19:11:20+01:00
New Revision: 35e9540ba8bd54d31a8b805d70c5c8607cf73cf1
URL: https://github.com/llvm/llvm-project/commit/35e9540ba8bd54d31a8b805d70c5c8607cf73cf1
DIFF: https://github.com/llvm/llvm-project/commit/35e9540ba8bd54d31a8b805d70c5c8607cf73cf1.diff
LOG: [mlir][SCF] Improve `ForOp::getSuccessorRegions` (#177116)
- Loops with 0 iterations always branch back to the parent.
- Loops with 1 iteration always branch into the loop, then immediately
back to the parent.
This change improves the quality of data flow analyses (e.g., dead code
analysis). It is also in preparation of adding a generic region inlining
canonicalization pattern for `RegionBranchOpInterface` ops (#176641).
---------
Co-authored-by: Jakub Kuderski <jakub at nod-labs.com>
Added:
Modified:
mlir/lib/Dialect/SCF/IR/SCF.cpp
mlir/test/Analysis/DataFlow/test-dead-code-analysis.mlir
mlir/test/Dialect/Arith/int-range-narrowing.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Dialect/SCF/IR/SCF.cpp b/mlir/lib/Dialect/SCF/IR/SCF.cpp
index 5b6e9304de505..983f2de63784a 100644
--- a/mlir/lib/Dialect/SCF/IR/SCF.cpp
+++ b/mlir/lib/Dialect/SCF/IR/SCF.cpp
@@ -704,6 +704,26 @@ OperandRange ForOp::getEntrySuccessorOperands(RegionSuccessor successor) {
void ForOp::getSuccessorRegions(RegionBranchPoint point,
SmallVectorImpl<RegionSuccessor> ®ions) {
+ if (std::optional<APInt> tripCount = getStaticTripCount()) {
+ // The loop has a known static trip count.
+ if (point.isParent()) {
+ if (*tripCount == 0) {
+ // The loop has zero iterations. It branches directly back to the
+ // parent.
+ regions.push_back(RegionSuccessor::parent());
+ } else {
+ // The loop has at least one iteration. It branches into the body.
+ regions.push_back(RegionSuccessor(&getRegion()));
+ }
+ return;
+ } else if (*tripCount == 1) {
+ // The loop has exactly 1 iteration. Therefore, it branches from the
+ // region to the parent. (No further iteration.)
+ regions.push_back(RegionSuccessor::parent());
+ return;
+ }
+ }
+
// Both the operation itself and the region may be branching into the body or
// back into the operation itself. It is possible for loop not to enter the
// body.
diff --git a/mlir/test/Analysis/DataFlow/test-dead-code-analysis.mlir b/mlir/test/Analysis/DataFlow/test-dead-code-analysis.mlir
index 7ce5c0f9e3d5a..4d3a61601a85c 100644
--- a/mlir/test/Analysis/DataFlow/test-dead-code-analysis.mlir
+++ b/mlir/test/Analysis/DataFlow/test-dead-code-analysis.mlir
@@ -283,3 +283,41 @@ func.func @test_forall_op_control_flow(%num_threads: index) {
} {tag = "test_forall_op_control_flow"}
return
}
+
+func.func @test_for_op_control_flow() {
+ %c1 = arith.constant 1 : index
+ %c5 = arith.constant 5 : index
+ %c6 = arith.constant 6 : index
+ %c7 = arith.constant 7 : index
+
+ // Test case 1: Zero loop iterations.
+ // CHECK: test_for_op_control_flow_zero:
+ // CHECK: region #0
+ // CHECK: ^bb0 = dead
+ // CHECK: op_preds: (all) predecessors:
+ // CHECK: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %c1 {...} {tag = "test_for_op_control_flow_zero"}
+ scf.for %iv = %c5 to %c5 step %c1 {} {tag = "test_for_op_control_flow_zero"}
+
+ // Test case 2: One loop iteration.
+ // CHECK: test_for_op_control_flow_one:
+ // CHECK: region #0
+ // CHECK: ^bb0 = live
+ // CHECK: region_preds: (all) predecessors:
+ // CHECK: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {...} {tag = "test_for_op_control_flow_one"}
+ // CHECK: op_preds: (all) predecessors:
+ // CHECK: scf.yield
+ scf.for %iv = %c5 to %c6 step %c1 {} {tag = "test_for_op_control_flow_one"}
+
+ // Test case 3: More than one loop iteration.
+ // CHECK: test_for_op_control_flow_multi:
+ // CHECK: region #0
+ // CHECK: ^bb0 = live
+ // CHECK: region_preds: (all) predecessors:
+ // CHECK: scf.for %arg0 = %{{.*}} to %{{.*}} step %{{.*}} {...} {tag = "test_for_op_control_flow_multi"}
+ // CHECK: scf.yield
+ // CHECK: op_preds: (all) predecessors:
+ // CHECK: scf.yield
+ scf.for %iv = %c5 to %c7 step %c1 {} {tag = "test_for_op_control_flow_multi"}
+
+ return
+}
diff --git a/mlir/test/Dialect/Arith/int-range-narrowing.mlir b/mlir/test/Dialect/Arith/int-range-narrowing.mlir
index 9107bf649b561..e2cd9b50f6736 100644
--- a/mlir/test/Dialect/Arith/int-range-narrowing.mlir
+++ b/mlir/test/Dialect/Arith/int-range-narrowing.mlir
@@ -361,7 +361,7 @@ func.func private @use_i64(i64)
// CHECK-LABEL: func.func @loop_with_iter_arg
func.func @loop_with_iter_arg() {
%c0 = arith.constant 0 : index
- %c1 = arith.constant 0 : index
+ %c1 = arith.constant 1 : index
%c16 = arith.constant 16 : index
%cst = arith.constant dense<0.000000e+00> : vector<4xf32>
More information about the Mlir-commits
mailing list