SSE2 直接测试 xmm 位掩码而不使用“pmovmskb”
Posted
技术标签:
【中文标题】SSE2 直接测试 xmm 位掩码而不使用“pmovmskb”【英文标题】:SSE2 test xmm bitmask directly without using 'pmovmskb' 【发布时间】:2020-02-28 07:01:14 【问题描述】:考虑我们有这个:
....
pxor xmm1, xmm1
movdqu xmm0, [reax]
pcmpeqb xmm0, xmm1
pmovmskb eax, xmm0
test ax , ax
jz .zero
...
有什么办法不使用'pmovmskb'并直接从xmm0测试位掩码(检查它是否为零)? 此操作是否有任何 SSE 指令?
事实上,我正在搜索类似 'ptest xmm0, xmm0' 的操作,但在 SSE2 中...而不是 SSE4
【问题讨论】:
请注意,由于pcmpeqb
在相等时将字段设置为0xff
,因此您需要cmp ax, 0xffff
或cmp eax, 0xffff
而不是test ax, ax
。
我已经投票结束这个问题,因为“需要更清楚”,因为不清楚您是否要检查 xmm0
中的任何字节是否为零,或者它们是否全部为零。请澄清这一点,我将撤回我的投票。
您的代码正在检查xmm0
中是否有任何非零字节,而不是xmm0
是否全为零。你能澄清一下这是否是你想要的吗?也许还说那个测试的上下文是什么? (它真的很关键还是你在进行微优化?)
如果您确实在寻找类似ptest
指令的东西,那么您拥有的序列已经是最佳选择(在您使用cmp eax, 0xffff
而不是test ax, ax
之后)。这已经被问过很多次了。此外,如果您希望其他人注意到您更改了某些内容,请在评论中注明您要回复的人的 @-mention。
如果您想检查内存中的 128 个连续位是否全为零,您最好使用mov rdx, [rax]; or rdx, [rax+8]; je .zero;
之类的东西。但如上所述,您需要展示更多关于您实际想要实现的内容...
【参考方案1】:
通常不值得在 pcmpeqb
结果上使用 SSE4.1 ptest xmm0,xmm0
,尤其是在您进行分支时。
pmovmskb
是 1 uop,cmp
或 test
可以与 jnz
宏融合到 Intel 和 AMD CPU 上的另一个单个 uop。 使用 pmovmsk + test/jcc 对 pcmpeqb 结果进行分支总共需要 2 个微指令
但是ptest
是 2 微指令,它的第 2 微指令 不能 与下面的分支进行宏融合。 在带有ptest
+ jcc 的向量上分支总共需要 3 微指令。
当您可以直接使用 ptest
而不需要 pcmp
时,这是收支平衡的,例如测试整个向量中的任何/所有位(或使用掩码,一些位)。如果您将其用于 cmov 或 setcc 而不是分支,则实际上是一种胜利。即使微指令数量相同,这也是代码大小的胜利。
您可以分摊检查多个向量。 例如por
一些向量在一起,然后检查所有字节是否为零。或者pminub
一些向量在一起,然后检查 any 零。 (像 strlen 和 strchr 这样的 glibc 字符串函数使用这个技巧来并行检查整个缓存行的向量,然后在离开循环后对它的来源进行排序。)
您可以组合 pcmpeq 结果而不是原始输入,例如对于memchr。在这种情况下,您可以使用 pand
而不是 pminub
在 any 输入为零的元素中获取零。一些 CPU 在比 pminub
更多的端口上运行 pand
,因此向量 ALU 的竞争更少。
还要注意 pmovmskb 零扩展为 EAX;你可以test eax,eax
而不是浪费一个前缀字节来只测试 AX。
【讨论】:
一个关于'test eax,eax'的问题......所以你告诉我如果我们处于长模式(64位),最好这样做'test rax,rax ' ? @ELHASKSERVERS No.test rax, rax
需要一个前缀字节(正如您在之前的一个问题中已经注意到的那样),而 test eax, eax
不需要。
@ELHASKSERVERS:长模式下的默认操作数大小为 32 位。当您可以选择节省代码大小时使用它(即当它不需要任何额外的指令时),出于同样的原因,您可以使用 xor eax,eax
将 64 位寄存器归零【参考方案2】:
使用ptest
:
ptest xmm0, xmm0
jz .zero
ptest a, b
如果a
∧ b
为零,则设置 ZF,如果 a
∧ ¬ b
为零,则设置 CF。
但请注意,ptest
需要 SSE 4.1。
否则,我想你的方法是as good as it gets。
【讨论】:
在 SSE2 中还有其他方法吗? @ELHASKSERVERS 据我所知,没有一个比你已经拥有的更好。有关详细信息,请参阅链接的问题。 @ELHASKSERVERS 另见this answer。 @fuz 链接的问题检查全零。上面的问题检查所有字节是否非零。使用ptest
(在pcmpeqb
之后)似乎是最有效的方法(如果有的话)。
@chtz 我想 OPs 代码是错误的,因为下面的文字清楚地表明他想检查寄存器是否全为零。以上是关于SSE2 直接测试 xmm 位掩码而不使用“pmovmskb”的主要内容,如果未能解决你的问题,请参考以下文章