使用 SIMD 将 8 位解包到 16 位:AVX2 版本混淆了顺序

Unpacking 8 to 16-bit using SIMD: AVX2 version mixes up the order

我正在尝试使用 SSE2 解压缩带零的文本,并将其扩展到 AVX2。这就是我的意思:

假设您有这样的文本:abcd

我正在尝试使用 SSE2 将 abcd 解压为 a[=16=]b[=16=]c[=16=]d[=17=] 是零。这当然适用于 16 个字符而不是 4 个。

我能够使用此代码(忽略 C 样式转换)做到这一点:

__m128i chunk = _mm_loadu_si128((__m128i const*) src); // Load 16 bytes from memory

__m128i half = _mm_unpacklo_epi8(chunk, _mm_setzero_si128()); // Unpack lower 8 bytes with zeros
_mm_storeu_si128((__m128i*) dst, half); // Write to destination

half = _mm_unpackhi_epi8(chunk, _mm_setzero_si128()); // Unpack higher 8 bytes with zeros
_mm_storeu_si128((__m128i*) (dst + 16), half); // Write to destination

效果很好,但我正在尝试将代码转换为 AVX2,因此我可以一次处理 32 个字节。但是,我在解压缩低字节时遇到了问题。

这是我用于 AVX2 的代码:

__m256i chunk = _mm256_loadu_si256((__m256i const*) src); // Load 32 bytes from memory

__m256i half = _mm256_unpacklo_epi8(chunk, _mm256_setzero_si256()); // Unpack lower 16 bytes with zeros
_mm256_storeu_si256((__m256i*) dst, half); // Write to destination

half = _mm256_unpackhi_epi8(chunk, _mm256_setzero_si256()); // Unpack higher 16 bytes with zeros
_mm256_storeu_si256((__m256i*) (dst + 32), half); // Write to destination

问题是,_mm256_unpacklo_epi8 指令似乎每转换 8 个字节就跳过 8 个字节。例如这个文本(末尾的“fr”是有意的):

Permission is hereby granted, fr

转换为

Permissireby graon is hented, fr

每 8 个字节 _mm256_unpacklo_epi8,进程,跳过 8 个字节。

我在这里做错了什么? 任何帮助将不胜感激。

据我所知,@PeterCordes 已收到正确答案。不过我想用小辅助函数来补充它:

template <int part> inline __m256i Cvt8uTo16u(__m256i a)
{
    return _mm256_cvtepu8_epi16(_mm256_extractf128_si256(a, part));
}