[Mlir-commits] [mlir] [mlir][vector] Decline in the parsers instead of asserting on bad input (PR #219917)
Alessandro Potenza
llvmlistbot at llvm.org
Mon Aug 31 02:03:14 PDT 2026
https://github.com/alepot55 created https://github.com/llvm/llvm-project/pull/219917
Three custom parsers in the Vector dialect reach a cast or an index that the input does not have to satisfy, so `mlir-opt` aborts while parsing, before any verifier can report the problem.
`vector.outerproduct` builds its result type from dimension 0 of the operands. A 0-d vector has no dimension 0, so `getScalableDims()[0]` runs off the end:
```mlir
vector.outerproduct %a, %b : vector<f32>, vector<f32>
```
```
Assertion `Index < Length && "Invalid index!"' failed.
```
`vector.transfer_read` and `vector.transfer_write` take `permutation_map` out of the attribute dictionary and cast it to `AffineMapAttr` without checking:
```mlir
vector.transfer_read %m[%i], %f {permutation_map = 42 : i64} : memref<4xf32>, vector<4xf32>
```
```
Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
```
`vector.contract` casts the two operand types to `VectorType` on the path that resolves the mask operands:
```mlir
vector.contract {...} %a, %b, %c, %m0, %m1 : f32, f32 into f32
```
```
Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
```
Each one now emits a diagnostic instead.
The `outerproduct` check is deliberately limited to rank 0, which is the only rank the parser itself cannot handle. A higher rank still reaches the verifier, which rejects it with the same wording, and the existing test for that keeps testing the verifier. An earlier version of this patch rejected every rank other than 1 and broke that test, which is how the narrower condition was arrived at.
This is the same family as #133434, which fixed the unchecked `iterator_types` cast in this same `vector.contract` parser in 2025.
## Testing
Verified by execution on `11e915f2b75d`: the three inputs above abort without the patch and produce the diagnostics with it. `mlir/test/Dialect/Vector`, `Conversion/VectorToSCF`, `Conversion/VectorToGPU` and `Conversion/VectorToLLVM` are green, 119 tests. Across `mlir/test/Dialect` and `mlir/test/Conversion`, 1697 of 1707 pass, with 8 failures in `Dialect/LLVMIR` and `Dialect/X86` that are identical on the unpatched baseline and one expected failure.
`clang-format` is clean against the merge base.
Assisted-by: Claude (Anthropic)
AI-assisted, disclosed per the LLVM AI Tool Use Policy.
>From fc54471aa8e8c6a949e10afc1368f9b89747c962 Mon Sep 17 00:00:00 2001
From: Alessandro Potenza <ap.alessandro.potenza at gmail.com>
Date: Sun, 30 Aug 2026 10:02:11 +0200
Subject: [PATCH] [mlir][vector] Decline in the parsers instead of asserting on
bad input
Three custom parsers in the Vector dialect reach a cast or an index that the
input does not have to satisfy, so `mlir-opt` aborts while parsing, before any
verifier can report the problem.
`vector.outerproduct` builds its result type from dimension 0 of the operands.
A 0-d vector has no dimension 0, so `getScalableDims()[0]` runs off the end:
vector.outerproduct %a, %b : vector<f32>, vector<f32>
Assertion `Index < Length && "Invalid index!"' failed.
`vector.transfer_read` and `vector.transfer_write` read `permutation_map` out
of the attribute dictionary and cast it to `AffineMapAttr` without checking:
vector.transfer_read %m[%i], %f {permutation_map = 42 : i64}
: memref<4xf32>, vector<4xf32>
Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
`vector.contract` casts the two operand types to `VectorType` on the path that
resolves the mask operands:
vector.contract {...} %a, %b, %c, %m0, %m1 : f32, f32 into f32
Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
Emit a diagnostic in each case. The `outerproduct` check is deliberately
limited to rank 0, which is the only rank the parser itself cannot handle; a
higher rank still reaches the verifier, which already rejects it with the same
wording, and the existing test for that keeps testing the verifier.
Verified by execution on 11e915f2b75d: the three inputs above abort without the
patch and produce the diagnostics with it. mlir/test/Dialect/Vector,
Conversion/VectorToSCF, Conversion/VectorToGPU and Conversion/VectorToLLVM are
green (119 tests). Across mlir/test/Dialect and mlir/test/Conversion, 1697 of
1707 pass with 8 failures in Dialect/LLVMIR and Dialect/X86 that are identical
on the unpatched baseline.
Assisted-by: Claude (Anthropic)
AI-assisted, disclosed per the LLVM AI Tool Use Policy.
---
mlir/lib/Dialect/Vector/IR/VectorOps.cpp | 32 +++++++++++++++---
mlir/test/Dialect/Vector/invalid.mlir | 42 ++++++++++++++++++++++++
2 files changed, 70 insertions(+), 4 deletions(-)
diff --git a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
index f8f3deb2e4789..f88c40acc553c 100644
--- a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
+++ b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
@@ -963,8 +963,13 @@ ParseResult ContractionOp::parse(OpAsmParser &parser, OperationState &result) {
if (masksInfo.size() != 2)
return parser.emitError(parser.getNameLoc(),
"expected zero or exactly 2 vector mask operands");
- auto lhsType = llvm::cast<VectorType>(types[0]);
- auto rhsType = llvm::cast<VectorType>(types[1]);
+ auto lhsType = llvm::dyn_cast<VectorType>(types[0]);
+ auto rhsType = llvm::dyn_cast<VectorType>(types[1]);
+ if (!lhsType || !rhsType)
+ return parser.emitError(
+ parser.getNameLoc(),
+ "expected vector types for the lhs and rhs operands "
+ "when mask operands are present");
auto maskElementType = parser.getBuilder().getI1Type();
std::array<VectorType, 2> maskTypes = {
VectorType::Builder(lhsType).setElementType(maskElementType),
@@ -4379,6 +4384,15 @@ ParseResult OuterProductOp::parse(OpAsmParser &parser, OperationState &result) {
if (!vLHS)
return parser.emitError(parser.getNameLoc(),
"expected vector type for operand #1");
+ // The result type is built below from dimension 0 of the operands, which a
+ // 0-d vector does not have. Only that case has to be caught here; a higher
+ // rank still reaches the verifier, which rejects it with the same wording.
+ if (vLHS.getRank() == 0)
+ return parser.emitError(parser.getNameLoc(),
+ "expected 1-d vector for operand #1");
+ if (vRHS && vRHS.getRank() == 0)
+ return parser.emitError(parser.getNameLoc(),
+ "expected 1-d vector for operand #2");
VectorType resType;
if (vRHS) {
@@ -5285,7 +5299,12 @@ ParseResult TransferReadOp::parse(OpAsmParser &parser, OperationState &result) {
permMap = getTransferMinorIdentityMap(shapedType, vectorType);
result.attributes.set(permMapAttrName, AffineMapAttr::get(permMap));
} else {
- permMap = llvm::cast<AffineMapAttr>(permMapAttr).getValue();
+ auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(permMapAttr);
+ if (!affineMapAttr)
+ return parser.emitError(parser.getNameLoc(),
+ "expected an affine map attribute for the "
+ "permutation_map attribute");
+ permMap = affineMapAttr.getValue();
}
auto inBoundsAttrName = TransferReadOp::getInBoundsAttrName(result.name);
Attribute inBoundsAttr = result.attributes.get(inBoundsAttrName);
@@ -5775,7 +5794,12 @@ ParseResult TransferWriteOp::parse(OpAsmParser &parser,
permMap = getTransferMinorIdentityMap(shapedType, vectorType);
result.attributes.set(permMapAttrName, AffineMapAttr::get(permMap));
} else {
- permMap = llvm::cast<AffineMapAttr>(permMapAttr).getValue();
+ auto affineMapAttr = llvm::dyn_cast<AffineMapAttr>(permMapAttr);
+ if (!affineMapAttr)
+ return parser.emitError(parser.getNameLoc(),
+ "expected an affine map attribute for the "
+ "permutation_map attribute");
+ permMap = affineMapAttr.getValue();
}
auto inBoundsAttrName = TransferWriteOp::getInBoundsAttrName(result.name);
Attribute inBoundsAttr = result.attributes.get(inBoundsAttrName);
diff --git a/mlir/test/Dialect/Vector/invalid.mlir b/mlir/test/Dialect/Vector/invalid.mlir
index 489f5489030fd..3ac92633ce752 100644
--- a/mlir/test/Dialect/Vector/invalid.mlir
+++ b/mlir/test/Dialect/Vector/invalid.mlir
@@ -251,6 +251,20 @@ func.func @outerproduct_non_vector_operand(%arg0: f32) {
// -----
+func.func @outerproduct_zero_rank_lhs(%arg0: vector<f32>, %arg1: vector<4xf32>) {
+ // expected-error at +1 {{expected 1-d vector for operand #1}}
+ %1 = vector.outerproduct %arg0, %arg1 : vector<f32>, vector<4xf32>
+}
+
+// -----
+
+func.func @outerproduct_zero_rank_rhs(%arg0: vector<4xf32>, %arg1: vector<f32>) {
+ // expected-error at +1 {{expected 1-d vector for operand #2}}
+ %1 = vector.outerproduct %arg0, %arg1 : vector<4xf32>, vector<f32>
+}
+
+// -----
+
func.func @outerproduct_invalid_kind_attr(%arg0 : vector<[4]xf32>, %arg1 : vector<[8]xf32>) {
// expected-error at +1 {{expected 'kind' attribute of type CombiningKind (e.g. 'vector.kind<add>')}}
%0 = vector.outerproduct %arg0, %arg1 {kind = "invalid"} : vector<[4]xf32>, vector<[8]xf32>
@@ -2416,3 +2430,31 @@ func.func @load_negative_stride(%src: memref<100x100xf32, strided<[-100, 1]>>) -
%v = vector.load %src[%c0, %c0] : memref<100x100xf32, strided<[-100, 1]>>, vector<8xf32>
return %v : vector<8xf32>
}
+
+// -----
+
+func.func @transfer_read_permutation_map_not_an_affine_map(%arg0: memref<4xf32>,
+ %i: index, %f: f32) {
+ // expected-error at +1 {{expected an affine map attribute for the permutation_map attribute}}
+ %0 = vector.transfer_read %arg0[%i], %f {permutation_map = 42 : i64} : memref<4xf32>, vector<4xf32>
+}
+
+// -----
+
+func.func @transfer_write_permutation_map_not_an_affine_map(%v: vector<4xf32>,
+ %arg0: memref<4xf32>, %i: index) {
+ // expected-error at +1 {{expected an affine map attribute for the permutation_map attribute}}
+ vector.transfer_write %v, %arg0[%i] {permutation_map = 42 : i64} : vector<4xf32>, memref<4xf32>
+}
+
+// -----
+
+#map0 = affine_map<(d0) -> (d0)>
+#map1 = affine_map<(d0) -> ()>
+func.func @contraction_masked_non_vector_operands(%a: f32, %b: f32, %c: f32,
+ %m0: vector<4xi1>, %m1: vector<4xi1>) {
+ // expected-error at +1 {{expected vector types for the lhs and rhs operands when mask operands are present}}
+ %0 = vector.contract {indexing_maps = [#map0, #map0, #map1],
+ iterator_types = ["reduction"], kind = #vector.kind<add>}
+ %a, %b, %c, %m0, %m1 : f32, f32 into f32
+}
More information about the Mlir-commits
mailing list