c++ - 从 avx/sse 掩码到 avx512 掩码的 "correct"方法是什么?

标签 c++ sse avx avx512

我有一些现有的 avx/sse 掩码,是我用旧方法得到的:

auto mask_sse = _mm_cmplt_ps(a, b);
auto mask_avx = _mm_cmp_ps(a, b, 17);

在某些情况下,当将旧的 avx 代码与新的 avx512 代码混合时,我想将这些旧样式的掩码转换为新的 avx512 __mmask4__mmask8 类型。

我试过这个:

auto mask_avx512 = _mm_cmp_ps_mask(sse_mask, _mm_setzero_ps(), 25/*nge unordered quiet*/);

它似乎适用于比较的普通旧输出,但我不认为它会正确捕获可能与 sse4.1 _mm_blendv_ps 一起使用的正 NAN。

还有很好的旧_mm_movemask_ps,但看起来它把掩码一直放在通用寄存器中,我需要用 _cvtu32_mask8 链接它> 将其拉回专用掩码寄存器之一。

是否有更简洁的方法直接将符号位从旧式掩码中拉出到 k 个寄存器之一?

示例代码:

这是一个按照我上面提到的第一种方式进行掩码转换的示例程序

#include "x86intrin.h"
#include <cassert>
#include <cstdio>

int main()
{
    auto a = _mm_set_ps(-1, 0, 1, 2);
    auto c = _mm_set_ps(3, 4, 5, 6);

    auto sse_mask    = _mm_cmplt_ps(a, _mm_setzero_ps());
    auto avx512_mask = _mm_cmp_ps_mask(sse_mask, _mm_setzero_ps(), 25);

    alignas(16) float v1[4];
    alignas(16) float v2[4];
    _mm_store_ps(v1, _mm_blendv_ps(a, c, sse_mask));
    _mm_store_ps(v2, _mm_mask_blend_ps(avx512_mask, a, c));

    assert(v1[0] == v2[0]);
    assert(v1[1] == v2[1]);
    assert(v1[2] == v2[2]);
    assert(v1[3] == v2[3]);
    return 0;
}

最佳答案

首先使用 AVX-512 比较内在函数来获得 AVX-512 掩码(如 _mm_cmp_ps_mask );这将比先比较一个 vector 然后再转换它要高效得多,除非编译器为您优化掉这种低效率。 (考虑使用像 Agner Fog's VCL 这样的包装库来尝试抽象出差异。VCL 许可证最近从 GPL 更改为 Apache。)


但如果您真的需要这个(例如,作为完成优化之前的权宜之计),您不需要 FP 比较_mm_cmp_ps在 C 中产生一个 __m128结果,但它真的不是 float 1的 vector 。它是全一位/全零位。你只想要这些位,所以你正在寻找 AVX-512 等效于 vmovmskps , 但进入 k注册而不是 GP 整数。即 VPMOVD2M k, x/y/zmm 对于 32 位源元素。

   __m128 cmpvec = _mm_cmplt_ps(v, _mm_setzero_ps() );
   __mmask8 cmpmask = _mm_movepi32_mask( _mm_castps_si128(cmpvec) );   // <----

// equivalent to comparing into a mask in the first place:
   __mmask8 cmpmask = _mm_cmplt_ps_mask(v, _mm_setzero_ps(), _CMP_LT_OQ);

// equivalent to (if I got this right)
   __mmask8 cmpmask = _mm_fpclass_ps_mask(v, 0x40 | 0x10);  // negative | negative_inf

https://uops.info/现在正在关闭,否则我会检查 VPMOVD2M 与 VCMPPS 的延迟和执行端口到掩码(对于 UNORD 谓词)与 VFPCLASSPS。


脚注 1:您可以使用 AVX-512 vfpclassps进入面具,甚至与 vcmpps 进行比较像 UNORD 这样的谓词来检测 NAN 与否。但我认为这些速度较慢。


I would need to chain it with a _cvtu32_mask8 to pull it back into one of the dedicated mask registers.

编译器当前做事的方式,__mmask8只是 unsigned char 的类型定义, 和 __mmask16unsigned short .它们可以在没有内在函数的情况下自由转换,无论好坏。但在 asm 中,它需要一个 kmovb k1, eax将数据从 GP reg 获取到 k mask reg 的指令,并且该指令只能在当前 CPU 的端口 5 上运行。

关于c++ - 从 avx/sse 掩码到 avx512 掩码的 "correct"方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66493835/

相关文章:

x86 - 如何为我的独立可启动代码启用 SSE?

c - 使用代码矢量化的矩阵运算

c++ - 将 AVX 与 GCC : __builtin_ia32_addpd256 not declared 一起使用

c++ - AVX __m256i 有符号 32 位元素的整数除法

c++ - 通过libusb与USB设备通信的蛮力方法

c++ - 如何提取音频/视频文件的持续时间?

matrix - 使用 SIMD 内在函数进行高效的行列转换

c - 使用 AVX 的有符号/无符号整数的最小值

c++ - 文件输入/输出是否需要二进制标志?

c++ - 还检查继承函数的函数签名