Search code examples
c++sseunions

Is accessing bytes of a __m128 variable via union legal?


Consider this variable declaration:

union {
        struct {
            float x, y, z, padding;
        } components;
        __m128 sse;
    } _data;

My idea is to assign the value through x, y, z fields, perform SSE2 computations and read the result through x, y, z. I have slight doubts as to whether it is legal, though. My concern is alignment: MSDN says that __m128 variables are automatically aligned to 16 byte boundary, and I wonder if my union can break this behavior. Are there any other pitfalls to consider here?


Solution

  • The union's alignment should be fine, but in the case of Windows you may be able to access the 32 bit components directly. From xmmintrin.h (DirectXMath):

    typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128 {
         float               m128_f32[4];
         unsigned __int64    m128_u64[2];
         __int8              m128_i8[16];
         __int16             m128_i16[8];
         __int32             m128_i32[4];
         __int64             m128_i64[2];
         unsigned __int8     m128_u8[16];
         unsigned __int16    m128_u16[8];
         unsigned __int32    m128_u32[4];
     } __m128;
    

    As you can see, there's 4 floats in there. If you want to be uber paranoid, you can probably define all the same alignment specialities and such to make sure nothing will break. As far as I can see, however, and given that you mentioned MSDN in your answer, you should be all good to go. Both the union and accessing it directly should work if you know you have SSE compatible stuff. You can poke around the DirectXMath headers as well to get a feel for how Windows does the definitions and wrangling itself: they define a few macros as well depending on which instrinsics and capabilities are present at compile-time.

    EDIT: As the R.MartinhoFernandes says in the comments, accessing it directly is probably way less of a headache than redefining it in a union.