[Mlir-commits] [mlir] [mlir][Interfaces] Allow integer types for `ValueBoundsOpInterface` (PR #196082)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed May 6 07:14:38 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-linalg
Author: Matthias Springer (matthias-springer)
<details>
<summary>Changes</summary>
Allow integer-typed SSA values in the `ValueBoundsConstraintSet` infrastructure. This feature is opt-in only. The implementation assumes that integer computation cannot overflow.
A new `ValueBoundsOptions` struct is added. Public entry points now take this struct instead of the `closedUB` flag. The flag was moved to the options struct, along with the `allowIntegerType` flag.
Note for LLVM integration: Pass `ValueBoundsOptions` instead of `bool closedUB`.
Assisted-by: gpt-5.5-extra-high
---
Patch is 47.62 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/196082.diff
20 Files Affected:
- (modified) mlir/include/mlir/Dialect/Affine/Transforms/Transforms.h (+6-6)
- (modified) mlir/include/mlir/Dialect/Arith/Transforms/Transforms.h (+6-6)
- (modified) mlir/include/mlir/Dialect/Vector/IR/ScalableValueBoundsConstraintSet.h (+5-4)
- (modified) mlir/include/mlir/Interfaces/ValueBoundsOpInterface.h (+35-14)
- (modified) mlir/lib/Dialect/Affine/Transforms/ReifyValueBounds.cpp (+15-8)
- (modified) mlir/lib/Dialect/Arith/Transforms/ReifyValueBounds.cpp (+31-15)
- (modified) mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp (+1-1)
- (modified) mlir/lib/Dialect/Linalg/Transforms/Hoisting.cpp (+2-1)
- (modified) mlir/lib/Dialect/Linalg/Transforms/Padding.cpp (+1-1)
- (modified) mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp (+1-1)
- (modified) mlir/lib/Dialect/Linalg/Transforms/TilingInterfaceImpl.cpp (+3-2)
- (modified) mlir/lib/Dialect/MemRef/Transforms/IndependenceTransforms.cpp (+1-1)
- (modified) mlir/lib/Dialect/Tensor/Transforms/IndependenceTransforms.cpp (+1-2)
- (modified) mlir/lib/Dialect/Vector/IR/ScalableValueBoundsConstraintSet.cpp (+4-4)
- (modified) mlir/lib/Interfaces/ValueBoundsOpInterface.cpp (+44-29)
- (modified) mlir/test/Dialect/Affine/invalid-reify-bound-dim.mlir (+1-1)
- (modified) mlir/test/Dialect/Arith/value-bounds-op-interface-impl.mlir (+41)
- (modified) mlir/test/lib/Dialect/Affine/TestReifyValueBounds.cpp (+17-7)
- (modified) mlir/test/lib/Dialect/Test/TestOpDefs.cpp (+12-3)
- (modified) mlir/test/lib/Dialect/Test/TestOps.td (+2-1)
``````````diff
diff --git a/mlir/include/mlir/Dialect/Affine/Transforms/Transforms.h b/mlir/include/mlir/Dialect/Affine/Transforms/Transforms.h
index 84adb8e6a1e6d..f8f6d4f5928b0 100644
--- a/mlir/include/mlir/Dialect/Affine/Transforms/Transforms.h
+++ b/mlir/include/mlir/Dialect/Affine/Transforms/Transforms.h
@@ -80,19 +80,19 @@ FailureOr<AffineApplyOp> decompose(RewriterBase &rewriter, AffineApplyOp op);
/// `stopCondition` is met.
///
/// By default, lower/equal bounds are closed and upper bounds are open. If
-/// `closedUB` is set to "true", upper bounds are also closed.
+/// `options.closedUB` is set to "true", upper bounds are also closed.
FailureOr<OpFoldResult>
reifyValueBound(OpBuilder &b, Location loc, presburger::BoundType type,
const ValueBoundsConstraintSet::Variable &var,
ValueBoundsConstraintSet::StopConditionFn stopCondition,
- bool closedUB = false);
+ ValueBoundsOptions options = {});
/// Reify a bound for the given index-typed value in terms of SSA values for
/// which `stopCondition` is met. If no stop condition is specified, reify in
/// terms of the operands of the owner op.
///
/// By default, lower/equal bounds are closed and upper bounds are open. If
-/// `closedUB` is set to "true", upper bounds are also closed.
+/// `options.closedUB` is set to "true", upper bounds are also closed.
///
/// Example:
/// %0 = arith.addi %a, %b : index
@@ -107,19 +107,19 @@ reifyValueBound(OpBuilder &b, Location loc, presburger::BoundType type,
FailureOr<OpFoldResult> reifyIndexValueBound(
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
ValueBoundsConstraintSet::StopConditionFn stopCondition = nullptr,
- bool closedUB = false);
+ ValueBoundsOptions options = {});
/// Reify a bound for the specified dimension of the given shaped value in terms
/// of SSA values for which `stopCondition` is met. If no stop condition is
/// specified, reify in terms of the operands of the owner op.
///
/// By default, lower/equal bounds are closed and upper bounds are open. If
-/// `closedUB` is set to "true", upper bounds are also closed.
+/// `options.closedUB` is set to "true", upper bounds are also closed.
FailureOr<OpFoldResult> reifyShapedValueDimBound(
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
int64_t dim,
ValueBoundsConstraintSet::StopConditionFn stopCondition = nullptr,
- bool closedUB = false);
+ ValueBoundsOptions options = {});
/// Materialize an already computed bound with Affine dialect ops.
///
diff --git a/mlir/include/mlir/Dialect/Arith/Transforms/Transforms.h b/mlir/include/mlir/Dialect/Arith/Transforms/Transforms.h
index ffd367ef11abc..c079bb9aea6e1 100644
--- a/mlir/include/mlir/Dialect/Arith/Transforms/Transforms.h
+++ b/mlir/include/mlir/Dialect/Arith/Transforms/Transforms.h
@@ -27,19 +27,19 @@ namespace arith {
/// `stopCondition` is met.
///
/// By default, lower/equal bounds are closed and upper bounds are open. If
-/// `closedUB` is set to "true", upper bounds are also closed.
+/// `options.closedUB` is set to "true", upper bounds are also closed.
FailureOr<OpFoldResult>
reifyValueBound(OpBuilder &b, Location loc, presburger::BoundType type,
const ValueBoundsConstraintSet::Variable &var,
ValueBoundsConstraintSet::StopConditionFn stopCondition,
- bool closedUB = false);
+ ValueBoundsOptions options = {});
/// Reify a bound for the given index-typed value in terms of SSA values for
/// which `stopCondition` is met. If no stop condition is specified, reify in
/// terms of the operands of the owner op.
///
/// By default, lower/equal bounds are closed and upper bounds are open. If
-/// `closedUB` is set to "true", upper bounds are also closed.
+/// `options.closedUB` is set to "true", upper bounds are also closed.
///
/// Example:
/// %0 = arith.addi %a, %b : index
@@ -54,19 +54,19 @@ reifyValueBound(OpBuilder &b, Location loc, presburger::BoundType type,
FailureOr<OpFoldResult> reifyIndexValueBound(
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
const ValueBoundsConstraintSet::StopConditionFn &stopCondition = nullptr,
- bool closedUB = false);
+ ValueBoundsOptions options = {});
/// Reify a bound for the specified dimension of the given shaped value in terms
/// of SSA values for which `stopCondition` is met. If no stop condition is
/// specified, reify in terms of the operands of the owner op.
///
/// By default, lower/equal bounds are closed and upper bounds are open. If
-/// `closedUB` is set to "true", upper bounds are also closed.
+/// `options.closedUB` is set to "true", upper bounds are also closed.
FailureOr<OpFoldResult> reifyShapedValueDimBound(
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
int64_t dim,
const ValueBoundsConstraintSet::StopConditionFn &stopCondition = nullptr,
- bool closedUB = false);
+ ValueBoundsOptions options = {});
} // namespace arith
} // namespace mlir
diff --git a/mlir/include/mlir/Dialect/Vector/IR/ScalableValueBoundsConstraintSet.h b/mlir/include/mlir/Dialect/Vector/IR/ScalableValueBoundsConstraintSet.h
index 216b94fc445c7..3a03eef8808b6 100644
--- a/mlir/include/mlir/Dialect/Vector/IR/ScalableValueBoundsConstraintSet.h
+++ b/mlir/include/mlir/Dialect/Vector/IR/ScalableValueBoundsConstraintSet.h
@@ -32,10 +32,10 @@ struct ScalableValueBoundsConstraintSet
ScalableValueBoundsConstraintSet(
MLIRContext *context,
ValueBoundsConstraintSet::StopConditionFn stopCondition,
- unsigned vscaleMin, unsigned vscaleMax)
- : RTTIExtends(context, stopCondition,
+ unsigned vscaleMin, unsigned vscaleMax, ValueBoundsOptions options = {})
+ : RTTIExtends(context, stopCondition, options,
/*addConservativeSemiAffineBounds=*/true),
- vscaleMin(vscaleMin), vscaleMax(vscaleMax) {};
+ vscaleMin(vscaleMin), vscaleMax(vscaleMax){};
using RTTIExtends::bound;
using RTTIExtends::StopConditionFn;
@@ -71,7 +71,8 @@ struct ScalableValueBoundsConstraintSet
static FailureOr<ConstantOrScalableBound>
computeScalableBound(Value value, std::optional<int64_t> dim,
unsigned vscaleMin, unsigned vscaleMax,
- presburger::BoundType boundType, bool closedUB = true,
+ presburger::BoundType boundType,
+ ValueBoundsOptions options = {/*closedUB=*/true},
const StopConditionFn &stopCondition = nullptr);
/// Get the value of vscale. Returns `nullptr` vscale as not been encountered.
diff --git a/mlir/include/mlir/Interfaces/ValueBoundsOpInterface.h b/mlir/include/mlir/Interfaces/ValueBoundsOpInterface.h
index 0590cadca8f9e..434f786c161d8 100644
--- a/mlir/include/mlir/Interfaces/ValueBoundsOpInterface.h
+++ b/mlir/include/mlir/Interfaces/ValueBoundsOpInterface.h
@@ -52,9 +52,22 @@ class HyperrectangularSlice {
// Profiled: 488K calls, avg=1.5+-0.5. N=2 covers >90% of cases inline.
using ValueDimList = SmallVector<std::pair<Value, std::optional<int64_t>>, 2>;
+/// Options that control value bound computation.
+struct ValueBoundsOptions {
+ /// By default, lower/equal bounds are closed and upper bounds are open. If
+ /// `closedUB` is set to "true", upper bounds are also closed.
+ bool closedUB = false;
+
+ /// If set to "true", integer-typed SSA values are treated like index-typed
+ /// SSA values. The value bounds infrastructure assumes that such integer
+ /// computations do not overflow. If set to "false", integer-typed SSA values
+ /// are rejected.
+ bool allowIntegerType = false;
+};
+
/// A helper class to be used with `ValueBoundsOpInterface`. This class stores a
-/// constraint system and mapping of constrained variables to index-typed
-/// values or dimension sizes of shaped values.
+/// constraint system and mapping of constrained variables to index-typed values
+/// or dimension sizes of shaped values.
///
/// Interface implementations of `ValueBoundsOpInterface` use `addBounds` to
/// insert constraints about their results and/or region block arguments into
@@ -176,19 +189,21 @@ class ValueBoundsConstraintSet
/// `ValueBoundsOpInterface` for each visited value.
///
/// By default, lower/equal bounds are closed and upper bounds are open. If
- /// `closedUB` is set to "true", upper bounds are also closed.
+ /// `options.closedUB` is set to "true", upper bounds are also closed.
static LogicalResult
computeBound(AffineMap &resultMap, ValueDimList &mapOperands,
presburger::BoundType type, const Variable &var,
- StopConditionFn stopCondition, bool closedUB = false);
+ StopConditionFn stopCondition, ValueBoundsOptions options = {});
/// Compute a bound in terms of the values/dimensions in `dependencies`. The
/// computed bound consists of only constant terms and dependent values (or
/// dimension sizes thereof).
- static LogicalResult
- computeDependentBound(AffineMap &resultMap, ValueDimList &mapOperands,
- presburger::BoundType type, const Variable &var,
- ValueDimList dependencies, bool closedUB = false);
+ static LogicalResult computeDependentBound(AffineMap &resultMap,
+ ValueDimList &mapOperands,
+ presburger::BoundType type,
+ const Variable &var,
+ ValueDimList dependencies,
+ ValueBoundsOptions options = {});
/// Compute a bound in that is independent of all values in `independencies`.
///
@@ -198,10 +213,12 @@ class ValueBoundsConstraintSet
/// must be made independent of loop induction variables (in the case of "for"
/// loops). Loop induction variables are the independencies; they may not
/// appear in the computed bound.
- static LogicalResult
- computeIndependentBound(AffineMap &resultMap, ValueDimList &mapOperands,
- presburger::BoundType type, const Variable &var,
- ValueRange independencies, bool closedUB = false);
+ static LogicalResult computeIndependentBound(AffineMap &resultMap,
+ ValueDimList &mapOperands,
+ presburger::BoundType type,
+ const Variable &var,
+ ValueRange independencies,
+ ValueBoundsOptions options = {});
/// Compute a constant bound for the given variable.
///
@@ -216,11 +233,11 @@ class ValueBoundsConstraintSet
/// computed.
///
/// By default, lower/equal bounds are closed and upper bounds are open. If
- /// `closedUB` is set to "true", upper bounds are also closed.
+ /// `options.closedUB` is set to "true", upper bounds are also closed.
static FailureOr<int64_t>
computeConstantBound(presburger::BoundType type, const Variable &var,
const StopConditionFn &stopCondition = nullptr,
- bool closedUB = false);
+ ValueBoundsOptions options = {});
/// Compute a constant delta between the given two values. Return "failure"
/// if a constant delta could not be determined.
@@ -330,6 +347,7 @@ class ValueBoundsConstraintSet
ValueBoundsConstraintSet(MLIRContext *ctx,
const StopConditionFn &stopCondition,
+ ValueBoundsOptions options = {},
bool addConservativeSemiAffineBounds = false);
/// Return "true" if, based on the current state of the constraint system,
@@ -435,6 +453,9 @@ class ValueBoundsConstraintSet
/// The current stop condition function.
StopConditionFn stopCondition = nullptr;
+ /// Options that control value bound computation.
+ ValueBoundsOptions options;
+
/// Should conservative bounds be added for semi-affine expressions.
bool addConservativeSemiAffineBounds = false;
};
diff --git a/mlir/lib/Dialect/Affine/Transforms/ReifyValueBounds.cpp b/mlir/lib/Dialect/Affine/Transforms/ReifyValueBounds.cpp
index 9537d3e75c26a..1bd068d6151c6 100644
--- a/mlir/lib/Dialect/Affine/Transforms/ReifyValueBounds.cpp
+++ b/mlir/lib/Dialect/Affine/Transforms/ReifyValueBounds.cpp
@@ -9,6 +9,7 @@
#include "mlir/Dialect/Affine/Transforms/Transforms.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Interfaces/ValueBoundsOpInterface.h"
@@ -19,12 +20,13 @@ using namespace mlir::affine;
FailureOr<OpFoldResult> mlir::affine::reifyValueBound(
OpBuilder &b, Location loc, presburger::BoundType type,
const ValueBoundsConstraintSet::Variable &var,
- ValueBoundsConstraintSet::StopConditionFn stopCondition, bool closedUB) {
+ ValueBoundsConstraintSet::StopConditionFn stopCondition,
+ ValueBoundsOptions options) {
// Compute bound.
AffineMap boundMap;
ValueDimList mapOperands;
if (failed(ValueBoundsConstraintSet::computeBound(
- boundMap, mapOperands, type, var, stopCondition, closedUB)))
+ boundMap, mapOperands, type, var, stopCondition, options)))
return failure();
// Reify bound.
@@ -41,8 +43,12 @@ OpFoldResult affine::materializeComputedBound(
std::optional<int64_t> dim = valueDim.second;
if (!dim.has_value()) {
- // This is an index-typed value.
- assert(value.getType().isIndex() && "expected index type");
+ // This is an index-typed/integer-typed value.
+ assert(
+ (value.getType().isIndex() || value.getType().isSignlessInteger()) &&
+ "expected index or signless integer type");
+ if (value.getType().isSignlessInteger())
+ value = arith::IndexCastOp::create(b, loc, b.getIndexType(), value);
operands.push_back(value);
continue;
}
@@ -82,7 +88,7 @@ OpFoldResult affine::materializeComputedBound(
FailureOr<OpFoldResult> mlir::affine::reifyShapedValueDimBound(
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
int64_t dim, ValueBoundsConstraintSet::StopConditionFn stopCondition,
- bool closedUB) {
+ ValueBoundsOptions options) {
auto reifyToOperands = [&](Value v, std::optional<int64_t> d,
ValueBoundsConstraintSet &cstr) {
// We are trying to reify a bound for `value` in terms of the owning op's
@@ -94,17 +100,18 @@ FailureOr<OpFoldResult> mlir::affine::reifyShapedValueDimBound(
};
return reifyValueBound(b, loc, type, {value, dim},
stopCondition ? stopCondition : reifyToOperands,
- closedUB);
+ options);
}
FailureOr<OpFoldResult> mlir::affine::reifyIndexValueBound(
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
- ValueBoundsConstraintSet::StopConditionFn stopCondition, bool closedUB) {
+ ValueBoundsConstraintSet::StopConditionFn stopCondition,
+ ValueBoundsOptions options) {
auto reifyToOperands = [&](Value v, std::optional<int64_t> d,
ValueBoundsConstraintSet &cstr) {
return v != value;
};
return reifyValueBound(b, loc, type, value,
stopCondition ? stopCondition : reifyToOperands,
- closedUB);
+ options);
}
diff --git a/mlir/lib/Dialect/Arith/Transforms/ReifyValueBounds.cpp b/mlir/lib/Dialect/Arith/Transforms/ReifyValueBounds.cpp
index 127563c8f4967..6f02575767e8e 100644
--- a/mlir/lib/Dialect/Arith/Transforms/ReifyValueBounds.cpp
+++ b/mlir/lib/Dialect/Arith/Transforms/ReifyValueBounds.cpp
@@ -18,6 +18,18 @@
using namespace mlir;
using namespace mlir::arith;
+static bool isIndexLikeType(Type type, ValueBoundsOptions options) {
+ return type.isIndex() || (options.allowIntegerType && type.isInteger());
+}
+
+static Value castToIndexValue(OpBuilder &b, Location loc, Value value) {
+ if (value.getType().isIndex())
+ return value;
+ assert(value.getType().isSignlessInteger() &&
+ "expected index or signless integer type");
+ return IndexCastOp::create(b, loc, b.getIndexType(), value);
+}
+
/// Build Arith IR for the given affine map and its operands.
static Value buildArithValue(OpBuilder &b, Location loc, AffineMap map,
ValueRange operands) {
@@ -28,10 +40,12 @@ static Value buildArithValue(OpBuilder &b, Location loc, AffineMap map,
return ConstantIndexOp::create(b, loc,
cast<AffineConstantExpr>(e).getValue());
case AffineExprKind::DimId:
- return operands[cast<AffineDimExpr>(e).getPosition()];
+ return castToIndexValue(b, loc,
+ operands[cast<AffineDimExpr>(e).getPosition()]);
case AffineExprKind::SymbolId:
- return operands[cast<AffineSymbolExpr>(e).getPosition() +
- map.getNumDims()];
+ return castToIndexValue(
+ b, loc,
+ operands[cast<AffineSymbolExpr>(e).getPosition() + map.getNumDims()]);
case AffineExprKind::Add: {
auto binaryExpr = cast<AffineBinaryOpExpr>(e);
return AddIOp::create(b, loc, buildExpr(binaryExpr.getLHS()),
@@ -66,13 +80,13 @@ static Value buildArithValue(OpBuilder &b, Location loc, AffineMap map,
FailureOr<OpFoldResult> mlir::arith::reifyValueBound(
OpBuilder &b, Location loc, presburger::BoundType type,
const ValueBoundsConstraintSet::Variable &var,
- ValueBoundsConstraintSet::StopConditionFn stopCondition, bool closedUB) {
+ ValueBoundsConstraintSet::StopConditionFn stopCondition,
+ ValueBoundsOptions options) {
// Compute bound.
AffineMap boundMap;
ValueDimList mapOperands;
if (failed(ValueBoundsConstraintSet::computeBound(
- boundMap, mapOperands, type, var, std::move(stopCondition),
- closedUB)))
+ boundMap, mapOperands, type, var, std::move(stopCondition), options)))
return failure();
// Materialize tensor.dim/memref.dim ops.
@@ -82,8 +96,9 @@ FailureOr<OpFoldResult> mlir::arith::reifyValueBound(
std::optional<int64_t> dim = valueDim.second;
if (!dim.has_value()) {
- // This is an index-typed value.
- assert(value.getType().isIndex() && "expected index type");
+ // This is an index-typed/integer-typed value.
+ assert(isIndexLikeType(value.getType(), options) &&
+ "expected index or integer type");
operands.push_back(value);
continue;
}
@@ -109,10 +124,11 @@ FailureOr<OpFoldResult> mlir::arith::reifyValueBound(
}
// No arith ops are needed if the bound is a single SSA value.
if (auto expr = dyn_cast<AffineDimExpr>(boundMap.getResult(0)))
- return static_cast<OpFoldResult>(operands[expr.getPosition()]);
- if (auto expr = dyn_cast<AffineSymbolExpr>(boundMap.getResult(0)))
return static_cast<OpFoldResult>(
- operands[expr.getPosition() + boundMap.getNumDims()]);
+ castToIndexValue(b, loc, operands[expr.getPosition()]));
+ if (auto expr = dyn_cast<AffineSymbolExpr>(boundMap.getResult(0)))
+ return static_cast<OpFoldResult>(castToIndexValue(
+ b, loc, operands[expr.getPosition() + boundMap.getNumDims()]));
// General case: build Arith ops.
return static_cast<OpFoldResult>(buildArithValue(b, loc, boundMap, operands));
}
@@ -120,7 +136,7 @@ FailureOr<OpFoldResult> mlir::arith::reifyValueBound(
FailureOr<OpFoldResult> mlir::arith::reifyShapedValueDimBound(
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
int64_t dim, const ValueBoundsConstraintSet::StopConditionFn &stopCondition,
- bool closedUB) {
+ ValueBoundsOptions options) {
auto reifyToOperands = [&](Value v, std::optional<int64_t> d,
ValueBoundsConstraintSet &cstr) {
// We are trying to reify a bound for `value` in terms of the owning op's
@@ -132,18 +148,18 @@ FailureOr<OpFoldResult> mlir::arith::reifyShapedValueDimBound(
};
return reifyValueBound(b, loc, type, ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/196082
More information about the Mlir-commits
mailing list