Question Details

No question body available.

Tags

c gcc clang simd type-punning

Answers (2)

Accepted Answer Available
Accepted Answer
May 27, 2026 Score: 4 Rep: 381,119 Quality: Expert Completeness: 100%

With the same type as the vector elements, yes I think so, but I haven't seen any actual GCC or Clang documentation that it's true (both for pointing a vector-pointer at an array of scalars, and the reverse). I think GCC at least, and presumably also Clang, treat a vector-float type as being composed of actual float objects, since they're defined with a typedef that uses float as the base type. If that's true, that's what makes it safe to point a float into a simd_float4.

With a different element type, like int32_t into a vector of long long (e.g. m256i), definitely not: GCC AVX m256i cast to int array leads to wrong values is an example of actual breakage from that.

In the few times I've played around with it (instead of storing to a tmp array or manually using shuffles to set up for a free cast to scalar for the low element), I've never seen breakage with same-type pointers. And it would make sense that compiler devs think about vectors this way, and program their compilers to work that way. Otherwise you'd always need memcpy or a load intrinsic to load a GNU C native vector from an array. (Or looping over the scalar elements of the vector with the [] operator, but I don't think that's the intended use. They seem rather under-documented, though.)

Casting a vector object to a same-size vector with different element types just reinterprets the bits. I think that's the intended way to e.g. load int32_t bit-patterns into a vector of floats, or load from a char[] buffer.


If you typedef float aliasing_v4f attribute((vector_size (16),may_alias)); (like Intel m128) you can point it at anything (including int32_t or int64_t arrays), but you still can't point other scalar pointers into it, you'd need an aliasing_i32 typedef to get a bit-pattern as an int. The pointer type needs to have may_alias, it doesn't matter if the type being pointed-to has it or not1.

You can also define vectors with less alignment, so dereffing such a vector-pointer will compile to an unaligned-load instruction. e.g. typedef float v4f_u attribute((vector_size(16),aligned(1),may_alias)); You can point this at anything with any alignment to load 16 bytes of data. The Apple header you're quoting calls that simd_packed_float4, with "packed" meaning "unaligned", like how attribute((packed)) on a struct can lead to unaligned members. I don't know if they're using aligned(1) or aligned(4), but the comments say it's less aligned than the default 16. (Clang allows implicit conversion between vector types; GCC might need a (simd_float4)deref cast to not warn about it.)

I don't know much about Clang's extvectortype(4); I don't think it gives any different semantics than GCC's vectorsize(16), except that it counts in elements instead of bytes.


Footnote 1: In anonymous dynamically-allocated memory where the only accesses are via pointer, one of them can be a non-aliasing type, as long as all others are mayalias types via typedef or being char*. Then as far as the abstract machine is concerned, the objects there are the type without the mayalias, and the others are aliasing that.

Related:

May 27, 2026 Score: -1 Rep: 790,739 Quality: Low Completeness: 40%

The C standard requires that alignments be a power of 2. See Why alignment is power of 2?. Therefore, it should always be safe to cast a pointer to a more finely aligned pointer type.

Technically, using the resulting pointer as you do may still invoke UB due to the strict aliasing rule. But since we're dealing with a language extension when using this type, we may be able to assume it will "do the expected thing" (I was going to say "right thing", but I'm sure someone would have gotten pedantic about this).