使用英特尔内在函数 (AVX) 中的混合指令

Dev*_*X10 4 c c++ intrinsics avx immediate-operand

我有一个关于 AVX_mm256_blend_pd功能的问题。

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

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

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

Pet*_*des 6

_mm256_blend_pd是内部函数,vblendpd它将其控制操作数作为立即常量,嵌入到指令的机器代码中。(这就是汇编/机器代码术语中“立即”的含义。)

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

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

对于一般情况来说,没有什么比这更好的了,直到 AVX512 使屏蔽成为您可以作为其他指令的一部分执行的一流操作,并为我们提供单微指令混合指令vblendmpd ymm0{k1}, ymm1, ymm2(根据屏蔽寄存器进行混合)。

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


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