[Mlir-commits] [mlir] [mlir][affine] Allow affine.min/max results as dimension IDs (PR #233411)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Oct 19 04:58:57 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: lonely eagle (linuxlonelyeagle)

<details>
<summary>Changes</summary>

An `affine.for` lower bound can express a maximum, and an upper bound can
express a minimum. When splitting a tiled loop into source-only and shared
iterations, the source-only loop may need a maximum *inside* its upper-bound
minimum:

```mlir
// Lower bound of the destination point loop within this tile.
%cut = affine.max affine_map<(d0) -> (3, d0 * 4)>(%tile)
affine.for %i = max affine_map<(d0) -> (1, d0 * 4)>(%tile)
              to min affine_map<(d0, d1) -> (4, d0 * 4 + 4, d1)>(%tile, %cut) {
  // Source-only iterations.
}
```

The verifier currently rejects `%cut` as a dimension ID in the loop bound,
even though its operand `%tile` is a valid dimension ID. This change allows
`affine.min` and `affine.max` results to be used as dimension IDs when all
their operands are valid dimensions. The change also updates the Affine
dialect documentation and adds positive and negative verifier tests.

---
Full diff: https://github.com/llvm/llvm-project/pull/233411.diff


4 Files Affected:

- (modified) mlir/docs/Dialects/Affine.md (+4-2) 
- (modified) mlir/lib/Dialect/Affine/IR/AffineOps.cpp (+6-1) 
- (modified) mlir/test/Dialect/Affine/invalid.mlir (+26) 
- (modified) mlir/test/Dialect/Affine/ops.mlir (+17) 


``````````diff
diff --git a/mlir/docs/Dialects/Affine.md b/mlir/docs/Dialects/Affine.md
index 90aa43a85d877..2d889d16c1926 100644
--- a/mlir/docs/Dialects/Affine.md
+++ b/mlir/docs/Dialects/Affine.md
@@ -83,8 +83,10 @@ location of the SSA use. Dimensions may be bound not only to anything that a
 symbol is bound to, but also to induction variables of enclosing
 [`affine.for`](#affinefor-affineaffineforop) and
 [`affine.parallel`](#affineparallel-affineaffineparallelop) operations, and the result
-of an [`affine.apply` operation](#affineapply-affineaffineapplyop) (which recursively
-may use other dimensions and symbols).
+of an [`affine.apply` operation](#affineapply-affineaffineapplyop), or an
+[`affine.min`](#affinemin-affineaffineminop) or
+[`affine.max`](#affinemax-affineaffinemaxop) operation, whose operands are
+valid dimensions (which recursively may use other dimensions and symbols).
 
 ### Affine Expressions
 
diff --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
index 5f5a49a68eb67..16c7e44711629 100644
--- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
+++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
@@ -309,6 +309,8 @@ bool mlir::affine::isValidDim(Value value) {
 // *) It is valid as a symbol.
 // *) It is an induction variable.
 // *) It is the result of an affine apply operation with dimension id operands.
+// *) It is the result of an affine min or max operation with dimension id
+//    operands.
 // *) It is the result of a more specialized index transformation (ex.
 // delinearize_index or linearize_index) with dimension id operands.
 bool mlir::affine::isValidDim(Value value, Region *region) {
@@ -330,6 +332,10 @@ bool mlir::affine::isValidDim(Value value, Region *region) {
   // Affine apply operation is ok if all of its operands are ok.
   if (auto applyOp = dyn_cast<AffineApplyOp>(op))
     return applyOp.isValidDim(region);
+  // Affine min and max results are valid dimensions when their operands are.
+  if (isa<AffineMinOp, AffineMaxOp>(op))
+    return llvm::all_of(op->getOperands(),
+                        [&](Value arg) { return ::isValidDim(arg, region); });
   // delinearize_index and linearize_index are special forms of apply
   // and so are valid dimensions if all their arguments are valid dimensions.
   if (isa<AffineDelinearizeIndexOp, AffineLinearizeIndexOp>(op))
@@ -5090,7 +5096,6 @@ SmallVector<OpFoldResult> AffineDelinearizeIndexOp::getPaddedBasis() {
 }
 
 namespace {
-
 // Drops delinearization indices that correspond to unit-extent basis
 struct DropUnitExtentBasis
     : public OpRewritePattern<affine::AffineDelinearizeIndexOp> {
diff --git a/mlir/test/Dialect/Affine/invalid.mlir b/mlir/test/Dialect/Affine/invalid.mlir
index 87a40e7382b2e..17fa1f0fdfd91 100644
--- a/mlir/test/Dialect/Affine/invalid.mlir
+++ b/mlir/test/Dialect/Affine/invalid.mlir
@@ -61,6 +61,32 @@ func.func @affine_for_upper_bound_invalid_sym() {
 
 // -----
 
+func.func @affine_max_of_invalid_dim(%n: index) {
+  affine.for %tile = 0 to 4 {
+    %one = arith.constant 1 : index
+    %non_affine = arith.addi %tile, %one : index
+    %cut = affine.max affine_map<(d0) -> (3, d0)>(%non_affine)
+    // expected-error at +1 {{operand cannot be used as a dimension id}}
+    affine.for %point = affine_map<(d0) -> (d0)>(%cut) to %n {
+    }
+  }
+  return
+}
+
+// -----
+
+func.func @affine_max_of_dim_is_not_symbol(%n: index) {
+  affine.for %tile = 0 to 4 {
+    %cut = affine.max affine_map<(d0) -> (3, d0 * 4)>(%tile)
+    // expected-error at +1 {{operand cannot be used as a symbol}}
+    affine.for %point = affine_map<()[s0] -> (s0)>()[%cut] to %n {
+    }
+  }
+  return
+}
+
+// -----
+
 #set0 = affine_set<(i)[N] : (i >= 0, N - i >= 0)>
 
 func.func @affine_if_invalid_sym() {
diff --git a/mlir/test/Dialect/Affine/ops.mlir b/mlir/test/Dialect/Affine/ops.mlir
index 54e35b9ad06b4..7ea7510d8ae5e 100644
--- a/mlir/test/Dialect/Affine/ops.mlir
+++ b/mlir/test/Dialect/Affine/ops.mlir
@@ -100,6 +100,23 @@ func.func @affine_max(%arg0 : index, %arg1 : index, %arg2 : index) {
 
 // -----
 
+// CHECK-LABEL: @affine_min_max_dim_bounds
+func.func @affine_min_max_dim_bounds(%n: index) {
+  affine.for %tile = 0 to 4 {
+    // CHECK: %[[LOWER:.*]] = affine.max
+    %lower = affine.max affine_map<(d0) -> (3, d0 * 4)>(%tile)
+    // CHECK: %[[UPPER:.*]] = affine.min
+    %upper = affine.min affine_map<(d0)[s0] -> (d0 * 4 + 4, s0)>(%tile)[%n]
+    // CHECK: affine.for %{{.*}} = #{{.*}}(%[[LOWER]]) to #{{.*}}(%[[UPPER]])
+    affine.for %point = affine_map<(d0) -> (d0)>(%lower)
+                        to affine_map<(d0) -> (d0)>(%upper) {
+    }
+  }
+  return
+}
+
+// -----
+
 func.func @valid_symbols(%arg0: index, %arg1: index, %arg2: index) {
   %c1 = arith.constant 1 : index
   %c0 = arith.constant 0 : index

``````````

</details>


https://github.com/llvm/llvm-project/pull/233411


More information about the Mlir-commits mailing list