test
就像and
,除了它只写 FLAGS ,而它的两个输入都保持不变。对于两个不同的输入,它对于测试某些位是否全为零或是否至少设置了一个很有用。(例如test al, 3
,如果 EAX 是 4 的倍数,则设置 ZF(因此它的低 2 位都归零)。
test eax,eax
以完全相同的方式设置所有cmp eax, 0
标志:
- CF 和 OF 清零(AND/TEST 总是这样做;减去零永远不会产生进位)
- ZF、SF 和 PF 根据 EAX 中的值。(
a = a&a = a-0
)。
(PF照常只根据低8位设置)
除了过时的 AF(辅助进位标志,由 ASCII/BCD 指令使用)。 TEST 将其保留为 undefined,但CMP 将其设置为“根据结果”。由于减零不能产生从第 4 位到第 5 位的进位,CMP 应始终清除 AF。
TEST 更小(不立即),有时更快(可以在比 CMP 更多的情况下在更多 CPU 上宏融合到比较和分支微指令中)。 这使得test
将寄存器与零进行比较的首选习语。这是一个窥视孔优化,cmp reg,0
无论语义如何,您都可以使用它。
使用立即数为 0 的 CMP 的唯一常见原因是当您想与内存操作数进行比较时。例如,cmpb $0, (%esi)
检查隐式长度 C 样式字符串末尾的终止零字节。
AVX512F addkortestw k1, k2
和 AVX512DQ/BW (Skylake-X 但不是 KNL) add ktestb/w/d/q k1, k2
,它们在 AVX512 掩码寄存器 (k0..k7) 上运行,但仍然像test
整数OR
或AND
指令一样设置常规 FLAGS。(有点像 SSE4ptest
或 SSE ucomiss
:在 SIMD 域中输入并产生整数 FLAGS。)
kortestw k1,k1
是基于 AVX512 比较结果分支 / cmovcc / setcc 的惯用方式,替换 SSE/AVX2 (v)pmovmskb/ps/pd
+test
或cmp
.
jz
vs.的使用je
可能会令人困惑。
jz
并且je
实际上是相同的指令,即机器代码中的相同操作码。 它们做同样的事情,但对人类有不同的语义。反汇编程序(通常是编译器的 asm 输出)只会使用一个,因此语义区别会丢失。
cmp
并sub
在它们的两个输入相等(即减法结果为0)时设置ZF。 je
(jump if equal) 是语义相关的同义词。
test %eax,%eax
/and %eax,%eax
当结果为零时再次设置 ZF,但没有“相等”测试。测试后的 ZF 不会告诉您两个操作数是否相等。所以jz
(jump if zero) 是语义相关的同义词。