_mm_testc_ps 和 _mm_testc_pd 对比 _mm_testc_si128

_mm_testc_ps and _mm_testc_pd vs _mm_testc_si128

如您所知,前两个是特定于 AVX 的内部函数,第二个是 SSE4.1 内部函数。两组内在函数均可用于检查 2 个浮点向量是否相等。我的具体用例是:

但是 AVX 为 "legacy" 内在函数提供了等价物,因此我可以在将结果转换为 __m128i 之后使用 _mm_testc_si128。我的问题是,这两个用例中的哪一个会带来更好的性能,以及我在哪里可以找到 AVX 提供的遗留 SSE 指令。

糟糕,我没有仔细阅读问题。你说的是在 cmpeqps 之后使用这些。如果您已经有了面具,它们总是比 movmskps / test 慢。 cmpps / ptest / jcc 是 4 微指令。 cmpps / movmskps eax, xmm0 / test eax,eax / jnz 是 3 微指令。 (test/jnz 融合成一个 uop)。此外,none 的指令是多 uop,因此没有解码瓶颈。

仅当您可以充分利用 AND 或 ANDN 运算以避免更早的步骤时才使用 ptest / vtestps/pd。在将 ptest 与替代方案进行比较之前,我已经发布了答案。我想我确实找到了一个案例,其中 ptest 是一个胜利,但它很难使用。是的,found it: someone wanted an FP compare that was true for NaN == NaN。这是我发现 ptest.

的进位标志结果的唯一一次使用

如果比较结果的高位元素是"garbage",那么你仍然可以用movmskps廉价地忽略它:

_mm_movemask_ps(vec) & 0b0111 == 0  // tests for none of the first three being true

这是完全免费的。 x86 test 指令的工作方式与 ptest 非常相似:您可以将它与直接掩码一起使用,而不是针对自身测试寄存器。 (它实际上有一个很小的成本:一个额外的机器代码字节,因为 test eax, 3test eax, eax 长一个字节,但它们 运行 相同。)。

请参阅 wiki 以获取指南链接(Agner Fog 的指南非常适合在指令级别进行性能分析)。 every 遗留 SSE 指令有一个 AVX 版本,但有些只有 128 位宽。他们都得到一个额外的操作数(因此 dest 不必是 src regs 之一),这节省了 mov 复制寄存器的指令。


回答一个你没有问过的问题:

_mm_testc_ps_mm_testc_si128 都不能用来比较浮点数是否相等。 vtestps 类似于 ptest,但只对每个 float 元素的符号位进行操作。

它们都计算 (~x) & y(在符号位或完整寄存器上),这不会告诉您它们是否相等,甚至符号位是否相等。

请注意,即使检查浮点数的按位相等性(使用 pcmpeqd)也与 cmpeqps(实现 C 的 == 运算符)不同,因为 -0.0 不按位等于 0.0。并且两个按位相同的 NaN 彼此不相等。如果其中一个或两个操作数是 NaN.

,则比较是无序的(这意味着不相等)