_mm_load_si128 以相反的顺序加载数据

Posted

技术标签:

【中文标题】_mm_load_si128 以相反的顺序加载数据【英文标题】:_mm_load_si128 loads data in reverse order 【发布时间】:2021-03-14 17:31:33 【问题描述】:

我正在编写一个带有 SSE2 内在函数的 C 函数,以本质上比较 4 个 32 位整数并检查哪些大于零,并以 16 位掩码的形式给出该结果。我正在使用以下代码来执行此操作

#include <x86intrin.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>


static void cmp_example(void) 
    const uint32_t byte_vals[] = 0, 5, 0, 3;
    __m128i got_data = _mm_load_si128((__m128i const*)byte_vals);
    __m128i cmp_data = _mm_setzero_si128();
    __m128i result = _mm_cmpgt_epi32 (got_data, cmp_data);
    int mask_result = _mm_movemask_epi8(result);
    printf("Result 0x%x\n", mask_result & 0xFFFF);

但是,当我编译并运行它时,它会打印出 0xf0f0 。我希望结果遵循从内存中加载的相同顺序。为了进一步检查,我添加了一些调试语句,如下所示:

const uint32_t byte_vals[] = 0, 5, 0, 3;
__m128i got_data = _mm_load_si128((__m128i const*)byte_vals);
printf("0x%llx 0x%llx\n", got_data[0], got_data[1]);
__m128i cmp_data = _mm_setzero_si128();
__m128i result = _mm_cmpgt_epi32 (got_data, cmp_data);
printf("0x%llx 0x%llx\n", result[0], result[1]);
int mask_result = _mm_movemask_epi8(result);
printf("Result 0x%x\n", mask_result & 0xFFFF);

此运行打印

0x500000000 0x300000000
0xffffffff00000000 0xffffffff00000000
Result 0xf0f0

因此,这里的罪魁祸首似乎是_mm_load_si128

基于此,如何让_mm_load_si128 以与内存中布局相同的顺序加载数据?

【问题讨论】:

这里并没有真正反转,这就是 little-endian 的工作原理。 另请参阅Convention for displaying vector registers 和print a __m128i variable 以打印为 16 个单独的十六进制字节,如果这是您想要的。还有How does endianness work with SIMD registers? 【参考方案1】:

_mm_load_si128 以小端格式加载数据。字 0 至少在概念上指向 xmm 寄存器中的元素 0。

但是当值被打印为十六进制值时,它们以大端格式打印。 xmm寄存器got_data[0]的第一个int64_t元素包含字节流00 00 00 00 05 00 00 00,即0x(000000)0500000000ull。

根据上下文,必须从左到右或从右到左读取值。掩码的第 0 个半字节 (0x000F) 对应于 result 的第 0 个字。

【讨论】:

以上是关于_mm_load_si128 以相反的顺序加载数据的主要内容,如果未能解决你的问题,请参考以下文章

为什么SSE有128位负载功能?

如何从 16 x 8 位 __m128i 值中提取 32 x 4 位整数

C++ SSE 命令反转寄存器值

vfptr 中的 Visual C++ 方法以相反的顺序

数据库结果以与分配的内联和块相反的顺序显示

oracle状态