通过联合合法访问 __m128 变量的字节吗?

Posted

技术标签:

【中文标题】通过联合合法访问 __m128 变量的字节吗?【英文标题】:Is accessing bytes of a __m128 variable via union legal? 【发布时间】:2013-02-23 20:14:16 【问题描述】:

考虑这个变量声明:

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

我的想法是通过xyz字段分配值,执行SSE2计算并通过xyz读取结果。不过,我有点怀疑它是否合法。我担心的是对齐:MSDN 说__m128 变量自动对齐到 16 字节边界,我想知道我的联合是否可以打破这种行为。 这里还有其他需要考虑的陷阱吗?

【问题讨论】:

不,对齐不是问题。工会将拥有其所有成员正常工作所需的任何对齐方式。 还要注意,至少在Visual Studio上,你可以通过sse.m128_f32[0]sse.m128_f32[1]sse.m128_f32[2]sse.m128_f32[3]获取__m128 sse;的组件,所以不需要这个把戏。 @R.MartinhoFernandes 和 gcc? 对于 gcc,您可以做更简单的操作:sse[0]sse[1] 等,尽管最高 4.7 只能在 C 中使用,而您需要 g++-4.8 才能在 C++ 中获得它。使用联合,对齐和别名会很好,但代码质量会很差,最好使用((float*)&sse)[1] 附带说明,SSE 数据类型不应该以这种方式访问​​。因此,这样做通常会导致显着的性能损失。仅在打包/解包数据并且对打包数据有很多工作要做时才这样做。 【参考方案1】:

联合的对齐应该没问题,但在 Windows 的情况下,您可能能够直接访问 32 位组件。来自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;

如您所见,里面有 4 个花车。如果您想成为超级偏执狂,您可能可以定义所有相同的对齐特性等,以确保不会破坏任何东西。但是,据我所知,鉴于您在回答中提到了 MSDN,您应该一切顺利。如果你知道你有 SSE 兼容的东西,联合和直接访问它都应该工作。您还可以查看 DirectXMath 标头,以了解 Windows 如何进行定义和自行处理:它们还定义了一些宏,具体取决于编译时存在的内在函数和功能。

编辑:正如 R.MartinhoFernandes 在 cmets 中所说,直接访问它可能比在联合中重新定义它更容易。

【讨论】:

我想保持我的代码跨平台,因此联合技巧。 @VioletGiraffe 那么联合应该没问题。 GCC 也应该尊重工会,也不要做任何时髦的事情,但我不是 GCC 专家,我相信一些标准律师会出现并谴责我们俩使用union

以上是关于通过联合合法访问 __m128 变量的字节吗?的主要内容,如果未能解决你的问题,请参考以下文章

清除 __m128i 的高字节

如何将 16 字节的内存加载到 Rust __m128i 中?

使用 AVX/AVX2/SSE __m128i 将所有负数字节设置为 -128 (0x80) 并保留所有其他字节

从 __m128i 中查找最小值/最大值

计算两个 _m128i SIMD 向量之间的匹配字节数

从四个 __m128i 变量的 64 个高位或低位初始化 __m256i