__m512 打包位测试没有内在的内容(如
_mm512_testz_si512
)。
最好的方法是什么?
_mm512_test_epi32_mask(v,v) == 0
是直接替代品。
测试掩码,然后测试掩码以获得标量
bool
您可以分支或其他。
如果您不想立即在其上分支并且不需要需要将其转换为
bool
,或者如果您想知道,您也可以将掩码用作0或非零整数其中设置的位是(位扫描或弹出计数)。或者使用它来零屏蔽或合并屏蔽其他 AVX-512 操作。
__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中,如果使用周围的代码进行优化,它可能看起来像这样:
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
或者根据您想要对掩码执行的操作,
_mm512_testn_epi32_mask(v,v)
获得 NAND 而不是 AND。 testn(v,v) == ~test(v,v)
。但是,如果您只想测试掩码,您同样可以执行 _mm512_test_epi32_mask(v,v) == 0xFFFF
来检查所有 16 个元素是否都有非零位,而不是检查 testn
结果是否为 0。除了机器代码之外,这并不便宜尺寸,因此最重要的是避免在 countr_zero
或其他任何事情之前翻转掩模。
AVX-512 比较和测试仅适用于将掩码寄存器作为目标 (
k0-k7
),有点像将比较 + vpmovmskb
卷入一条单微指令指令中。 (_mm256_movemask_epi8
或ps/pd
。这些的AVX-512版本提取每个元素的高位,是vpmovd2m
(_mm512_movepi32_mask
),可用于每个元素大小,包括16位,例如抓取整数或浮点数的符号位。)
获得掩码后,有两条指令用于根据
k
寄存器设置整数FLAGS条件:kortest
(根据2个掩码或掩码与其自身的按位或来设置FLAGS)和AVX512DQ /BW ktest
(... AND 2 个面具...)。
因此,您实际上可以一次测试两个向量是否有任何非零元素,例如
__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
vptestmd
和 1x kortestw
。在这种情况下,与向量相同的微指令数 OR + 1 vptestmd
+ kortest
;能够检查两个掩码中任何一个中的任何设置位对于更复杂的比较(例如精确相等)可能很有用。
SSE4 / AVX
ptest
转换为整数 FLAGS 始终为 2 uops (https://uops.info/)。像 _mm256_testz_si256
这样的内在函数公开了您可以检查的各种 FLAGS 条件,在本例中为 ZF==1,让编译器发出诸如 jz
、jnz
、cmovz ecx, edx
或 setz al
之类的指令,具体取决于您的方式使用结果 bool
。
传统 SSE
ptest
(不覆盖源寄存器)的好处之一在 AVX 3 操作数指令中不存在,但当输入向量不比较时,获取 AND 或 ANDN 结果偶尔仍然有用结果或其他全 0/全 1 掩码。 (比较 + ptest + jcc 比比较 / pmovmskb / 宏融合 test+jcc
更差,总共 3 个 uops)。
AVX-512 是围绕每个元素掩码进行大量设计的(例如,我们不只是将
_mm256_xor_si256
扩大到 512,而是使用 _mm512_xor_epi32
或 64
作为 _mm512_maskz_and_epi32
的无掩码版本。同样,AVX -512 版本的 ptest
现在是掩码寄存器中每个元素的东西。除了标量 FP 比较到像 vucomisd
这样的 EFLAGS 之外,AVX-512 正则化了东西,所以比较/测试总是进入掩码寄存器,而不是像 那样的 EFLAGS ptest
或通用寄存器,如 pmovmskb
。
相关:
vptestmw
(_mm512_test_epi16_mask(v,v)
) 的示例,以获取元素所在位置的掩码
缺少掩码的 AVX-512 内在函数? - 因为我提到了像
kunpckwd
这样的掩码向量操作。通常,由编译器决定是否将 kmov
掩码转换为整数寄存器(如果再次将它们用作 AVX-512 掩码,则返回)。