[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