[Mlir-commits] [mlir] [mlir][vector] fix contraction lowering crash on scalar results after folding a broadcast-like shape_cast (PR #229824)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Oct 28 23:45:59 PDT 2026


Cerulime wrote:

> Wasn't the problem discovered and solution proposed by @Cerulime ? We should make sure that their contribution is attributed accordingly.
> 
> It's not entirely clear to me what is happening here - the reproduce is too complex. Below's a reduced version (I removed one TD Op). It generates invalid IR and that needs to be investigated _first_. Otherwise, we are tweaking other patterns so that they stay correct even when _invalid_ input is fed. We don't do that in MLIR.
> 
> ```mlir
> func.func @contract_scalar_result_unit_dims_lowering(%x: vector<2xbf16>, %scale: bf16, %acc: bf16) -> bf16 {
>   %lhs = vector.shape_cast %x : vector<2xbf16> to vector<1x1x2xbf16>
>   %rhs = vector.broadcast %scale : bf16 to vector<1x1x2xbf16>
>   %out = vector.contract {
>     indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>,
>                      affine_map<(d0, d1, d2) -> (d0, d1, d2)>,
>                      affine_map<(d0, d1, d2) -> ()>],
>     iterator_types = ["reduction", "reduction", "reduction"],
>     kind = #vector.kind<add>
>   } %lhs, %rhs, %acc : vector<1x1x2xbf16>, vector<1x1x2xbf16> into bf16
>   return %out : bf16
> }
> 
> module attributes {transform.with_named_sequence} {
>   transform.named_sequence @__transform_main(%module_op: !transform.any_op {transform.readonly}) {
>     %func = transform.structured.match ops{["func.func"]} in %module_op : (!transform.any_op) -> !transform.any_op
>     transform.apply_patterns to %func {
>       transform.apply_patterns.vector.reduction_to_contract
>     } : !transform.any_op
>     transform.yield
>   }
> }
> ```
> 
> Thanks!

Hi @banach-space ,

Thank you first for looking into this and for looking out for the attribution!

Yes, you point out another problem in this file. I also submit a issue #230084 to describe it. I am not sure should we merge these two issues.

The reduced test case makes the root cause crystal clear:

In CombineContractBroadcastMask (combineContractAndBroadcast), the LHS vector.shape_cast is folded, dropping the leading unit reduction dimensions (d0, d1) from the LHS map ((d0, d1, d2) -> (d2)).
However, the RHS is a scalar broadcast (vector.broadcast %scale : bf16 to vector<1x1x2xbf16>), which combineContractAndBroadcast skips folding because the source is scalar rather than a vector. The RHS map remains (d0, d1, d2) -> (d0, d1, d2).
This creates an asymmetric vector.contract where d0 and d1 are still marked as reduction iterators but only appear on the RHS. In ContractionOp::verify() / verifyOutputShape(), these orphaned reduction dimensions fail to form contracting pairs and are treated as free dimensions, leading to a verification failure because the result is expected to be a vector rather than a scalar.

The crash in ContractionOpLowering::lowerParallel was purely a downstream symptom of this invalid intermediate IR. Other details is in that issue.

Thanks for all contributors. I am glad to help.

https://github.com/llvm/llvm-project/pull/229824


More information about the Mlir-commits mailing list