Context
Currently in LLVM, vectors do not support TargetExtType as a valid element type. Vectors are meant to support types with constant sizes, and implementations of TargetExtType are by default not guaranteed to have a fixed size. However, the type could be checked for size when doing the vector assertions.
Proposal
The group I am in has modified our fork of LLVM to allow a TargetExtType to be stored in vectors. It seems reasonable to upstream a similar change which allows target types that are sized to be stored in vectors.
I was wondering what people’s thoughts are on this?
I made a very simple PR here to illustrate what I’m talking about:
Previous Conversation and Related Thread
I have heard from some people that it would make more sense for groups to create “container” target types which hold their element target types. This seems counterintuitive to me. It seems like groups would be missing out on functionality that is already provided by vector if they did that, and it seems like almost all the scaffolding to provide vector support for target types already exists.
Could you please provide some more context on what the practical use-case for this is?
This seems like a reasonable thing to allow in principle, but at the same time I wouldn’t expect LLVM’s existing vector support to do anything particularly useful with such a type.
What kind of capabilities would you expect the middle-end to have for such types, and how would you be handling it in the backend?
(An alternative is to use a custom target vector type, rather than an actual vector of target types.)
Thanks for the thoughts! The biggest reason our group uses an actual vector of target is the operations that vector provides. There are useful operations that work on vectors of target type as long as data layout information is provided for that target type. These include things like insertelement, extractelement, and shufflevector.
In the backend, these lower to hardware intrinsics that already work for things like i8. When the target types are just groups of n bits, the same infrastructure can be shared between vectors of integers/floats and the target types. For us, this ends up being more convenient than having to reinvent things for a custom target vector type.
We have a similar use case for AArch64 whereby we’ve recently introduced a target specific scalar type in clang for 8-bit modal floating point instructions to account for its ABI requirements. Ideally we would be able to have vectors of these types but currently use i8 based vectors. This works fine but does open up the potential to use operations that do not make much sense for the underlying type (e.g. integer adds, muls etc, plus the reverse, i.e FP8 operations on actual i8 based data).
By either having vectors of target types, or generic vectors of some fixed size element type that is otherwise opaque, would mean we can better ensure the IR is well formed. Sure, you’d still be able to bitcast the vector but the presence of the bitcast would at least signal something to be aware of with the common usages (e.g. loads, store, shuffles) looking the same as their non-target type equivalents.
Thanks. Being able to use standard insertelement/extractelement/shufflevector ops for vectors of target type does sound valuable.
I don’t really see any problems with allowing vectors of target types. I do think we shouldn’t automatically allow all sized target types inside vectors, similarly to how we currently don’t allow all (non-target) sized types in vectors. Most of our existing target types are not suitable for use in vectors, even if they are sized. We should instead make this a separate opt-in property, similar to HasZeroInit / CanBeGlobal / etc.
I don’t believe we allow bitcasts involving target types, so I’d expect bitcasts of vectors of target types to also not be allowed.