-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[mlir] ViewLikeInterface - verify ranks in verifyOffsetSizeAndStrideOp #147926
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-mlir-memref @llvm/pr-subscribers-mlir Author: Maya Amrami (amrami) ChangesgetMixedOffsets() calls getMixedValues() with A verification of this assumption is added to verifyOffsetSizeAndStrideOp() and a clear assert is added in getMixedValues(). Full diff: https://github.com/llvm/llvm-project/pull/147926.diff 3 Files Affected:
diff --git a/mlir/lib/Dialect/Utils/StaticValueUtils.cpp b/mlir/lib/Dialect/Utils/StaticValueUtils.cpp
index 1cded38c4419e..af494b99cb4cb 100644
--- a/mlir/lib/Dialect/Utils/StaticValueUtils.cpp
+++ b/mlir/lib/Dialect/Utils/StaticValueUtils.cpp
@@ -181,12 +181,16 @@ bool isEqualConstantIntOrValueArray(ArrayRef<OpFoldResult> ofrs1,
return true;
}
-/// Return a vector of OpFoldResults with the same size a staticValues, but all
+/// Return a vector of OpFoldResults with the same size as staticValues, but all
/// elements for which ShapedType::isDynamic is true, will be replaced by
/// dynamicValues.
SmallVector<OpFoldResult> getMixedValues(ArrayRef<int64_t> staticValues,
ValueRange dynamicValues,
MLIRContext *context) {
+ assert(llvm::count_if(staticValues, ShapedType::isDynamic) ==
+ dynamicValues.size() &&
+ "expected the rank of dynamic values to match the number of"
+ " values known to be dynamic";);
SmallVector<OpFoldResult> res;
res.reserve(staticValues.size());
unsigned numDynamic = 0;
diff --git a/mlir/lib/Interfaces/ViewLikeInterface.cpp b/mlir/lib/Interfaces/ViewLikeInterface.cpp
index 3112da9ef182a..677d7dcc1b135 100644
--- a/mlir/lib/Interfaces/ViewLikeInterface.cpp
+++ b/mlir/lib/Interfaces/ViewLikeInterface.cpp
@@ -94,6 +94,32 @@ SliceBoundsVerificationResult mlir::verifyInBoundsSlice(
LogicalResult
mlir::detail::verifyOffsetSizeAndStrideOp(OffsetSizeAndStrideOpInterface op) {
+ // A dynamic size is represented as ShapedType::kDynamic in `static_sizes`.
+ // Its corresponding Value appears in `sizes`. Thus, the number of dynamic
+ // dimensions in `static_sizes` must equal the rank of `sizes`.
+ // The same applies to strides and offsets.
+ unsigned int numDynamicDims =
+ llvm::count_if(op.getStaticSizes(), ShapedType::isDynamic);
+ if (numDynamicDims != op.getSizes().size()) {
+ return op->emitError("expected sizes rank to match the number of dynamic "
+ "dimensions (")
+ << numDynamicDims << " vs " << op.getSizes().size() << ")";
+ }
+ unsigned int numDynamicStrides =
+ llvm::count_if(op.getStaticStrides(), ShapedType::isDynamic);
+ if (numDynamicStrides != op.getStrides().size()) {
+ return op->emitError("expected strides rank to match the number of dynamic "
+ "dimensions (")
+ << numDynamicStrides << " vs " << op.getStrides().size() << ")";
+ }
+ unsigned int numDynamicOffsets =
+ llvm::count_if(op.getStaticOffsets(), ShapedType::isDynamic);
+ if (numDynamicOffsets != op.getOffsets().size()) {
+ return op->emitError("expected offsets rank to match the number of dynamic "
+ "dimensions (")
+ << numDynamicOffsets << " vs " << op.getOffsets().size() << ")";
+ }
+
std::array<unsigned, 3> maxRanks = op.getArrayAttrMaxRanks();
// Offsets can come in 2 flavors:
// 1. Either single entry (when maxRanks == 1).
diff --git a/mlir/test/Dialect/MemRef/invalid.mlir b/mlir/test/Dialect/MemRef/invalid.mlir
index 704cdaf838f45..43d0362b78e1d 100644
--- a/mlir/test/Dialect/MemRef/invalid.mlir
+++ b/mlir/test/Dialect/MemRef/invalid.mlir
@@ -658,6 +658,18 @@ func.func @invalid_subview(%arg0 : index, %arg1 : index, %arg2 : index) {
// -----
+// This test is not written in the op's assembly format, to reproduce a mismatch
+// between the rank of static_offsets and the number of Values sent as the
+// dynamic offsets.
+func.func @invalid_subview(%arg0 : memref<?x128xi8, 1>) {
+ %0 = memref.alloc() :memref<1xf32>
+ // expected-error@+1 {{expected offsets rank to match the number of dynamic dimensions (1 vs 0)}}
+ "memref.subview"(%0) <{operandSegmentSizes = array<i32: 1, 0, 0, 0>, static_offsets = array<i64: -9223372036854775808>, static_sizes = array<i64: 1>, static_strides = array<i64: 1>}> : (memref<1xf32>) -> memref<1xf32, strided<[1], offset: ?>>
+ return
+}
+
+// -----
+
func.func @invalid_subview(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = memref.alloc() : memref<8x16x4xf32>
// expected-error@+1 {{expected mixed sizes rank to match mixed strides rank (3 vs 2) so the rank of the result type is well-formed}}
|
27248ee
to
6568205
Compare
getMixedOffsets() calls getMixedValues() with `static_offsets` and `offsets`. It is assumed that the number of dynamic offsets in `static_offsets` equals the rank of `offsets`. Otherwise, we fail on assert when trying to access an array out of its bounds. The same applies to getMixedStrides() and getMixedOffsets(). A verification of this assumption is added to verifyOffsetSizeAndStrideOp() and a clear assert is added in getMixedValues().
6568205
to
41481df
Compare
/// elements for which ShapedType::isDynamic is true, will be replaced by | ||
/// dynamicValues. | ||
SmallVector<OpFoldResult> getMixedValues(ArrayRef<int64_t> staticValues, | ||
ValueRange dynamicValues, | ||
MLIRContext *context) { | ||
assert(dynamicValues.size() == | ||
(unsigned)llvm::count_if(staticValues, ShapedType::isDynamic) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use C++ style static_cast and size_t.
unsigned int numDynamicDims = | ||
llvm::count_if(op.getStaticSizes(), ShapedType::isDynamic); | ||
if (op.getSizes().size() != numDynamicDims) { | ||
return op->emitError("expected sizes rank to match the number of dynamic " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I wouldn't use the term "rank" because users may think of the rank of the source
e.g.:
expected the number of 'sizes' to match the number of dynamic entries in 'static_sizes'
unsigned int numDynamicStrides = | ||
llvm::count_if(op.getStaticStrides(), ShapedType::isDynamic); | ||
if (op.getStrides().size() != numDynamicStrides) { | ||
return op->emitError("expected strides rank to match the number of dynamic " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
unsigned int numDynamicOffsets = | ||
llvm::count_if(op.getStaticOffsets(), ShapedType::isDynamic); | ||
if (op.getOffsets().size() != numDynamicOffsets) { | ||
return op->emitError("expected offsets rank to match the number of dynamic " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
// Its corresponding Value appears in `sizes`. Thus, the number of dynamic | ||
// dimensions in `static_sizes` must equal the rank of `sizes`. | ||
// The same applies to strides and offsets. | ||
unsigned int numDynamicDims = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto
or size_t
?
getMixedOffsets() calls getMixedValues() with
static_offsets
andoffsets
. It is assumed that the number of dynamic offsets instatic_offsets
equals the rank ofoffsets
. Otherwise, we fail on assert when trying to access an array out of its bounds.The same applies to getMixedStrides() and getMixedOffsets().
A verification of this assumption is added to verifyOffsetSizeAndStrideOp() and a clear assert is added in getMixedValues().