将 __m128i 值转换为 std::tuple

Posted

技术标签:

【中文标题】将 __m128i 值转换为 std::tuple【英文标题】:Convert __m128i value into std::tuple 【发布时间】:2017-05-12 12:14:27 【问题描述】:

想象一下,经过一些 SIMD 计算,我得到一个 __m128i 值,其中第四个字段的值为零。是否有一种简单便携的方法可以将其他三个字段转换为std::tuple<int,int,int>,记住它不是standard layout?

【问题讨论】:

“简单”经常与“便携”和/或“符合标准”相冲突。 std::tuple<int, int, int> 不要求具有标准布局。但是,您可能会发现大多数实现产生的内存布局与您预期的一样。如果是这种情况,如果不要求严格遵守标准,您脑海中已有的实现可能会起作用。由于您引用了__m128i,因此您使用的是x86,所以我不考虑int 可能有的任何奇怪的填充/对齐要求; __m128i 的布局与 int[4] 一样。 @JasonR:tuple 的字段顺序未指定...所以 “可能工作” 对 IMO 过于乐观。 @Jason R 实际上,对于 x86 平台上的 SIMD 'm128' _requires 对齐(16) @Jarod42:也许吧。给 OP 的教训可能是不,没有可移植或符合标准的方法来做到这一点。话虽如此,有很多 C++ 代码并不完全符合标准。如果您可以绑定您的一组平台和编译器/库版本,并且您愿意承担未来可能出现的维护难题,那么这可能是可能的。 @Swift:我从事类似的项目。我鼓励您将_mm_load_ps() 更改为_mm_loadu_ps() 进行基准测试。您会发现,在类似的条件下,它们的性能基本上无法区分;您使用的指令的选择并不重要。话虽如此,对齐加载可以更快,因为它们保证不会跨越缓存行或页面边界,但使用哪种类型的指令并不重要。假设未对齐的 128 位内存操作可以简化您的代码结构并放松对输入和输出的约束。 【参考方案1】:

丑陋,但便携。我不相信有快速的解决方案,因为std::tuple 没有定义内存布局。所以只需将这三个值复制到一个元组中。

std::tuple<int, int, int> to_tuple(__m128i& value)

    auto* ptr = reinterpret_cast<int*>(&value);
    return std::make_tuple(ptr[0], ptr[1], ptr[2]);


为什么需要这个?也许您可以通过其他方式解决您的问题。

【讨论】:

这就是我正在做的,尽管使用_mm_storeu_si128 而不是reinterpret_cast,但我认为生成的程序集是相同的。我希望有一个更优雅的解决方案......

以上是关于将 __m128i 值转换为 std::tuple的主要内容,如果未能解决你的问题,请参考以下文章

AVX/SSE 将浮点符号掩码转换为 __m128i

SSE:将 __m128 转换为浮点数

如何使用 SSE 将 _m128i 转换为无符号整数?

将 16 位值的 __m256i 打包(饱和)到 8 位值的 __m128i?

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

将 __m256i 设置为两个 __m128i 值的值