__m512的包装位测试

Packed bit test for __m512

提问人:user2052436 提问时间:11/3/2023 最后编辑:Peter Cordesuser2052436 更新时间:11/3/2023 访问量:47

问:

没有__m512填充位测试的内在函数(如)。_mm512_testz_si512

最好的方法是什么?

x86-64 函数 AVX512

评论


答:

2赞 Peter Cordes 11/3/2023 #1

_mm512_test_epi32_mask(v,v) == 0 是直接替换。

测试到掩码中,然后测试掩码以获得可以分支的标量或其他任何东西。如果您只关心整个向量是否在任何地方都有非零位,则测试的元素大小无关紧要,但可以使用 8/16/32/64 的元素大小(asm 手册/内部指南)。bool

如果您不想立即对掩码进行分支并且不需要将其转换为 ,或者如果您想知道设置位的位置(位扫描或 popcount),您也可以将掩码用作 0 或非零整数。或者使用它对其他 AVX-512 操作进行零屏蔽或合并屏蔽。bool

    __mmask16 mask == _mm512_test_epi32_mask(v,v);   // 0 or non-zero integer
    if (mask != 0) {  // __mmask16 is in practice an alias for uint16_t
          // You might have further use for the mask, e.g.
          int first_match_index = std::countr_zero(mask);
    }

在asm中,测试/分支或获取GPR整数可能如下所示:

  vptestmd  k0, zmm1, zmm1     ; mask of elements where zmm1&zmm1 was non-zero.

; branch on it.  Or a compiler might use cmovz or setz (create an actual bool)
  kortestw  k0, k0             ; set integer FLAGS according to k0|k0
  jz        vec_was_all_zero   ; branch if ZF==1

; or get a 0 / non-0  int  you can return, or bit-scan to find the first non-zero element
  kmovw     eax, k0

或者根据你想用掩码做什么,得到NAND而不是AND。但是,如果您只想测试掩码,则同样可以检查所有 16 个元素是否具有非零位,而不是检查结果是否为 0。除了机器代码大小之外,这并不便宜,因此最重要的是避免在之前反转掩模或其他任何事情。_mm512_testn_epi32_mask(v,v)testn(v,v) == ~test(v,v)_mm512_test_epi32_mask(v,v) == 0xFFFFtestncountr_zero


AVX-512 比较和测试仅适用于将掩码寄存器作为目标 (k0-k7),有点像将比较 + 整合到一个单一 uop 指令中。( 或 .这些元素的 AVX-512 版本提取每个元素的高位,是 vpmovd2m(),可用于包括 16 位在内的所有元素大小,例如抓取 int 或 floats 的符号位。vpmovmskb_mm256_movemask_epi8ps/pd_mm512_movepi32_mask

获得掩码后,有两个指令用于基于寄存器设置整数 FLAGS 条件:kortest(根据 2 个掩码的按位 OR 或带有自身的掩码设置 FLAGS)和 AVX512DQ/BW ktest (...和 2 个面具......k

因此,您实际上可以一次测试两个向量是否具有任何非零元素,例如

 __mmask16 mask1 = _mm512_test_epi32_mask(v1,v1);
 __mmask16 mask2 = _mm512_test_epi32_mask(v2,v2);
 // or any other condition you want to check, like _mm512_cmple_epu32(x,y)
 if (mask1 | mask2) {
    // At least one was non-zero; sort out which if it matters.
    // Or maybe concatenate them (e.g. kunpckwd) and bit-scan the 32-bit mask
    //  to find an element index, maybe into memory they were loaded from
 }

这将编译为 2x 和 1x 。在这种情况下,与向量 OR + 1 + 相同的 uops 数量;能够检查两个掩码中的任何一个中的任何设置位对于更复杂的比较(例如精确相等)可能很有用。vptestmdkortestwvptestmdkortest


无论如何,SSE4 / AVX 转换为整数 FLAGS 在主流 Intel CPU 上始终是 2 uops(https://uops.info/)。内部函数 like 公开了您可以检查的各种 FLAGS 条件,在本例中为 ZF==1,让编译器发出类似 、 、 或 的指令,具体取决于您如何使用生成的 .ptest_mm256_testz_si256jzjnzcmovz ecx, edxsetz albool

AVX 3 操作数指令不存在 legacy-SSE(不覆盖源寄存器)的好处之一,但是当输入向量不是比较结果或其他 all-0 / all-1 掩码时,偶尔获得 AND 或 ANDN 结果仍然很有用。(比较 + ptest + jcc 比 compare / pmovmskb / macro-fused 差,后者总共有 3 个 uops)。ptesttest+jcc

AVX-512 是围绕每个元素的遮罩而设计的(例如,我们不是简单地扩展到 512,而是作为 .同样,AVX-512 版本现在是将每个元素的东西放入掩码寄存器中。除了标量 FP 与 EFLAGS 进行比较之外,AVX-512 正则化的东西,因此比较/测试始终进入掩码寄存器,而不是像 EFLAGS 这样的 EFLAGS 或像 这样的通用寄存器。_mm256_xor_si256_mm512_xor_epi3264_mm512_maskz_and_epi32ptestvucomisdptestpmovmskb

相关: