test 与and 类似,不同之处在于它只写入 FLAGS,而其两个输入均未修改。使用两个 不同 输入,这对于测试某些位是否全为零或是否至少设置了一个很有用。 (例如,test al, 3 如果 EAX 是 4 的倍数,则设置 ZF(因此其低 2 位均为零)。
test eax,eax 设置所有标志的方式与cmp eax, 0 完全相同:
除了过时的 AF(辅助进位标志,由 ASCII/BCD 指令使用)。 TEST leaves it undefined,但CMP sets it "according to the result"。由于减零不能产生从第 4 位到第 5 位的进位,因此 CMP 应始终清除 AF。
TEST 更小(不是立即的),有时更快(在比 CMP 更多的情况下,可以在更多 CPU 上宏融合到比较和分支微指令中)。 That makes test the preferred idiom for comparing a register against zero。这是cmp reg,0 的窥视孔优化,无论语义如何,您都可以使用它。
使用立即数为 0 的 CMP 的唯一常见原因是当您想与内存操作数进行比较时。例如,cmpb $0, (%esi) 检查隐式长度 C 样式字符串末尾的终止零字节。
AVX512F 添加 kortestw k1, k2 和 AVX512DQ/BW(Skylake-X 但不是 KNL)添加 ktestb/w/d/q k1, k2,它们在 AVX512 掩码寄存器 (k0..k7) 上运行,但仍设置常规 FLAGS,例如test 的作用与整数 OR 或 AND 指令的作用相同。 (有点像 SSE4 ptest 或 SSE ucomiss:在 SIMD 域中输入并生成整数 FLAGS。)
kortestw k1,k1 是基于 AVX512 比较结果分支 /cmovcc / setcc 的惯用方式,替换 SSE/AVX2 (v)pmovmskb/ps/pd + test 或 cmp。
jz 与 je 的使用可能会造成混淆。
jz and je are literally the same instruction,即机器码中的操作码相同。 它们做同样的事情,但对人类有不同的语义含义。反汇编程序(通常是编译器的 asm 输出)只会使用一个,因此语义区别会丢失。
cmp 和sub 在两个输入相等(即减法结果为 0)时设置 ZF。 je(如果相等则跳转)是语义相关的同义词。
test %eax,%eax / and %eax,%eax 在结果为零时再次设置 ZF,但没有“相等”测试。测试后的 ZF 不会告诉您两个操作数是否相等。所以jz(如果为零则跳转)是语义相关的同义词。