diff --git a/mlir/lib/Dialect/Utils/StaticValueUtils.cpp b/mlir/lib/Dialect/Utils/StaticValueUtils.cpp index 1cded38c4419e..e6ef0282101d2 100644 --- a/mlir/lib/Dialect/Utils/StaticValueUtils.cpp +++ b/mlir/lib/Dialect/Utils/StaticValueUtils.cpp @@ -181,12 +181,16 @@ bool isEqualConstantIntOrValueArray(ArrayRef 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 getMixedValues(ArrayRef staticValues, ValueRange dynamicValues, MLIRContext *context) { + assert(dynamicValues.size() == static_cast(llvm::count_if( + staticValues, ShapedType::isDynamic)) && + "expected the rank of dynamic values to match the number of " + "values known to be dynamic"); SmallVector res; res.reserve(staticValues.size()); unsigned numDynamic = 0; diff --git a/mlir/lib/Interfaces/ViewLikeInterface.cpp b/mlir/lib/Interfaces/ViewLikeInterface.cpp index 3112da9ef182a..0cddf658cce52 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. + size_t numDynamicDims = + llvm::count_if(op.getStaticSizes(), ShapedType::isDynamic); + if (op.getSizes().size() != numDynamicDims) { + return op->emitError("expected the number of 'sizes' to match the number " + "of dynamic entries in 'static_sizes' (") + << op.getSizes().size() << " vs " << numDynamicDims << ")"; + } + size_t numDynamicStrides = + llvm::count_if(op.getStaticStrides(), ShapedType::isDynamic); + if (op.getStrides().size() != numDynamicStrides) { + return op->emitError("expected the number of 'strides' to match the number " + "of dynamic entries in 'static_strides' (") + << op.getStrides().size() << " vs " << numDynamicStrides << ")"; + } + size_t numDynamicOffsets = + llvm::count_if(op.getStaticOffsets(), ShapedType::isDynamic); + if (op.getOffsets().size() != numDynamicOffsets) { + return op->emitError("expected the number of 'offsets' to match the number " + "of dynamic entries in 'static_offsets' (") + << op.getOffsets().size() << " vs " << numDynamicOffsets << ")"; + } + std::array 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..8b7fc1a3f2ad0 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) { + %0 = memref.alloc() :memref<1xf32> + // expected-error@+1 {{expected the number of 'offsets' to match the number of dynamic entries in 'static_offsets' (0 vs 1)}} + "memref.subview"(%0) <{operandSegmentSizes = array, static_offsets = array, static_sizes = array, static_strides = array}> : (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}}