_mm_testc_ps 和 _mm_testc_pd 对比 _mm_testc_si128
_mm_testc_ps and _mm_testc_pd vs _mm_testc_si128
如您所知,前两个是特定于 AVX 的内部函数,第二个是 SSE4.1 内部函数。两组内在函数均可用于检查 2 个浮点向量是否相等。我的具体用例是:
_mm_cmpeq_ps
或 _mm_cmpeq_pd
,后接
_mm_testc_ps
或 _mm_testc_pd
结果,带有适当的掩码
但是 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, 3
比 test eax, eax
长一个字节,但它们 运行 相同。)。
请参阅 x86 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
.
,则比较是无序的(这意味着不相等)
如您所知,前两个是特定于 AVX 的内部函数,第二个是 SSE4.1 内部函数。两组内在函数均可用于检查 2 个浮点向量是否相等。我的具体用例是:
_mm_cmpeq_ps
或_mm_cmpeq_pd
,后接_mm_testc_ps
或_mm_testc_pd
结果,带有适当的掩码
但是 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, 3
比 test eax, eax
长一个字节,但它们 运行 相同。)。
请参阅 x86 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
.