AVX2:寻找与_mm256_i32gather_epi32等价的反向存储intrinsics函数
嘿,刚好对SIMD指令集这块比较熟悉,来给你捋一捋:
你提到的这个需求——把AVX2寄存器里的8个32位整数分别存储到数组的指定索引位置,也就是_mm256_i32gather_epi32的反向操作,确实没有原生的AVX2 intrinsics支持。
为什么没有?
早期SIMD指令集的设计更偏向于"向加载和计算倾斜":AVX2只引入了gather类指令(从分散的内存位置加载到寄存器),而scatter类指令(把寄存器元素分散存储到内存指定位置)是直到AVX-512才正式加入的(比如_mm256_i32scatter_epi32这类函数)。这是因为scatter操作对内存子系统的压力更大,硬件实现难度更高,所以被推迟到了更晚的指令集版本。
那AVX2下怎么实现?
如果只能限制在AVX2平台,有几种替代方案:
- 手动逐个提取存储:这是最直接的通用方法,虽然效率不如原生scatter,但胜在兼容性强。用
_mm256_extract_epi32逐个取出寄存器里的元素,再赋值到目标索引:
void avx2_scatter_i32(int* dst, __m256i values, const int* indices) { // AVX2寄存器包含8个32位整数,循环提取每个元素 for (int i = 0; i < 8; ++i) { dst[indices[i]] = _mm256_extract_epi32(values, i); } }
注意:_mm256_extract_epi32的第二个参数是元素在寄存器中的位置(0到7),要和你要存储的索引对应好。
针对特定索引模式优化:如果你的目标索引有规律(比如可以分成连续的几组),可以尝试用
_mm256_shuffle_epi32之类的指令把寄存器元素重新排列成连续块,先批量存储到临时数组,再手动调整到目标位置。不过这种方法通用性差,只适合特定场景。结合SSE指令拆分处理:把256位的YMM寄存器拆成两个128位的XMM寄存器,用
_mm_extract_epi32逐个存储,本质和第一种方法类似,但在部分老CPU上可能有微小的性能差异。
额外提示
如果你的目标平台可以支持AVX-512,那直接使用_mm256_i32scatter_epi32就能完美实现你要的功能,不需要自己造轮子。
内容的提问来源于stack exchange,提问作者obaa5zn5

