Introduce memref_vector_cast op, which casts a memref of an elemental type
to a memref of a vector of that elemental type. This only supports
1-d vectorization of the shape and is meant to be used for vectorization
in the common case. Lowering to LLVM included.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Unit Tests
Event Timeline
Was there an RFC for this op? How this connects to https://llvm.discourse.group/t/memref-cast/1514?
Can this be used as a replacement/generalization of https://mlir.llvm.org/docs/Dialects/Vector/#vectortype_cast-vectortypecastop ?
mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp | ||
---|---|---|
2354 | Type conversion may fail, please check the result for null and bail out on errors. | |
2356 | MemRefDescriptor::undef(targetStructType) | |
2365 | Please use MemRefDescriptor API to work with descriptors instead of spreading around the assumptions about the descriptor structure. | |
2381 | I can't seem to find a verifier check that prevents this, so the assert may trigger on valid IR. | |
2384 | This would have been one line using MemRefDescriptor API |
See later in the discussion you are referring to:
https://llvm.discourse.group/t/memref-cast/1514/10
There were multiple requests for having this op contributed - this can be in the future integrated into one of the memref cast ops.
https://llvm.discourse.group/t/understanding-the-vector-abstraction-in-mlir/989/16
https://llvm.discourse.group/t/memref-cast/1514/10
Can this be used as a replacement/generalization of https://mlir.llvm.org/docs/Dialects/Vector/#vectortype_cast-vectortypecastop ?
Yes, this op can subsume such a cast. To start with, I don't think that vector type cast should have ideally been introduced in the vector dialect; my guess is that it was temporary and for local experimentation before it could be subsumed or generalized by something in the standard dialect. Because that's really a cast on memref's - not vectors.
In any case, I expect this memref_vector_cast to potentially be merged into another cast (memref_reinterpret_cast for example) depending on how loaded we want each of the cast ops to be.
Address remaining review comments.
mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp | ||
---|---|---|
2356 | Thanks. |
mlir/include/mlir/Dialect/StandardOps/IR/Ops.td | ||
---|---|---|
1894 | or rank (also not changed) | |
1895 | unless that last dimension is a ? I would add some more explanation on what is allowed in those cases | |
mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp | ||
2342 | this is a pretty big block of memref related manipulations without any comments | |
mlir/lib/Dialect/StandardOps/IR/Ops.cpp | ||
1980 | don't you want to test that the division is exact, i.e. no remainder? |
mlir/include/mlir/Dialect/StandardOps/IR/Ops.td | ||
---|---|---|
1894 | Thanks, updated. It's actually more than that: 'rank' as well as the extents along all but the last dimension remain unchanged the way it is. | |
1895 | Even if the last dimension is dynamic, it's still supported. We divide the dynamic size by the vector width. So it works for both static and dynamic and the lowering already supports it. The second example below has it. |
If it wants to subsume vector.type_cast, how does this interact with n-D vectors for n>1?
There are also implications related to data layout that I don't see how to handle in the general case.
This is the main reason vector.type_cast exists: it caters to a very specific use case.
This revision conveniently omits any discussion about layout which is critical.
How does this all work with non-"powers of 2" vectors?
This functionality makes it very straightforward to develop SIMD code and replicate at a high level the ability to view memory as either scalar or SIMD code with very few restrictions.
My implementation-level concerns have been addressed. Leaving the floor to others for conceptual discussions.
More than 1-d has not really been thought out. I guess I just meant it could subsume what vector type_cast would do 1-d vectors.
There are also implications related to data layout that I don't see how to handle in the general case.
Yes, the implications with layout come in for the case of n > 1. This isn't really meant / designed for that.
This is the main reason vector.type_cast exists: it caters to a very specific use case.
This revision conveniently omits any discussion about layout which is critical.
Are you referring to non-identity layouts for memrefs? This isn't really meant to handle non-identity layouts. I'm not sure what you mean by "discussion" - this isn't a paper or a document to omit or include discussion. This is just implementing the functionality it describes that's really missing and that multiple folks requested for and need. I also see the adjective "conveniently omits" as making absolutely no sense in this context.
How does this all work with non-"powers of 2" vectors?
There is no restriction on the vector width as far as I can see. It's just a floordiv by vector width. Separately and unrelatedly, I'm yet to see hardware with non power of two vectors though. Why should something deal with non power of two vectors to be useful?
mlir/include/mlir/Dialect/StandardOps/IR/Ops.td | ||
---|---|---|
1895 | Yes, I realized that. My comment was indented to ask for proper documentation of that case, since the text and example did not fully agree (it is unclear if ? is at least vector sized for example while reading the text). Sorry if that was not clear. |
mlir/include/mlir/Dialect/StandardOps/IR/Ops.td | ||
---|---|---|
1895 | That's right, whether ? or constant, the last dimension is expected to be vector sized. Let me know if you want me to augment this doc in some other way. |
or rank (also not changed)