使用单个AVX内置函数反转包含双精度浮点数的AVX寄存器

4

如果我有一个包含4个双精度浮点数的AVX寄存器,并且我想将其反转并储存在另一个寄存器中,是否可以使用单个内在命令来完成这个操作?

例如,如果我有一个包含4个浮点数的SSE寄存器,我可以使用:

_mm_shuffle_ps(A,A,_MM_SHUFFLE(0,1,2,3));

我可以使用_mm256_permute2f128_pd()来实现吗?我认为你无法使用上述内部函数来访问每个独立的double。

2个回答

11

实际上您需要使用两次排列来完成此操作:

  • _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

1
值得记住的是,AVX2将添加一个完整的置换功能,即使您今天无法使用它,VPERMPD / _mm256_permute4x64_pd。 英特尔的参考文献有更多细节。 - Stephen Canon
这两个指令的延迟相比之下有什么想法吗? - user1715122
我指的是使用“_mm_shuffle_ps()”反转SSE寄存器和对AVX寄存器进行上述反转操作的延迟。 - user1715122
@user1715122 我不知道。你可以从Agner Fog的表格中计算出来。当然,由于其他因素的影响,实际性能会更加复杂。 - Mysticial

4

支持粒度细于128位的车道交叉洗牌是AVX2中的新功能:

_mm256_permute4x64_pd(vec, _MM_SHUFFLE(0,1,2,3));  // i.e. 0b00011011

VPERMPD ymm1, ymm2/m256, imm8 在英特尔CPU上与其他跨通道洗牌操作(如VPERM2F128)具有相同的吞吐量和延迟。此外,在内部函数查找器中也有相关信息

在AMD Zen1(和Excavator)上,vpermpd比2输入的vperm2f128更快。它们的矢量ALU内部仅为128位;256位矢量指令被解码为至少2个uops,但对于跨越通道的操作需要更多的uops,特别是可以读取任意4个总通道中的一个的操作。(不幸的是,解码器在选择vperm2f128的uops时不仅仅查看即时位)。在Bulldozer家族和Zen1上,手动vextractf128 / vinsertf128vperm2f128更好,但在其他地方会很糟糕。https://uops.info/。我认为vpermpd在Excavator / Zen1上是最佳选择,3个uops vs.至少4个uops来进行通道内反转,然后使用vextracti128 / vinsert128交换两半部分。

有一些CPU支持FMA3但不支持AVX2,例如AMD Piledriver和Steamroller。在英特尔方面,AVX2和FMA都是Haswell时期的新技术。虽然AMD Bulldozer系列已经过时,但仍然存在于家用计算机中,因此即使您的函数利用了AVX1 + FMA,您的选择是要求使用AVX2并让那些少数CPU回退到更糟糕的情况(例如没有FMA的AVX1),或者再制作一个版本的函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接