360 Commits

Author SHA1 Message Date
Yang Bai
b4c31dc98d
[mlir][Vector] add vector.insert canonicalization pattern to convert a chain of insertions to vector.from_elements (#142944)
## Description

This change introduces a new canonicalization pattern for the MLIR
Vector dialect that optimizes chains of insertions. The optimization
identifies when a vector is **completely** initialized through a series
of vector.insert operations and replaces the entire chain with a
single `vector.from_elements` operation.

Please be aware that the new pattern **doesn't** work for poison vectors
where only **some** elements are set, as MLIR doesn't support partial
poison vectors for now.

**New Pattern: InsertChainFullyInitialized**

* Detects chains of vector.insert operations.
* Validates that all insertions are at static positions, and all
intermediate insertions have only one use.
* Ensures the entire vector is **completely** initialized.
* Replaces the entire chain with a
single vector.from_elementts operation.

**Refactored Helper Function**

* Extracted `calculateInsertPosition` from
`foldDenseElementsAttrDestInsertOp` to avoid code duplication.

## Example

```
// Before:
%v1 = vector.insert %c10, %v0[0] : i64 into vector<2xi64>
%v2 = vector.insert %c20, %v1[1] : i64 into vector<2xi64>

// After:
%v2 = vector.from_elements %c10, %c20 : vector<2xi64>
```

It also works for multidimensional vectors.

```
// Before:
%v1 = vector.insert %cv0, %v0[0] : vector<3xi64> into vector<2x3xi64>
%v2 = vector.insert %cv1, %v1[1] : vector<3xi64> into vector<2x3xi64>

// After:
%0:3 = vector.to_elements %arg1 : vector<3xi64>
%1:3 = vector.to_elements %arg2 : vector<3xi64>
%v2 = vector.from_elements %0#0, %0#1, %0#2, %1#0, %1#1, %1#2 : vector<2x3xi64>
```

---------

Co-authored-by: Yang Bai <yangb@nvidia.com>
Co-authored-by: Andrzej Warzyński <andrzej.warzynski@gmail.com>
2025-08-19 13:43:31 +01:00
Matthias Springer
ef2b8805bf
[mlir][vector] Implement InferTypeOpInterface on vector.to_elements (#153172)
Just for convenience. This auto-generates an additional builder that
infers the result type.
2025-08-12 15:15:30 +02:00
Min-Yih Hsu
b4e8b8ee91
[mlir][vector] Canonicalize broadcast of shape_cast (#150523)
Fold `broadcast(shape_cast(x))` into `broadcast(x)` if the type of x is
compatible with broadcast's result type and the shape_cast only adds or removes ones in the leading dimensions.

---------

Co-authored-by: Andrzej Warzyński <andrzej.warzynski@gmail.com>
Co-authored-by: James Newling <james.newling@gmail.com>
2025-08-08 09:25:32 -07:00
James Newling
a96d8aed98
[mlir][vector] vector.splat and vector.broadcast folding/canonicalizing parity (#150284)
This PR ensures parity in folding/canonicalizing of vector.broadcast
(from a scalar) and vector.splat. This means that by using
vector.broadcast instead of vector.splat (which is currently
deprecated), there is no loss in optimizations performed. All tests
which were previously checking folding/canonicalizing of vector.splat
are now done for vector.broadcast. The vector.splat canonicalization
tests are now in a separate file, ready for removal when, in the future,
we remove vector.splat completely.

This PR also adds a canonicalizer to vector.splat to always convert it
to vector.broadcast. This is to reduce the 'traffic' through
vector.splat.

There is a chance that this PR will break downstream users who create/expect 
for vector.splat. Changing all such logic to work just vector.broadcast instead
should fix.
2025-08-01 08:57:38 -07:00
James Newling
0f35244816
[mlir][vector] shape_cast(constant) -> constant fold for non-splats (#145539)
The folder `shape_cast(splat constant) -> splat constant` was first
introduced
[here](36480657d8 (diff-484cea976e0c96459027c951733bf2d22d34c5a0c0de6f577069870ef4588983R2600))
(Nov 2020). In that commit there is a comment to _Only handle splat for
now_. Based on that I assume the intention was to, at a later time,
support a general `shape_cast(constant) -> constant` folder. That is
what this PR does

One minor downside: It is possible with this folder end up with, instead
of 1 large constant and 1 shape_cast, 2 large constants:

```mlir
  func.func @foo() -> (vector<4xi32>, vector<2x2xi32>) {
    %cst = arith.constant dense<[1, 2, 3, 4]> : vector<4xi32> # 'large' constant 1
    %0 = vector.shape_cast %cst : vector<4xi32> to vector<2x2xi32>
    return %cst, %0 : vector<4xi32>, vector<2x2xi32>
  }
```
gets folded with this new folder to 

```mlir
   func.func @foo() -> (vector<4xi32>, vector<2x2xi32>) {
    %cst = arith.constant dense<[1, 2, 3, 4]> : vector<4xi32> # 'large' constant 1
    %cst_0 = arith.constant dense<[[1, 2], [3, 4]]> : vector<2x2xi32> # 'large' constant 2
    return %cst, %cst_0 : vector<4xi32>, vector<2x2xi32>
  }
```
Notes on the above case:
1) This only effects the textual IR, the actual values share the same
context storage (I've verified this by checking pointer values in the
`DenseIntOrFPElementsAttrStorage`
[constructor](da5c442550/mlir/lib/IR/AttributeDetail.h (L59)))
so no compile-time memory overhead to this folding. At the LLVM
IR level the constant is shared, too.
2) This only happens when the pre-folded constant cannot be dead code
eliminated (i.e. when it has 2+ uses) which I don't think is common.
2025-07-31 12:12:53 -07:00
Max191
91e0055c7c
[mlir] Implement inferResultRanges for vector.step op (#151536)
Implements the `inferResultRanges` method from the
`InferIntRangeInterface` interface for `vector.step`. The implementation
is similar to that of arith.constant, since the exact result values are
statically known.

Signed-off-by: Max Dawkins <max.dawkins@gmail.com>
2025-07-31 10:35:26 -07:00
Max191
69751196a9
[mlir] Implement inferResultRanges for vector.transpose (#151537)
Implements the `inferResultRanges` method from the
`InferIntRangeInterface` interface for `vector.transpose`. The result
ranges simply match the source ranges.

Signed-off-by: Max Dawkins <max.dawkins@gmail.com>
2025-07-31 09:32:50 -07:00
Diego Caballero
33465bb2bb
[mlir][Vector] Remove vector.extractelement and vector.insertelement ops (#149603)
This PR removes `vector.extractelement` and `vector.insertelement` ops
from the code base in favor of the `vector.extract` and `vector.insert`
counterparts.

See RFC:
https://discourse.llvm.org/t/rfc-psa-remove-vector-extractelement-and-vector-insertelement-ops-in-favor-of-vector-extract-and-vector-insert-ops
2025-07-28 11:01:14 -07:00
Maksim Levental
fcbcfe44cf
[mlir][NFC] update mlir/Dialect create APIs (32/n) (#150657)
See https://github.com/llvm/llvm-project/pull/147168 for more info.
2025-07-25 13:50:15 -05:00
Longsheng Mou
f047b735e9
[mlir][NFC] Use getDefiningOp<OpTy>() instead of dyn_cast<OpTy>(getDefiningOp()) (#150428)
This PR uses `val.getDefiningOp<OpTy>()` to replace `dyn_cast<OpTy>(val.getDefiningOp())` , `dyn_cast_or_null<OpTy>(val.getDefiningOp())` and `dyn_cast_if_present<OpTy>(val.getDefiningOp())`.
2025-07-25 10:35:51 +08:00
Hideto Ueno
cd1acf2ae3
[mlir][Transforms] Remove UB dialect dependency from Canonicalizer pass (#150555)
The Canonicalizer pass has a dependency to UB dialect which shouldn't have.
It also no longer needs to directly depend on the UB dialect since the Vector dialect
(which uses UB dialect for poison index operations introduced by 35df525) already
declares this dependency(878d3594).
2025-07-24 17:33:07 -07:00
Longsheng Mou
8937b61f21
[mlir][vector] Fix cast incompatible type bug in ShuffleOp::fold (#150037)
This PR uses `dyn_cast` instead of `cast` to avoid a crash when the
constant attribute is not a `DenseElementsAttr`. Fixes #149325.
2025-07-23 11:37:22 +08:00
Maksim Levental
f904cdd6c3
[mlir][NFC] update mlir/Dialect create APIs (24/n) (#149931)
See https://github.com/llvm/llvm-project/pull/147168 for more info.
2025-07-22 08:16:15 -04:00
James Newling
abce4e9ad0
[mlir][vector] Folder: shape_cast(extract) -> extract (#146368)
In a later PR more shape_cast ops will appear. Specifically, broadcasts that 
just prepend ones become shape_cast ops (i.e. volume preserving broadcasts 
are canonicalized to shape_casts). This PR ensures that broadcast-like 
shape_cast ops fold at least as well as broadcast ops.

This is done by modifying patterns that target broadcast ops, to target
'broadcast-like' ops. No new patterns are added, the patterns that exist
are just made to match on shape_casts where appropriate.

This PR also includes minor code simplifications: use
`isBroadcastableTo` to simplify `ExtractOpFromBroadcast` and simplify
how broadcast dims are detected in `foldExtractFromBroadcast`. These are
NFC.

---------

Co-authored-by: Andrzej Warzyński <andrzej.warzynski@gmail.com>
2025-07-21 11:12:50 -07:00
Tomás Longeri
5d367080a8
[MLIR][Vector] Fix bug in ExtractStrideSlicesOp canonicalization (#147591)
The pattern would produce an invalid slice when some dimensions were
both sliced and broadcast.
2025-07-16 08:52:35 +01:00
Kazu Hirata
c06d3a7b72
[mlir] Remove unused includes (NFC) (#148769)
These are identified by misc-include-cleaner.  I've filtered out those
that break builds.  Also, I'm staying away from llvm-config.h,
config.h, and Compiler.h, which likely cause platform- or
compiler-specific build failures.
2025-07-14 22:19:23 -07:00
Kunwar Grover
0227aef688
[mlir][Vector] Add canonicalization for extract_strided_slice(create_mask) (#146745)
extract_strided_slice(create_mask) can be folded into create_mask by
simply subtracting the offsets from the bounds.
2025-07-10 15:43:20 +01:00
lonely eagle
517cda12e5
[mlir][vector] Add foldInsertUseChain folder function to insert op (#147045)
When the result of an insert op is used by an insert op, and the
subsequent insert op is inserted at the same location as the previous
insert op, replaces the dest of the subsequent insert op with the dest
of the previous insert op.This is because the previous insert op does
not affect subsequent insert ops.

---------

Co-authored-by: Mehdi Amini <joker.eph@gmail.com>
Co-authored-by: Andrzej Warzyński <andrzej.warzynski@gmail.com>
2025-07-08 22:39:18 +08:00
Jakub Kuderski
6512ca7ddb
[mlir] Add isStatic* size check for ShapedTypes. NFCI. (#147085)
The motivation is to avoid having to negate `isDynamic*` checks, avoid
double negations, and allow for `ShapedType::isStaticDim` to be used in
ADT functions without having to wrap it in a lambda performing the
negation.

Also add the new functions to C and Python bindings.
2025-07-07 14:57:27 -04:00
Kunwar Grover
5eb195fa90
[mlir][Vector] Fold vector.constant_mask to SplatElementsAttr (#146724)
Adds a folder to vector.constant_mask to fold to SplatElementsAttr when
possible
2025-07-04 14:44:36 +01:00
Yang Bai
393a75ebb7
[mlir][Vector] Add constant folding for vector.from_elements operation (#145849)
### Summary

This PR adds a new folding pattern for **vector.from_elements** that
canonicalizes it to **arith.constant** when all input operands are
constants.

### Implementation Details

**Leverages FoldAdaptor capabilities**: Uses adaptor.getElements() to
access **pre-computed** constant attributes, avoiding redundant pattern
matching on operands.

### Example Transformation
```
Before:
%c0_i32 = arith.constant 0 : i32
%c1_i32 = arith.constant 1 : i32
%c2_i32 = arith.constant 2 : i32
%c3_i32 = arith.constant 3 : i32
%v = vector.from_elements %c0_i32, %c1_i32, %c2_i32, %c3_i32 : vector<2x2xi32>

After:
%v = arith.constant dense<[[0, 1], [2, 3]]> : vector<2x2xi32>
```

---------

Co-authored-by: Yang Bai <yangb@nvidia.com>
2025-06-30 20:39:53 -07:00
Fabian Mora
878d3594ed
[mlir][vector] Avoid setting padding by default to 0 in vector.transfer_read prefer ub.poison (#146088)
Context:
`vector.transfer_read` always requires a padding value. Most of its
builders take no `padding` value and assume the safe value of `0`.
However, this should be a conscious choice by the API user, as it makes
it easy to introduce bugs.
For example, I found several occasions while making this patch that the
padding value was not getting propagated (`vector.transfer_read` was
transformed into another `vector.transfer_read`). These bugs, were
always caused because of constructors that don't require specifying
padding.

Additionally, using `ub.poison` as a possible default value is better,
as it indicates the user "doesn't care" about the actual padding value,
forcing users to specify the actual padding semantics they want.

With that in mind, this patch changes the builders in
`vector.transfer_read` to always having a `std::optional<Value> padding`
argument. This argument is never optional, but for convenience users can
pass `std::nullopt`, padding the transfer read with `ub.poison`.

---------

Signed-off-by: Fabian Mora <fabian.mora-cordero@amd.com>
2025-06-30 15:20:42 -04:00
Andrzej Warzyński
e9e25f02e6
[mlir][vector] Restrict vector.insert/vector.extract to disallow 0-d vectors (#121458)
This patch enforces a restriction in the Vector dialect: the non-indexed
operands of `vector.insert` and `vector.extract` must no longer be 0-D
vectors. In other words, rank-0 vector types like `vector<f32>` are
disallowed as the source or result.

EXAMPLES
--------
The following are now **illegal** (note the use of `vector<f32>`):

```mlir
%0 = vector.insert %v, %dst[0, 0] : vector<f32> into vector<2x2xf32>
%1 = vector.extract %src[0, 0] : vector<f32> from vector<2x2xf32>
```

Instead, use scalars as the source and result types:

```mlir
  %0 = vector.insert %v, %dst[0, 0] : f32 into vector<2x2xf32>
  %1 = vector.extract %src[0, 0] : f32 from vector<2x2xf32>
```

Note, this change serves three goals. These are summarised below.

## 1. REDUCED AMBIGUITY
By enforcing scalar-only semantics when the result (`vector.extract`)
or source (`vector.insert`) are rank-0, we eliminate ambiguity
in interpretation. Prior to this patch, both `f32` and `vector<f32>`
were accepted.

## 2. MATCH IMPLEMENTATION TO DOCUMENTATION
The current behaviour contradicts the documented intent. For example,
`vector.extract` states:

> Degenerates to an element type if n-k is zero.

This patch enforces that intent in code.

## 3. ENSURE SYMMETRY BETWEEN INSERT AND EXTRACT
With the stricter semantics in place, it’s natural and consistent to
make `vector.insert` behave symmetrically to `vector.extract`, i.e.,
degenerate the source type to a scalar when n = 0.

NOTES FOR REVIEWERS
-------------------
1. Main change is in "VectorOps.cpp", where stricter type checks are
   implemented.
2. Test updates in "invalid.mlir" and "ops.mlir" are minor cleanups to
   remove now-illegal examples.
2. Lowering changes in "VectorToSCF.cpp" are the main trade-off: we now
   require an additional `vector.extract` when a preceding
   `vector.transfer_read` generates a rank-0 vector.

RELATED RFC
-----------
*
https://discourse.llvm.org/t/rfc-should-we-restrict-the-usage-of-0-d-vectors-in-the-vector-dialect
2025-06-26 09:47:06 +01:00
Andrzej Warzyński
c92b580d63
[mlir][ArmSME] Remove ConvertIllegalShapeCastOpsToTransposes (#139706)
As a follow-up to PR #135841 (see discussion for background), this patch
removes the `ConvertIllegalShapeCastOpsToTransposes` pattern from the SME
legalization pass. This change unblocks folding for ShapeCastOp involving
scalable vectors.

Originally, the `ConvertIllegalShapeCastOpsToTransposes` pattern was introduced
to rewrite certain `vector.shape_cast` ops that could not be lowered otherwise.
Based on local end-to-end testing, this workaround is no longer required, and
the pattern can now be safely removed.

This patch also removes a special case from `ShapeCastOp::fold`, simplifying
the fold logic.

As a side effect of removing `ConvertIllegalShapeCastOpsToTransposes`, we lose
the mechanism that enabled lowering of certain ops like:

```mlir
%res = vector.transfer_read %mem[%a, %b] (...) :
       memref<?x?xf32>, vector<[4]x1xf32>
```
Previously, such cases were handled by:
* Rewriting a nearby `vector.shape_cast` to a `vector.transpose` (via
  `ConvertIllegalShapeCastOpsToTransposes`)
* Then lowering the result with `LiftIllegalVectorTransposeToMemory`.

This patch introduces a new dedicated pattern,
`LowerColumnTransferReadToLoops`, that directly handles illegal
`vector.transfer_read` ops involving leading scalable dimensions.
2025-06-25 16:40:14 +01:00
Nicolas Vasilache
d31ba52563
[mlir][Interface] Factor out common IndexingMapOpInterface behavior in a new generic interface (#145313)
Refactor the verifiers to make use of the common bits and make
`vector.contract` also use this interface.
In the process, the confusingly named getStaticShape has disappeared.

Note: the verifier for IndexingMapOpInterface is currently called
manually from other verifiers as it was unclear how to avoid it taking
precedence over more meaningful error messages
2025-06-24 07:56:32 +02:00
Nishant Patel
9c1ce31f54
[mlir][vector] Add unroll patterns for vector.load and vector.store (#143420)
This PR adds unroll patterns for vector.load and vector.store. This PR is follow up of #137558
2025-06-20 13:50:25 -07:00
Diego Caballero
ff6367b470
[[mlir][Vector] Add simple folders for vector.from_element/vector.to_elements (#144444)
This PR adds simple folders to remove no-op sequences of
`vector.from_elements` and `vector.to_elements`.
2025-06-20 11:16:46 -07:00
Yang Bai
fe3933da15
[mlir][vector] Support complete folding in single pass for vector.insert/vector.extract (#142124)
### Description

This patch improves the folding efficiency of `vector.insert` and
`vector.extract` operations by not returning early after successfully
converting dynamic indices to static indices.

This PR also renames the test pass `TestConstantFold` to
`TestSingleFold` and adds comprehensive documentation explaining the
single-pass folding behavior.

### Motivation

Since the `OpBuilder::createOrFold` function only calls `fold` **once**,
the current `fold` methods of `vector.insert` and `vector.extract` may
leave the op in a state that can be folded further. For example,
consider the following un-folded IR:
```
%v1 = vector.insert %e1, %v0 [0] : f32 into vector<128xf32>
%c0 = arith.constant 0 : index
%e2 = vector.extract %v1[%c0] : f32 from vector<128xf32>
```
If we use `createOrFold` to create the `vector.extract` op, then the
result will be:
```
%v1 = vector.insert %e1, %v0 [127] : f32 into vector<128xf32>
%e2 = vector.extract %v1[0] : f32 from vector<128xf32>
```
But this is not the optimal result. `createOrFold` should have returned
`%e1`.
The reason is that the execution of fold returns immediately after
`extractInsertFoldConstantOp`, causing subsequent folding logics to be
skipped.

---------

Co-authored-by: Yang Bai <yangb@nvidia.com>
2025-06-18 09:26:04 -07:00
Nicolas Vasilache
e4de74ba11
[mlir][Vector] Tighten up application conditions in TransferReadAfter… (#143869)
…WriteToBroadcast

The pattern would previously apply in spurious cases and generate
incorrect IR.

In the process, we disable the application of this pattern in the case
where there is no broadcast; this should be handled separately and may
more easily support masking.

The case {no-broadcast, yes-transpose} was previously caught by this
pattern and arguably could also generate incorrect IR (and was also
untested): this case does not apply anymore.

The last cast {yes-broadcast, yes-transpose} continues to apply but
should arguably be removed from the future because creating transposes
as part of canonicalization feels dangerous.
There are other patterns that move permutation logic:

- either into the transfer, or
- outside of the transfer

Ideally, this would be target-dependent and not a canonicalization (i.e.
does your DMA HW allow transpose on the fly or not) but this is beyond
the scope of this PR.

Co-authored-by: Nicolas Vasilache <nicolasvasilache@users.noreply.github.com>
2025-06-12 17:11:06 +02:00
Simone Pellegrini
abbbe4a6cd
[mlir][vector] Fix attaching write effects on transfer_write's base (#142940)
This fixes an issue with `TransferWriteOp`'s implementation of the
`MemoryEffectOpInterface` where the write effect was attached to the
stored value rather than the base.

This had the effect that when asking for the memory effects for the
input memref buffer using `getEffectsOnValue(...)`, the function would
return no-effects (as the effect would have been attached to the stored
value rather than the input buffer).
2025-06-11 12:37:34 +01:00
Chao Chen
def37f7e3a
[mlir][vector] add unroll pattern for broadcast (#142011)
This PR adds `UnrollBroadcastPattern` to `VectorUnroll` transform. 
To support this, it also extends `BroadcastOp` definition with
`VectorUnrollOpInterface`
2025-06-05 12:42:16 -05:00
James Newling
543446a353
[mli][vector] canonicalize vector.from_elements from ascending extracts (#139819)
Example:
```mlir
%0 = vector.extract %source[0, 0] : i8 from vector<1x2xi8>
%1 = vector.extract %source[0, 1] : i8 from vector<1x2xi8>
%2 = vector.from_elements %0, %1 : vector<2xi8>
```

becomes
```mlir
%2 = vector.shape_cast %source : vector<1x2xi8> to vector<2xi8>
```

It was decided that we should spill canonicalization tests into new
files (see
[discussion](https://github.com/llvm/llvm-project/pull/135096#pullrequestreview-2760245596))
In view of this I added the new tests to a new file specifically for
canonicalization of from_elements. To be consistent in the location of
the tests, I moved existing tests `extract_scalar_from_from_element`,
`extract_1d_from_from_elements`, `extract_2d_from_from_elements` and
`from_elements_to_splat` from `canonicalize.mlir` to
`canonicalze/vector-from-elements.mlir`. In addition to moving I changed
the LIT variables to all be upper-case for consistency.
2025-06-02 11:15:25 -07:00
Diego Caballero
204eb70af8
[mlir][Vector] Canonicalize empty vector.mask into arith.select (#140976)
This PR adds a missing canonicalization for empty `vector.mask` ops with
a passthru value.

```
   %0 = vector.mask %mask, %passthru { vector.yield %a : vector<8xf32> } :
     vector<8xi1> -> vector<8xf32>

 becomes:

   %0 = arith.select %mask, %a, %passthru : vector<8xf32>
```
2025-05-23 08:29:57 -07:00
Diego Caballero
d6f394e141
[mlir][Vector] Move vector.mask canonicalization to folder (#140324)
This MR moves the canonicalization that elides empty `vector.mask` ops
to folders.
2025-05-21 17:25:01 -07:00
Diego Caballero
fd8bc37b45
[mlir][Vector][NFC] Run extractInsertFoldConstantOp earlier in the folder (#140814)
This PR moves `extractInsertFoldConstantOp` earlier in the folder lists
of `vector.extract` and `vector.insert`. Many folders require having
non-dynamic indices so `extractInsertFoldConstantOp` is a requirement
for them to trigger.
2025-05-21 13:57:01 -07:00
Diego Caballero
6cac792bf9
[mlir][Vector] Improve vector.mask verifier (#139823)
This PR improves the `vector.mask` verifier to make sure it's not
applying masking semantics to operations defined outside of the
`vector.mask` region. Documentation is updated to emphasize that and
make it clearer, even though it already stated that.

As part of this change, the logic that ensures that a terminator is
present in the region mask has been simplified to make it less
surprising to the user when a `vector.yield` is explicitly provided in
the IR.
2025-05-20 15:31:45 -07:00
Diego Caballero
b6dfe4dbfe
[mlir][Vector] Fix vector.mask parser for incorrect passthru cases (#140319)
This MR fixes a crash when parsing an invalid `vector.mask` with a
passtru operand.
2025-05-19 11:20:45 -07:00
Momchil Velikov
38d2306b62
[MLIR] Minor fixes to FoldTransposeBroadcast rewrite (#140083)
This patch contains two minor changes, which I believe were the original
author's intent.

* when folding `transpose(broadcast(x))` emit `broadcast(x)` instead of
`broadcast(broadcast(x))`. The latter causes transient verifier
failures with `mlir-opt --debug` , e.g.
```
mlir-asm-printer: 'func.func' failed to verify and will be printed in generic form
"func.func"() <{function_type = (vector<4x1x1x7xi8>) -> vector<3x2x4x5x6x7xi8>, sym_name = "broadcast_transpose_mixed_example"}> ({
^bb0(%arg0: vector<4x1x1x7xi8>):
  %0 = "vector.broadcast"(%arg0) : (vector<4x1x1x7xi8>) -> vector<2x3x4x5x6x7xi8>
  %1 = "vector.broadcast"(%0) : (vector<2x3x4x5x6x7xi8>) -> vector<3x2x4x5x6x7xi8>
  "func.return"(%1) : (vector<3x2x4x5x6x7xi8>) -> ()
}) : () -> ()
```

* when checking permutation groups the variable `low` was set just once
to zero, thus checking was quadratic. It looks the intent was for `low`
to track the beginning of each dimension groups. (Nevertheless the check
was correct).
2025-05-19 09:45:41 +01:00
James Newling
21f1a616d6
[mlir][vector] Additional transpose folding (#138347)
Fold transpose with unit-dimensions. Seen in the wild:
```
 %0 = vector.transpose %arg, [0, 2, 1, 3] : vector<6x1x1x4xi8> to vector<6x1x1x4xi8>
```

This transpose can be folded because (1) it preserves the shape and (2)
the shuffled dims are unit extent.

Also addresses comment about static vs anonymous namespace:
https://github.com/llvm/llvm-project/pull/135841#discussion_r2071869067

---------

Signed-off-by: James Newling <james.newling@gmail.com>
2025-05-14 14:56:35 -07:00
Andrzej Warzyński
c45cc3e420
[mlir][vector] Standardize base Naming Across Vector Ops (NFC) (#137859)
[mlir][vector] Standardize base Naming Across Vector Ops (NFC)

This change standardizes the naming convention for the argument
representing the value to read from or write to in Vector ops that
interface with Tensors or MemRefs. Specifically, it ensures that all
such ops use the name `base` (i.e., the base address or location to
which offsets are applied).

Updated operations:

* `vector.transfer_read`,
* `vector.transfer_write`.

For reference, these ops already use `base`:

* `vector.load`, `vector.store`, `vector.scatter`, `vector.gather`,
  `vector.expandload`, `vector.compressstore`, `vector.maskedstore`,
  `vector.maskedload`.

This is a non-functional change (NFC) and does not alter the semantics of these
operations. However, it does require users of the XFer ops to switch from
`op.getSource()` to `op.getBase()`.

To ease the transition, this PR temporarily adds a `getSource()` interface
method for compatibility. This is intended for downstream use only and should
not be relied on upstream. The method will be removed prior to the LLVM 21
release.

Implements #131602
2025-05-12 09:44:50 +01:00
Kazu Hirata
921d162460
[mlir] Remove unused local variables (NFC) (#138642) 2025-05-06 07:55:50 -07:00
James Newling
1a44f38d2a
[mlir][vector] Canonicalize/fold 'order preserving' transposes (#135841)
Handles special case where transpose doesn't permute any non-1
dimensions (and so is effectively a shape_cast) and is adjacent to a
shape_cast that it can fold into. For example

```
%1 = vector.transpose %0, [1, 0, 3, 2] : vector<4x1x1x6xf32> to vector<1x4x6x1xf32>
```

can be folded into an adjacent shape_cast. An alternative to this PR
would be to canonicalize such transposes to shape_casts directly, but I
think it'll be difficult getting consensus that shape_cast is 'more
canonical' than transpose, so this PR compromises with the less
opinionated claim that

1) shape_cast is more canonical than shape_cast(transpose)
2) shape_cast is more canonical than transpose(shape_cast)

The pattern `ConvertIllegalShapeCastOpsToTransposes` that is specific to
transposes with scalable dimensions reverses the canonicalization added
here, so I've I've disabled this canonicalization for scalable vectors
2025-05-01 15:50:55 -07:00
James Newling
5718460b22
[mlir][vector] Relax constraints on shape_cast (#136587)
`vector.shape_cast` was initially designed to be the union of
collapse_shape and expand_shape. There was an inconsistency in the
verifier that allowed any shape casts when the rank did not change, which
led to a strange middle ground where you could cast from shape (4,3) to
(3,4) but not from (4,3) to (2,3,2). That issue was fixed (verifier made stricter) 
in https://github.com/llvm/llvm-project/pull/135855, but further feedback
there (and polling) suggests that vector.shape_cast should rather allow all 
shape casts (so more like tensor.reshape than 
tensor.collapse_shape/tensor.expand_shape). This PR makes this simplification
by relaxing the verifier.
2025-05-01 10:18:33 -07:00
Andrzej Warzyński
8c2233b304
[mlir][vector] Update docs + add tests (#137144)
This is a small follow-on for #133721:
* Renamed `getRealVectorRank` as `getEffectiveVectorRankForXferOp` (to
  emphasise that this method was written specifically for transfer Ops).
* Marginally tweaked the description for
  `getEffectiveVectorRankForXferOp` (mostly to highlight the two edge
  cases being covered).
* Added tests for cases when the element type (of the shaped type) is a
  vector.
* Unified the naming (and the order) of arguments in tests with the
  surrounding tests (e.g. `%vec_to_write` -> `%arg1`). Mostly for
  consistency (it would be good to use self-documenting names like
  `%vec_to_write` throughout).
2025-04-25 07:42:21 +01:00
Andrzej Warzyński
ebceb732d5
[mlir][vector] Update the folder for vector.{insert|extract} (#136579)
This is a minor follow-up to #135498. It ensures that operations like
the following are not treated as out-of-bounds accesses and can be
folded correctly (*):

```mlir
  %c_neg_1 = arith.constant -1 : index
  %0 = vector.insert %value_to_store, %dest[%c_neg_1] : vector<5xf32> into vector<4x5xf32>
  %1 = vector.extract %src[%c_neg_1, 0] : f32 from vector<4x5xf32>
```

In addition to adding tests for the case above, this PR also relocates
the tests from #135498 to be alongside existing tests for the
`vector.{insert|extract}` folder, and reformats them to follow:
  * https://mlir.llvm.org/getting_started/TestingGuide/

For example:
  * The "no_fold" prefix is now used to label negative tests.
  * Redundant check lines have been removed (e.g., CHECK: vector.insert
    is sufficient to verify that folding did not occur).

(*) As per https://mlir.llvm.org/docs/Dialects/Vector/#vectorinsert-vectorinsertop,
these are poison values.
2025-04-24 10:43:25 +01:00
Cedric
a68c8e8314
[mlir][vector] Fix parser of vector.transfer_read (#133721)
This PR adds a check in the parser to prevent a crash when
vector.transfer_read fails to create minor identity permutation. map.
Fixes #132851

a.mlir

```
module {
  func.func @test_vector.transfer_read(%arg1: memref<?xindex>) -> vector<3x4xi32> {
    %c3_i32 = arith.constant 3 : i32
    %0 = vector.transfer_read %arg1[%c3_i32, %c3_i32], %c3_i32 : memref<?xindex>, vector<3x4xi32>
    return %0 : vector<3x4xi32>
  }
}
```
2025-04-24 09:21:51 +08:00
Fehr Mathieu
2721f5af12
[mlir][vector] Prevent folding of OOB values in insert/extract (#135498)
Out of bound position values should not be folded in vector.extract and
vector.insert operations, as only in bounds constants and -1 are valid.

Fixes #134516
2025-04-18 05:53:26 +02:00
James Newling
c7fae59ac5
[mlir][vector] Move extract_strided_slice canonicalization to folding (#135676)
Folders are preferred:
https://mlir.llvm.org/docs/Canonicalization/#when-to-use-the-fold-method-vs-rewriterpatterns-for-canonicalizations

Included here : some missing `-----` between lit test file with mlir-opt
with `-split-input-file` flag
2025-04-16 16:20:05 -04:00
James Newling
eea86489dd
[mlir][vector] Fold broadcast(poison) -> poison (#135677)
In addition to the new folder, I've also a test for broadcast(splat) ->
splat which I think was missing

Signed-off-by: James Newling <james.newling@gmail.com>
2025-04-16 13:12:38 -04:00
James Newling
73b8750a97
[mlir][vector] fold transpose(poison) -> poison (#135675)
Following on from https://github.com/llvm/llvm-project/pull/133988

---------

Signed-off-by: James Newling <james.newling@gmail.com>
2025-04-16 13:10:23 -04:00