排列 AVX 寄存器的内容

Permute content of AVX register

本文关键字:寄存器 AVX 排列      更新时间:2023-10-16

我有一个带有四个双精度值的AVX寄存器。现在我需要对每个元素单独执行一些算术。我需要做的一个例子如下。

Situation:
  a = [a4 a3 a2 a1]
  w = [ 0  0  0 w1]
  x = [ 0  0  0 x1]
  y = [ 0  0  0 y1]
  z = [ 0  0  0 z1]
Desired result:
  w = [-- -- -- w1+a1]
  x = [-- -- -- x1+a2]
  y = [-- -- -- y1+a3]
  z = [-- -- -- z1+a4]

除了期望的结果不仅仅是两个值的总和,而是它们更复杂的算术表达式。我把--放在哪里,我的意思是我不在乎那些价值,这些价值观将被丢弃。

我想出我可以使用排列操作来排列寄存器a(例如,参见使用单个AVX内联函数反转包含双精度的AVX寄存器(。我唯一的问题是这些内部函数需要一个即时的,即编译时值,而我需要动态地执行此操作。

我发现了排列内联函数,它们对其他寄存器(如_mm256_permutevar_pd(中包含的整数进行操作,但它们都没有跨通道排列(例如,使用这些指令首先不可能有a3。使用这些说明执行我想要的操作的唯一方法是使用 if ,我宁愿避免这样做。

我是否应该在受if条件约束的 128 位通道上进行排列,然后在通道内进行动态排列?还是有更好的解决方案?我对性能和可维护性都感兴趣。我最多可以使用AVX2指令。组装是一种选择,但我更喜欢内在。

理想情况下,您可以将[ z y x w ]打包到矢量中后,使用 SIMD 运算执行+所表示的任何操作。 但如果没有:

以正常方式将所有 4 个元素提取到标量double,然后执行任何您想要的操作:

void unpack_256_to_scalar(__m256d a) {
    // unpack to two 128b halves
    __m128d a01 = _mm256_castpd256_pd128(a);  // extractf128_pd(a, 0) should also compile the same way, if you like more-consistent C instead of code that matches the asm you expect
    __m128d a23 = _mm256_extractf128_pd(a, 1);
    // and then halves of each 128b vector
    double a0 = _mm_cvtsd_f64(a01);
    double a1 = _mm_cvtsd_f64(_mm_unpackhi_pd(a01,a01));
    double a2 = _mm_cvtsd_f64(a23);
    double a3 = _mm_cvtsd_f64(_mm_unpackhi_pd(a23,a23));
    ...
    // use the results
}

这(在 Godbolt 编译器资源管理器上(编译为只有 3 条带有 clang 的指令,或者使用 gcc 编译为 4 条指令,因为它在寄存器分配方面很愚蠢:

unpack_256_to_scalar(double __vector(4)):
    vextractf128    xmm1, ymm0, 0x1
    vunpckhpd       xmm2, xmm0, xmm0
    vmovapd xmm3, xmm1                 # gcc should have use vunpckhpd xmm3, xmm1,xmm1.  This wasted mov is a missed-optimization bug.
    vunpckhpd       xmm1, xmm1, xmm1
    # the empty asm statement emitted the empty string here.
    vzeroupper
    ret

三个指令中的每一个都会产生一个不同的元素作为其向量结果的低元素。 不需要常量,甚至不需要即时常量(这就是为什么我选择了 unpackhi_pd 而不是 clang 在从其内部表示数据移动生成随机播放时使用的shufpdvpermilpd

使用需要向量作为控制掩码的变量洗牌在这里是疯狂的。 这似乎不需要任何动态/变量洗牌或提取。

顺便说一句,请参阅 x86 标签 wiki 以获取有关编写高性能代码的一些链接。