在 intel 内部函数 (AVX) 中使用混合指令

Posted

技术标签:

【中文标题】在 intel 内部函数 (AVX) 中使用混合指令【英文标题】:Using the blend instructions in intel intrinsics (AVX) 【发布时间】:2020-05-21 02:07:29 【问题描述】:

我对 AVX _mm256_blend_pd 函数有疑问。

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

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

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

【问题讨论】:

【参考方案1】:

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

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

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

在 AVX512 使屏蔽成为您可以作为其他指令的一部分执行的一流操作并为我们提供像 vblendmpd ymm0k1, ymm1, ymm2 这样的单微指令混合指令(根据屏蔽寄存器混合)之前,没有什么比一般情况更好的了。

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


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

【讨论】:

你能用_mm256_permutevar_ps代替blend吗? 哦,我明白了,现在更有意义了。我有点不幸,但非常感谢您的澄清。那我必须坚持使用 blendv。 @anatolyg: vpermilps 确实采用矢量控制操作数,但它是一个只有 1 个数据输入的随机播放。我没有看到任何明显的方法可以与之融合。如果您有什么想法,可以在问题下方的评论中询问 OP。

以上是关于在 intel 内部函数 (AVX) 中使用混合指令的主要内容,如果未能解决你的问题,请参考以下文章

使用 AVX 内部函数进行转换

使用 Intel Core i7 的 AVX 上的非法指令

使用 intel 内在函数将压缩的 8 位整数乘以浮点向量

使用 AVX 与 NaN 的比较

通过使用 AVX 内部函数重写来提高 math.h 函数的性能

我可以正确比较 avx 中的零寄存器吗?