我正在移植 SSE SIMD 代码以使用 256 位 AVX 扩展,并且似乎找不到任何可以混合/混洗/移动高 128 位和低 128 位的指令。
背后的故事:
我真正想要的是VHADDPS
/表现_mm256_hadd_ps
得像HADDPS
/ _mm_hadd_ps
,只有 256 位字。不幸的是,它就像两个分别HADDPS
对低位和高位单词进行操作的调用。
使用 VPERM2F128,可以交换低 128 位和高 128 位(以及其他排列)。内在函数用法看起来像
x = _mm256_permute2f128_ps( x , x , 1)
第三个参数是一个控制字,它给用户很大的灵活性。有关详细信息,请参阅英特尔内部指南。
x = _mm256_permute4x64_epi64(x, 0b01'00'11'10);
注意:此指令需要 AVX2(不仅仅是 AVX1)。
正如@PeterCordes 在 Zen2 / Zen3 CPU 上的速度方面所评论的那样, _mm256_permute2x128_si256(x, x, i)是最好的选择,尽管它有 3 个参数,而我建议的函数_mm256_permute4x64_epi64(x, i)有 2 个参数。在 Zen1 和 KNL/KNM(以及 Bulldozer 系列挖掘机)上,我建议的_mm256_permute4x64_epi64(x, i)效率更高。在其他 CPU(包括主流 Intel)上,这两种选择是平等的。
如前所述,两者都_mm256_permute2x128_si256(x, y, i)
需要_mm256_permute4x64_epi64(x, i)
AVX2,而_mm256_permute2f128_si256(x, i)
只需要 AVX1。
我知道这样做的唯一方法是使用_mm256_extractf128_si256
and _mm256_set_m128i
。例如交换 256 位向量的两半:
__m128i v0h = _mm256_extractf128_si256(v0, 0);
__m128i v0l = _mm256_extractf128_si256(v0, 1);
__m256i v1 = _mm256_set_m128i(v0h, v0l);