[Mlir-commits] [mlir] 147af22 - [MLIR] ValueBoundsOpInterface: slice size from source size (#221756)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sun Oct 4 16:19:21 PDT 2026
Author: Alexey Kreshchuk
Date: 2026-10-04T23:19:10Z
New Revision: 147af22a75535542b0d2755b08174a44512d1b6d
URL: https://github.com/llvm/llvm-project/commit/147af22a75535542b0d2755b08174a44512d1b6d
DIFF: https://github.com/llvm/llvm-project/commit/147af22a75535542b0d2755b08174a44512d1b6d.diff
LOG: [MLIR] ValueBoundsOpInterface: slice size from source size (#221756)
Improve ValueBoundsOpInterface for tensor.extract_slice by adding an
upper bound of `ceil((sourceSize - offset) / stride)`.
Added:
Modified:
mlir/lib/Dialect/Tensor/IR/ValueBoundsOpInterfaceImpl.cpp
mlir/test/Dialect/Tensor/value-bounds-op-interface-impl.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Dialect/Tensor/IR/ValueBoundsOpInterfaceImpl.cpp b/mlir/lib/Dialect/Tensor/IR/ValueBoundsOpInterfaceImpl.cpp
index 684cec2d6748a..56ecccd681aaf 100644
--- a/mlir/lib/Dialect/Tensor/IR/ValueBoundsOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Tensor/IR/ValueBoundsOpInterfaceImpl.cpp
@@ -132,6 +132,27 @@ struct ExtractSliceOpInterface
++ctr;
if (ctr == dim) {
cstr.bound(value)[dim] == extractSliceOp.getMixedSizes()[i];
+ int64_t staticStride = extractSliceOp.getStaticStrides()[i];
+ if (staticStride > 0) {
+ // Force analysis of the size value to get a better bound. Example:
+ // %size = affine.min affine_map<(d0) -> (5, -d0 + 24)>(%iv)
+ // %slice = tensor.extract_slice %source[%iv][%size][1]
+ // : tensor<24xf32> to tensor<?xf32>
+ // Here we get a bound of 24 immediately, so %size is skipped under
+ // the default stop condition unless we force its analysis.
+ if (auto sizeValue =
+ llvm::dyn_cast<Value>(extractSliceOp.getMixedSizes()[i]))
+ cstr.populateConstraints(sizeValue, std::nullopt);
+ // Encode in-bounds slice constraint:
+ OpFoldResult offset = extractSliceOp.getMixedOffsets()[i];
+ AffineExpr offsetExpr = cstr.getExpr(offset);
+ AffineExpr sourceDimExpr =
+ cstr.getExpr(extractSliceOp.getSource(), i);
+ cstr.bound(value)[dim] <=
+ (sourceDimExpr - offsetExpr).ceilDiv(staticStride);
+ cstr.bound(value)[dim] <= sourceDimExpr - offsetExpr;
+ cstr.bound(value)[dim] <= sourceDimExpr;
+ }
return;
}
}
diff --git a/mlir/test/Dialect/Tensor/value-bounds-op-interface-impl.mlir b/mlir/test/Dialect/Tensor/value-bounds-op-interface-impl.mlir
index e957cc39831a7..2af2d917ca341 100644
--- a/mlir/test/Dialect/Tensor/value-bounds-op-interface-impl.mlir
+++ b/mlir/test/Dialect/Tensor/value-bounds-op-interface-impl.mlir
@@ -176,6 +176,85 @@ func.func @extract_slice_rank_reduce(%t: tensor<?x?xf32>, %sz: index) -> index {
// -----
+// An in-bounds extract_slice cannot exceed ceil((src - offset) / stride).
+// Default constant upper bounds are open, so size <= 8 reifies as 9.
+
+// CHECK-LABEL: func @extract_slice_in_bounds_constant_ub(
+// CHECK: %[[c9:.*]] = arith.constant 9 : index
+// CHECK: return %[[c9]]
+func.func @extract_slice_in_bounds_constant_ub(%t: tensor<10xf32>, %sz: index) -> index {
+ %0 = tensor.extract_slice %t[2][%sz][1] : tensor<10xf32> to tensor<?xf32>
+ %1 = "test.reify_bound"(%0) {dim = 0, type = "UB", constant} : (tensor<?xf32>) -> (index)
+ return %1 : index
+}
+
+// -----
+
+func.func @extract_slice_in_bounds_compare(%t: tensor<10xf32>, %sz: index) {
+ %c0 = arith.constant 0 : index
+ %c8 = arith.constant 8 : index
+ %0 = tensor.extract_slice %t[2][%sz][1] : tensor<10xf32> to tensor<?xf32>
+ %d = tensor.dim %0, %c0 : tensor<?xf32>
+ // expected-remark @below{{true}}
+ "test.compare"(%d, %c8) {cmp = "LE"} : (index, index) -> ()
+ return
+}
+
+// -----
+
+// src=10, stride=3 allows indices {0,3,6,9}, so size <= 4 = ceil(10/3).
+// floor(10/3) = 3 would be too tight.
+
+func.func @extract_slice_strided_in_bounds(%t: tensor<10xf32>, %sz: index) {
+ %c0 = arith.constant 0 : index
+ %c3 = arith.constant 3 : index
+ %c4 = arith.constant 4 : index
+ %0 = tensor.extract_slice %t[0][%sz][3] : tensor<10xf32> to tensor<?xf32>
+ %d = tensor.dim %0, %c0 : tensor<?xf32>
+ // expected-remark @below{{true}}
+ "test.compare"(%d, %c4) {cmp = "LE"} : (index, index) -> ()
+ // expected-error @below{{unknown}}
+ "test.compare"(%d, %c3) {cmp = "LE"} : (index, index) -> ()
+ return
+}
+
+// -----
+
+// A dynamic offset is non-negative, so size <= src - 0.
+
+func.func @extract_slice_dynamic_offset_in_bounds(%t: tensor<10xf32>, %off: index, %sz: index) {
+ %c0 = arith.constant 0 : index
+ %c10 = arith.constant 10 : index
+ %0 = tensor.extract_slice %t[%off][%sz][1] : tensor<10xf32> to tensor<?xf32>
+ %d = tensor.dim %0, %c0 : tensor<?xf32>
+ // expected-remark @below{{true}}
+ "test.compare"(%d, %c10) {cmp = "LE"} : (index, index) -> ()
+ return
+}
+
+// -----
+
+func.func @extract_slice_rank_reduce_in_bounds(%t: tensor<8x16xf32>, %sz: index) {
+ %c0 = arith.constant 0 : index
+ %c14 = arith.constant 14 : index
+ %0 = tensor.extract_slice %t[0, 2][1, %sz][1, 1] : tensor<8x16xf32> to tensor<?xf32>
+ %d = tensor.dim %0, %c0 : tensor<?xf32>
+ // expected-remark @below{{true}}
+ "test.compare"(%d, %c14) {cmp = "LE"} : (index, index) -> ()
+ return
+}
+
+// -----
+
+func.func @extract_slice_dynamic_stride_no_constant_ub(%t: tensor<10xf32>, %sz: index, %st: index) -> index {
+ %0 = tensor.extract_slice %t[0][%sz][%st] : tensor<10xf32> to tensor<?xf32>
+ // expected-error @below{{could not reify bound}}
+ %1 = "test.reify_bound"(%0) {dim = 0, type = "UB", constant} : (tensor<?xf32>) -> (index)
+ return %1 : index
+}
+
+// -----
+
// CHECK-LABEL: func @insert(
// CHECK-SAME: %[[t:.*]]: tensor<?xf32>
// CHECK: %[[c0:.*]] = arith.constant 0 : index
More information about the Mlir-commits
mailing list