[RFC][Vector][Standard] Add Bitcast operation

I would like to propose adding a bitcast operation to the Vector dialect. The semantic would match LLVM bitcast operation. This allows casting vectors like in this example:
bitcast … vector<4xi8> to vector<1xi32>

This would be useful for cases where we don’t want to bitcast the memref (for instance SPIR-V doesn’t allow pointer cast) but we want to be able to load/store data with a larger type and break it up.

This op could go either in Vector dialect or in Standard dialect if we want to also allow bitcast between scalars of same sizes.

FYI: @aartbik

1 Like

I can see value in such a reinterpreting cast for other SIMD idioms as well like shuffling in zeros/sign-bits and reinterpreting the results as a vector with shorter length but wider elements. Of course, we should also start thinking about proper type conversion ops, which preserve the vector length while changing the element types.

It is hard to keep track of what is already there and still in flight. The vector dialect currently has the vector.type_cast (and slightly related also shape_cast, reshape, and transfer_read/write with the recent ability to reinterpreted the memref type you added in revision D85244), and the standard dialect has std.memref_cast (and memref_vector_cast proposed in revision D85885 with more proposals still in RFCs).

I am in favor of adding more capabilities to the vector dialect, as long as we make sure all ops are made as simple as possible, but no simpler… :grinning:

I agree :neutral_face:. Casts on memref like vector.type_cast, std.memref_cast, memref_vector_cast have a different use and being able to cast the value itself sounds useful. This is very close to shape_cast operation. I’m not sure if we need to look at unifying some of those operations at some point?

What I’m thinking right now is adding vector.bitcast allowing the lowest dimension to be combined with the type without allowing any other dimension to be changed.


We stumbled upon this RFC since we were looking for a bitcast op. Thanks for adding the vector.bitcast op! However, we found that there isn’t a conversion pattern for it to convert it LLVM (or we couldn’t find it). Does it happen by any chance that you have somewhere internally? Do you plan to upstream it?

I’m also wondering if we should have this op in the Standard dialect so that we can use it on scalar types as well. WDYT?


Hey Diego,

Unfortunately I haven’t implement the convert to LLVM, I was looking at cases targeting SPIR-V (which doesn’t go through LLVM) and in my case the op could generally be canonicalized away. So I never got to the point where I needed this conversion.

I would assume it is straightforward to implement as the semantic should match exactly to llvm bitcast op but I can help out if needed.

Yes, that’s something I was wondering at the time. I’m not sure what direction the standard dialect is taking at this point so it seemed easier to add it to the vector dialect. I think we could allow to do vector -> scalar and scalar->vector while leaving it in the vector dialect, there are definitely other ops doing that (like broadcast op). It might look odd if we allow scalar to scalar, is this what you were thinking about?

I would assume it is straightforward to implement

Yeah, I already have it locally. I’ll contribute it. Thanks!

It might look odd if we allow scalar to scalar, is this what you were thinking about?

Exactly! That was my point. Scalar scenarios won’t fit the vector dialect and someone looking for a scalar bitcast might not even think about the vector dialect at all. I see ‘bitcast’ more like any other operation in the standar dialect that can have scalar or vector inputs/results. I think broadcast makes more sense to me to have it in the vector dialect since it always returns a vector. No strong opinion, though. I’ll leave it up to you :slight_smile:

I’m currently looking for

bitcast … vector<4xi64> to vector<8xi32>

for a compression algorithm.

Having the ability would be appreciated with whatever semantics you think is best.


Hey @rana! We already have this op in the Vector dialect. We recently introduced the lowering to LLVM: rGcf5c517c05e0. Is that enough for you use case?

1 Like

Hi @dcaballe! Thanks for responding!

Would ConvertOpToLLVMPattern<vector::BitCastOp> allow bitcast … vector<4xi64> to vector<8xi32>? It looks like we’re in the same area, but I’m not sure.

I see that you also added @bitcast_f32_to_i32_vector(%input: vector<16xf32>) -> vector<16xi32>.

Would we need a @bitcast_i64_to_i32_vector(%input: vector<4xi64>) -> vector<8xi32>?

Or is that covered by ConvertOpToLLVMPattern?

Yes, it should be supported as long as the input and output types are 1-D vectors. You can quickly run the following example:

  func @test(%arg0: vector<4xi64>) -> vector<8xi32> {
    %0 = vector.bitcast %arg0 : vector<4xi64> to vector<8xi32>
    return %0 : vector<8xi32>

Output (mlir-opt test.mlir -lower-vector-to-llvm):

  func @test(%arg0: vector<4xi64>) -> vector<8xi32> {
    %0 = llvm.bitcast %arg0 : vector<4xi64> to vector<8xi32>
    return %0 : vector<8xi32>

Feel free to create a patch with more test cases if you think they are meaningful not covered by the existing ones!