【发布时间】:2011-04-19 18:43:10
【问题描述】:
使用 nasm 在 x86 汇编中编程...
使用 MOVQ 指令我将 m64 放入 xmm
MOVQ xmm1, qword [mymem64]
现在我想将它与零进行比较,以便我可以使用 Jcc
如何做到这一点,必须使用什么指令? (快速查看我没有找到的手册)
PS。我更喜欢英特尔语法:P
【问题讨论】:
使用 nasm 在 x86 汇编中编程...
使用 MOVQ 指令我将 m64 放入 xmm
MOVQ xmm1, qword [mymem64]
现在我想将它与零进行比较,以便我可以使用 Jcc
如何做到这一点,必须使用什么指令? (快速查看我没有找到的手册)
PS。我更喜欢英特尔语法:P
【问题讨论】:
如果要根据值有条件地跳转,请不要使用 SSE。为了能够设置 Jcc 所需的标志,您需要将值存储在通用寄存器中。如果您使用的是 64 位,则可以执行以下操作:
mov r8,[m64]
test r8,r8
jnz .out
如果您使用的是 32 位,则可以分别检查这两个部分:
mov eax,dword [m64]
mov edx,dword [m64+4]
or eax,edx
jnz .out
【讨论】:
请注意,比较 xmm 寄存器中的 64 位操作数是没有意义的,您可以使用通用寄存器。
如果您需要针对操作数进行 AND 或 ANDN 测试,您可以使用 PTEST:
PTEST XMM0, [yourmem128] ; compare
JZ somewhere ; jump if all bits of the logical and are zero
如果要测试两个 64 位操作数,需要使用 PCMPEQQ
PCMPEQQ XMM0, [yourmem128] ; compare two 64 bit words
PEXTRQ RAX, XMM0, 1 ; upper 64 bit
MOVQ RBX, XMM0 ; lower 64 bit
OR RAX, RBX
NEG RAX
JZ somewhere ; jump if at least one word is zero
【讨论】:
movmskpd(2 位掩码)或pmovmskb eax, xmm0(16 位掩码)/test eax,eax/jnz at_least_one_match。 test/jnz 将宏融合到一个微指令中,不像 OR 或 NEG。
neg 毫无意义。 RAX 是 -1 或 0,而 -1 的 neg 仍然非零。所以 ZF 已经被 OR 适当地设置了。 (如果你在想NOT,NOT 不会设置标志。如果你想测试至少一个零,你会在你的中使用test rax, rbx,而不是 OR。你不能从 OR 结果中恢复 AND 结果。但实际上您仍然会使用 pmovmskb 和 cmp eax, 0xffff / jne not_all_matched
如果您只测试四字(64 位),则应避免使用 SSE:
CMP qword [mymem64], 0
JNZ .out
即使您正在测试完整的 128 位 XMM 的价值,也是如此:
MOV rax, qword [mymem128]
OR rax, qword [mymem128+8]
JNZ .out
但是,如果您的 CPU 使用 SSE 4.1,并且需要测试 128 位,则使用:
VMOVDQU xmm0, xmmword [mymem128]
VPTEST xmm0, xmm0
JNZ .out
【讨论】:
pcmpeqd xmm0,xmm0),您可以vptest xmm0, [mem] / jnz 仍然测试内存操作数中的所有位。 (AVX 编码不需要内存操作数对齐。)uops.info 表明现代英特尔 CPU 可以将ptest 与内存操作数微融合,因此它仍然只有 2 个微指令,与pcmpeqb/pmovmskb 相同.