[Mlir-commits] [mlir] [mlir][Vector] Add `vector.to_elements` op (PR #141457)

Diego Caballero llvmlistbot at llvm.org
Tue May 27 11:27:34 PDT 2025


dcaballe wrote:

Thanks for the feedback! Let me elaborate a more on the value that this op (and also the existing `vector.from_elements`) brings: 

* **Major code size reduction:** `vector.to_elements` leverages MLIR’s op multi-result feature to replace long sequences of `vector.extract` operations with a single `vector.to_elements` op. For instance, imagine extracting all elements from a `vector<1024xf32>`. Instead of generating 1,024 separate `vector.extract` ops, we would only need one `vector.to_elements`. This is a major improvement in code size, impacting any pass that traverses the IR. 

* **Reduced compilation time/transformation complexity**: `vector.to_elements` and `vector.from_elements` streamline transformations and analyses involving large sequences of vector extractions and insertions. `vector.to_elements` and `vector.from_elements` inherently encode the extraction order (no indices!) of all the elements and source vector into one operation. To give you a concrete example, LLVM’s InstCombine spends A LOT of time untangling chains of `extractelement` and `insertelement` instructions to turn them into `shufflevector` instructions. This involves grouping extractions by source vector, analyzing and sorting their indices, and matching them with insertion indices, etc... With `vector.to_elements` and `vector.from_elements`, much of this complexity is gone. For example: 

    * We can determine if a `vector.to_elements` feeding a `vector.from_elements` is redundant by just doing `llvm::equals(toElements.getResults(), fromElements.getOperands())` 
    * We can determine if a `vector.to_elements` feeding a `vector.from_elements` can be turned into a `vector.shuffle` by just checking that all the `vector.from_elements` operands come from the same `vector.to_elements` (this is just a simple case). 


> would that require significant refactoring? Do you anticipate any larger changes stemming from this? 

I don’t anticipate major changes other than replacing loops creating `vector.extract` for every element of a vector with a single `vector.to_elements` (and symmetrical replacement for `vector.from_elements`). 

 

> Basically, I want to make sure we avoid "dangling" ops 😅 - currently, vector.from_elements isn't widely used. 

Yeah, mostly because we needed the symmetrical op that this MR is introducing and implement the corresponding canonicalization patterns and lowering, which should come after this. 

> Is it important that it decomposes into all elements? This op could be really useful for unrolling a dimension if we could do it dimwise. Something like: 
> ```
> %0:16 = vector.to_elements %v : vector<16x4xf32> -> vector<4xf32> 
>```
 
As I mentioned above, it’s important that all the elements are decomposed to offer an implicit and trivial extraction order that doesn’t have to be analyzed. However, I think decomposing into sub-vectors is a natural follow-up that would be very helpful for unrolling, yes! I suggest, though, that we approach this incrementally by first having all the pieces in place for the simple scalar cases before enabling more cases complex cases. Does it sound reasonable? 

 

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


More information about the Mlir-commits mailing list