SIMD实现8位转16位解包:AVX2版本出现数据顺序错乱如何解决?
AVX2 字节插零解包异常问题解答
问题根源
异常是AVX2整数指令的128位通道(lane)隔离特性导致的:
- 所有
_mm256_*前缀的整数解包、置换类指令,默认将256位寄存器拆分为低128位、高128位两个独立通道,每个通道单独执行和128位版本指令完全相同的逻辑,不会跨通道操作。 - SSE2版本中的
_mm_unpacklo_epi8会对整个128位寄存器取低8字节和零解包为16字节,但AVX2版本的_mm256_unpacklo_epi8执行逻辑为:- 对低128位通道取低8字节解包为16字节,存入结果的低128位
- 对高128位通道取低8字节解包为16字节,存入结果的高128位
- 因此你加载的32字节原始数据中,低128位的高8字节、高128位的高8字节都会被
_mm256_unpacklo_epi8跳过,最终出现每处理8字节丢失8字节的现象。
正确AVX2实现方案
仅需要对两次unpack得到的结果做一次128位通道重排,即可得到连续的插零解包结果:
__m256i chunk = _mm256_loadu_si256((const __m256i*)src); // 加载32字节原始数据 __m256i zero = _mm256_setzero_si256(); // 解包结果:低128位是0-7字节插零,高128位是16-23字节插零 __m256i lo_unpack = _mm256_unpacklo_epi8(chunk, zero); // 解包结果:低128位是8-15字节插零,高128位是24-31字节插零 __m256i hi_unpack = _mm256_unpackhi_epi8(chunk, zero); // 拼接得到前16个原始字符的插零结果(共32字节) __m256i first_res = _mm256_permute2x128_si256(lo_unpack, hi_unpack, 0x20); _mm256_storeu_si256((__m256i*)dst, first_res); // 拼接得到后16个原始字符的插零结果(共32字节) __m256i second_res = _mm256_permute2x128_si256(lo_unpack, hi_unpack, 0x31); _mm256_storeu_si256((__m256i*)(dst + 32), second_res);
立即数参数说明
_mm256_permute2x128_si256的立即数含义:
0x20:取第一个输入的低128位作为结果低128位,取第二个输入的低128位作为结果高128位0x31:取第一个输入的高128位作为结果低128位,取第二个输入的高128位作为结果高128位
内容的提问来源于stack exchange,提问作者whatisgoingon
相关产品推荐
相关产品推荐

