在 intel intrinsics (AVX) 中使用混合指令

Using the blend instructions in intel intrinsics (AVX)

我对 AVX _mm256_blend_pd 函数有疑问。

我想优化我大量使用 _mm256_blendv_pd 函数的代码。不幸的是,这具有相当高的延迟和低吞吐量。此函数将三个 __m256d 变量作为输入,其中最后一个表示用于 select 来自前 2 个变量的掩码。

我找到了另一个函数 (_mm256_blend_pd),它采用位掩码而不是 __m256d 变量作为掩码。当掩码是静态的时,我可以简单地传递类似 0b0111 的东西来从第一个变量中获取第一个元素和第二个变量的最后 3 个元素。然而,在我的例子中,掩码是使用 _mm_cmp_pd 函数计算的,其中 return 是一个 __m256d 变量。我发现我可以使用掩码中的 _mm256_movemask_pd 到 return 一个整数,但是当将它传递给函数 _mm256_blend_pd 时,我得到一个错误 error: the last argument must be a 4-bit immediate.

有没有办法使用它的前 4 位来传递这个整数?或者是否有另一个类似于 movemask 的函数可以让我使用 _mm256_blend_pd?或者我可以使用另一种方法来避免使用 cmp、movemask 和 blend 对这个用例更有效吗?

_mm256_blend_pdvblendpd 的内在函数,它将其控制操作数作为立即数,嵌入到指令的机器代码中。 (这就是 "immediate" 在汇编/机器代码术语中的意思。)

在 C++ 术语中,控制参数必须是 constexpr 以便编译器可以在编译时将其嵌入到指令中。您不能将其用于 运行 时变混合。

不幸的是,像 vblendvpd 这样的可变混合指令速度较慢,但​​它们在 Skylake 上是 "only" 2 微指令,具有 1 或 2 个周期的延迟(取决于您正在测量的输入通过的关键路径)。 (uops.info)。在 Skylake 上,这些 uops 可以在 3 个向量 ALU 端口中的任何一个上 运行。 (不过,在 Haswell/Broadwell 上更糟,仅限于端口 5,与洗牌竞争)。 Zen 甚至可以 运行 它们作为一个 uop。

在 AVX512 将屏蔽作为您可以作为其他指令的一部分执行的第一个 class 操作之前,没有什么比一般情况更好的了,并为我们提供单 uop 混合指令,如 vblendmpd ymm0{k1}, ymm1, ymm2(混合根据屏蔽寄存器)。

在某些特殊情况下,您可以有用地 _mm256_and_pd 有条件地置零而不是混合,例如在 add 之前将输入归零,而不是在之后混合。


TL:DR: _mm256_blend_pd 允许您在控制 编译时常量的特殊情况下使用更快的指令。