_mm_store_si128/_mm_storeu_si128存储字节顺序异常的修复咨询
问题
我有一个signed char数组:
const signed char From[] = { 0b00000000, 0b00000001, 0b00000010, 0b00000011, 0b00000100, 0b00000101, 0b00000110, 0b00000111, 0b00001000, 0b00001001, 0b00001010, 0b00001011, 0b00001100, 0b00001101, 0b00001110, 0b00001111, };
需要将数组中的字符存入__m128i向量,再通过_mm_store_si128把向量内容存储到std::uint32_t Schedule[4]数组中。当前实现如下:
const __m128i Chars = _mm_set_epi8 ( From[0], From[1], From[2], From[3], From[4], From[5], From[6], From[7], From[8], From[9], From[10], From[11], From[12], From[13], From[14], From[15] ); _mm_store_si128((__m128i*)&Schedule[Kter], SettedLines4);
但存储后Schedule的字节顺序不符合预期(疑似位或字节错乱),通过自定义的to_binary函数验证了该问题。完整代码如下:
# include <x86intrin.h> # include <iostream> # include <cstdint> template<typename Type> [[ nodiscard ]] std::string to_binary(Type Data) noexcept { std::string Result = ""; std::uint64_t CurrentBit = 8 * sizeof Data; while(CurrentBit--) Result += ((Data >> CurrentBit) & 1) == 0 ? "0" : "1"; return Result; } int main(void) { std::uint32_t Schedule[4]; const signed char From[] = { 0b00000000, 0b00000001, 0b00000010, 0b00000011, 0b00000100, 0b00000101, 0b00000110, 0b00000111, 0b00001000, 0b00001001, 0b00001010, 0b00001011, 0b00001100, 0b00001101, 0b00001110, 0b00001111, }; const __m128i v = _mm_set_epi8 ( From[0], From[1], From[2], From[3], From[4], From[5], From[6], From[7], From[8], From[9], From[10], From[11], From[12], From[13], From[14], From[15] ); _mm_store_si128((__m128i*)&Schedule[0], v); std::cout << to_binary(Schedule[0]) << std::endl; std::cout << to_binary(Schedule[1]) << std::endl; std::cout << to_binary(Schedule[2]) << std::endl; std::cout << to_binary(Schedule[0]) << std::endl; }
请问如何修复该问题,以获得预期的字节顺序?
解决方法
问题根源
_mm_set_epi8的参数逻辑:这个函数的第一个参数对应向量的最高地址字节(128位中的第15个字节,从0开始计数),最后一个参数对应向量的最低地址字节(第0个字节)。你当前把From[0]放在第一个参数位置,会导致它被放到向量的高地址端,和预期顺序完全相反。- 存储映射的字节顺序:
_mm_store_si128按内存地址顺序存储向量字节,结合上面的参数顺序错误,最终Schedule数组的字节顺序会完全颠倒。
修复方式
有两种简洁的修复方案:
方案一:反转_mm_set_epi8的参数顺序
将From数组的元素从最后一个到第一个传入函数,让From[0]对应向量的最低地址字节:
const __m128i v = _mm_set_epi8 ( From[15], From[14], From[13], From[12], From[11], From[10], From[9], From[8], From[7], From[6], From[5], From[4], From[3], From[2], From[1], From[0] );
存储后,Schedule[0]会是0x03020100(二进制00000011000000100000000100000000),Schedule[1]是0x07060504,以此类推,符合预期的字节拼接顺序。
方案二:直接加载数组到向量
如果From数组的内存布局已经是你想要的顺序,用_mm_loadu_si128(或_mm_load_si128,若数组内存对齐)直接加载整个数组,避免手动传参的错误:
const __m128i v = _mm_loadu_si128((const __m128i*)From);
这种方式直接按内存顺序把From的16个字节加载到向量中,存储后Schedule的字节顺序与From完全一致,代码更简洁且不易出错。
验证效果
修复后运行代码,Schedule的输出会符合预期:
Schedule[0]:00000011000000100000000100000000Schedule[1]:00000111000001100000010100000100Schedule[2]:00001011000010100000100100001000Schedule[3]:00001111000011100000110100001100
内容的提问来源于stack exchange,提问作者faust403
相关产品推荐
相关产品推荐

