较小等于的AVX2整数比较

AVX2 integer comparison for smaller equal

比较 <= 的两个 4x 64 位整数 AVX 向量的最有效方法是什么。

从 Intel Intrinsics Guide 我们有

用于比较

用于逻辑运算。

我的方法是:

// check = ( a <= b ) = ~(a > b) & 0xF..F
__m256i a = ...
__m256i b = ...
__m256i tmp = _mm256_cmpgt_epi64(a, b)
__m256i check = _mm256_andnot_si256(tmp, _mm256_set1_epi64x(-1))

你是对的,没有直接的方法可以得到你真正想要的面具,只有一个倒置的面具:A gt B = A nle B.

没有 vector-NOT 指令,因此您确实需要一个全 1 向量以及一个额外的指令来反转向量。 (或全零向量和 _mm256_cmpeq_epi8,但不能 运行 在与 _mm256_xor_si256 一样多的执行端口上使用全一向量。)参见 标记 wiki 以获取性能信息,尤其是。 Agner Fog 的指南。

另一个按位布尔选项 _mm256_andn_si256 与异或一样好。它不是可交换的,并且在心理上验证您是否做对了稍微复杂一些。 xor-with-all-ones 是翻转所有位的好习惯用法。


在大多数代码中,可以以相反的方式使用它,而不是花费一条指令来反转掩码。

例如如果它是 blendv 的输入,则将操作数的顺序反转到混合。而不是
_mm256_blendv_epi8(a, b, A_le_B_mask),使用
_mm256_blendv_epi8(b, a, A_nle_B_mask)

如果你打算 _mm_and 戴面具,请改用 _mm_andn

如果您要 _mm_movemask 并测试全零,您可以改为测试全一。它将编译为 cmp eax, -1 指令而不是 test eax,eax,这同样有效。如果您要对第一个 1 进行位扫描,则必须将其反转。整数 not 指令(来自对 movemask 结果使用 ~ )比在向量上执行它更便宜。


只有在进行 OR 或 XOR 运算时才会遇到问题,因为这些指令不会否定其输入之一。 (IDK 如果英特尔只是不想添加 PORN 助记符,但可能 PANDPANDN 得到更多使用,尤其是在可变混合指令之前。