如果我有一个 AVX 寄存器,其中有 4 个双精度数,并且我想将其反转存储在另一个寄存器中,是否可以使用单个内部命令来执行此操作?
例如:如果我在 SSE 寄存器中有 4 个浮点数,我可以使用:
_mm_shuffle_ps(A,A,_MM_SHUFFLE(0,1,2,3));
我可以这样做_mm256_permute2f128_pd()
吗?我认为您不能使用上述内在函数来解决每个单独的双重问题。
如果我有一个 AVX 寄存器,其中有 4 个双精度数,并且我想将其反转存储在另一个寄存器中,是否可以使用单个内部命令来执行此操作?
例如:如果我在 SSE 寄存器中有 4 个浮点数,我可以使用:
_mm_shuffle_ps(A,A,_MM_SHUFFLE(0,1,2,3));
我可以这样做_mm256_permute2f128_pd()
吗?我认为您不能使用上述内在函数来解决每个单独的双重问题。
您实际上需要 2 个排列来执行此操作:
_mm256_permute2f128_pd()
仅在 128 位块中置换。_mm256_permute_pd()
不会跨 128 位边界置换。所以你需要同时使用:
inline __m256d reverse(__m256d x){
x = _mm256_permute2f128_pd(x,x,1);
x = _mm256_permute_pd(x,5);
return x;
}
测试:
int main(){
__m256d x = _mm256_set_pd(13,12,11,10);
cout << x.m256d_f64[0] << " " << x.m256d_f64[1] << " " << x.m256d_f64[2] << " " << x.m256d_f64[3] << endl;
x = reverse(x);
cout << x.m256d_f64[0] << " " << x.m256d_f64[1] << " " << x.m256d_f64[2] << " " << x.m256d_f64[3] << endl;
}
输出:
10 11 12 13
13 12 11 10
AVX2新增了对粒度更细的 128 位的车道交叉洗牌的支持:
_mm256_permute4x64_pd(vec, _MM_SHUFFLE(0,1,2,3)); // i.e. 0b00011011
VPERMPD ymm1, ymm2/m256, imm8
VPERM2F128
以与英特尔 CPU 上的其他通道交叉洗牌(如 )相同的吞吐量和延迟运行。也在内在函数查找器中。
在 AMD Zen1(和Excavator)上,vpermpd
比 2-input 更快vperm2f128
。它们的向量 ALU 内部只有 128 位宽;256 位向量指令被解码为至少 2 个微指令,但车道交叉操作需要更多,尤其是可以读取 4 个总车道中的任何一个的操作。(不幸的是,解码器在为 vperm2f128 选择 uops 时不仅仅查看直接位)。Manual vextractf128
/vinsertf128
会比vperm2f128
Bulldozer-family 和 Zen1 更好,但在其他任何地方都会很糟糕。https://uops.info/。我认为vpermpd
在 Excavator / Zen1 上是最佳的,3 uops 与至少 4 到车道内倒车,然后用vextracti128
/交换一半vinsert128
。
有一些 CPU 带有 FMA3 而不是 AVX2,例如 AMD Piledriver 和 Steamroller。在 Intel 上,AVX2 和 FMA 都是 Haswell 的新功能。AMD Bulldozer 系列已过时,但仍在家用计算机中,因此即使您的功能利用 AVX1 + FMA,您的选择也是需要 AVX2 并让这少数 CPU 退回到更糟糕的东西(例如,没有 FMA 的 AVX1) ,或制作另一个版本的函数。