在x86中,"test eax,eax"和"cmp eax,0"之间有什么区别

Hin*_*sum 24 x86 assembly

test eax, eax不是更有效cmp eax, 0?是否有test eax, eax必要在cmp eax, 0不满足要求的地方?

Mik*_*kis 29

正如臧明杰在评论中已经说过的那样,test eax,eax几乎是相同的cmp eax,0,除了它短于cmp,因为cmp你必须提供0作为论据.请注意,节省的不是很大,因为第二个操作数会进行符号扩展以匹配第一个操作数的大小,因此它不一定需要整整4个字节来表示该零.

现在,你要问的是,是否还有其他不同之处.这是一个合理的问题,因为它cmp是一个算术运算(它执行减法并丢弃结果),而它test是一个逻辑运算,(它执行按位AND并丢弃结果),因此可以合理地怀疑它们可以Flags不同地修改寄存器.

事实证明,两个指令都Flags几乎相同的方式修改寄存器.两条指令都修改了标志寄存器的OF SF ZF AF PF和CF位.test指令总是清除OF和CF,但这也是cmp反对零的指令.唯一的另一个区别是cmp指令将正确设置隐藏AF标志,而指令则保留标志test的内容未定义.但是在cmp eax,0AF 的情况下总是会被清除,无论其价值如何eax,所以没有什么可以从cmp eax,0你不会从中学到的东西中学到test eax,eax.

因此,我的结论是,没有任何情况test eax,eax会给你一些cmp eax,0不会,反之亦然的东西.除了保存一个或两个指令代码之外,这两条指令似乎完全可以互换用于任何实际或甚至不那么实用的目的.

使用test eax,eax而不是cmp eax,0显示你知道你的装配.它还表明,您更倾向于使用一种稍微含糊不清且性能稍好的指令而不是直接易懂的指令.这种东西往往会从其他极客那里获得奖励积分,但在过去的几十年里,它在现实世界中没有任何实际用处.

  • 具体来说,请参阅我在 [使用 CMP reg,0 与 OR reg,reg? 测试寄存器是否为零?](//stackoverflow.com/a/33724806) 上的答案以了解更多信息。(还有:“在现实世界中没有实际用处”:除非您是编译器/JIT 开发人员。人类必须知道如何创建高效的 asm,然后才能让机器为他们做这件事。) (5认同)
  • 在Intel Core2或Nehalem上可能存在性能上的差异,其中TEST可以与CMP相比具有更多JCC风格.例如,Core2和Nehalem可以将`test eax,eax/js`宏连接起来,而不是`cmp eax,0/js`.然而,Nehalem可以宏观地融合`cmp eax,0/jl`.(Core2不能,但Core2只能在32位模式下进行宏保险).[参见Agner Fog的microarch pdf](http://agner.org/optimize/) (4认同)

Lok*_*wat 7

#差异(理论)

正如上面在评论和接受的答案中所述,这些说明几乎相同当以这种方式使用时,但是如果指令集中有两条指令,为什么它们呢?

因为如果与不同的操作数一起使用它们是不同的。test same,same与零进行比较 的事实只是 2 的补码和 FLAGS 如何工作的一个方便的结果,使其成为有用的窥视孔优化。

TEST 指令对来自 arg0 和 arg1 的位对使用 AND 逻辑,可以检查是否设置了特定位,然后相应地设置 FLAGS。(丢弃整数结果)。就像cmp从减法中设置 FLAGS 而丢弃整数结果一样。

#操作(测试)

英特尔vol.2 PDF 手册中的HTML 除外

TEMP ? SRC1 **AND** SRC2;
SF ? MSB(TEMP);
IF TEMP=0
    THEN ZF ? 1;
    ELSE ZF ? 0;
FI:

PF ? BitwiseXNOR(TEMP[0:7]);
CF ? 0;
OF ? 0;
(* AF is undefined *)
Run Code Online (Sandbox Code Playgroud)

受影响的标志

OF 和 CF 标志设置为 0。SF、ZF 和 PF 标志根据结果设置(参见上面的“操作”部分)。AF 标志的状态未定义。

(TEST 操作将标志 CF 和 OF 设置为零。SF 设置为 AND 结果的最高有效位。如果结果为 0,则 ZF 设置为 1,否则设置为 0。)


虽然CMP 指令使用 SUB 指令并从 arg0 中减去 arg1 并将根据给定的 args 设置 CF(进位标志)和 ZF(零标志)到 CMP 指令,如果两者相等(arg1==arg0)那么很明显结果将为零,ZF 将设置为 1,如果 arg0 > arg1 则不设置标志(ZF 和 CF 保持为 0),如果 arg0 < arg1,则 ZF 将保持为 0,因为它们不相等但 CF 将被设置。

#操作(CMP)

temp ? SRC1 ? SignExtend(SRC2); 
ModifyStatusFlags; 
   (* Modify status flags in  the same manner as the SUB instruction*)
Run Code Online (Sandbox Code Playgroud)

受影响的标志

根据结果​​设置 CF、OF、SF、ZF、AF 和 PF 标志。