【问题标题】:In x86 what's difference between "test eax,eax" and "cmp eax,0"在 x86 中,“test eax,eax”和“cmp eax,0”有什么区别
【发布时间】:2017-01-26 04:01:58
【问题描述】:

test eax, eax 是否比cmp eax, 0 更高效?在cmp eax, 0 不满足要求的情况下,是否需要test eax, eax

【问题讨论】:

标签: assembly x86


【解决方案1】:

正如臧明杰在评论中所说,test eax, eaxcmp eax, 0 几乎相同,只是它比cmp 短,因为cmp 必须提供0 作为参数。请注意,节省的空间不是很大,因为第二个操作数会进行符号扩展以匹配第一个操作数的大小,因此不一定需要整整 4 个字节来表示该零。

现在,您要问的是是否还有其他区别。这是一个合理的问题,因为cmp 是算术运算,(它执行减法并丢弃结果,)而test 是逻辑运算,(它执行按位与并丢弃结果,)所以人们可以合理地怀疑他们可能会以不同的方式修改Flags 寄存器。

事实证明,两条指令都以几乎相同的方式修改Flags 寄存器。两条指令都修改标志寄存器的 OF SF ZF AF PF 和 CF 位。 test 指令总是清除 OF 和 CF,但这也是 cmp 对零的作用。唯一的其他区别是cmp 指令将正确设置the obscure AF flag,而test 指令未定义该标志的内容。但是在cmp eax,0 的情况下,无论eax 的值如何,AF 都将始终被清除,因此您可以从cmp eax, 0 中学到任何您不会从test eax, eax 中学到的东西。

因此,我会得出结论,test eax, eax 不会为您提供cmp eax, 0 不会提供的东西,反之亦然。除了节省一两个字节的指令代码之外,这两条指令似乎可以完全互换,以用于任何实际甚至不那么实用的目的。

使用test eax, eax 而不是cmp eax, 0 表明您了解您的程序集。它还表明,与简单易懂的指令相比,您更喜欢略显神秘、性能稍好一点的指令。这是一种倾向于从其他极客那里获得奖励积分的东西,但在过去几十年左右的时间里,它在现实世界中没有任何实际用处。

【讨论】:

  • 在 Intel Core2 或 Nehalem 上可能存在性能差异,其中 TEST 可以与更多的 JCC 风格进行宏融合,而不是 CMP。例如Core2 和 Nehalem 可以宏熔断 test eax,eax / js,但不能宏熔断 cmp eax,0 / js。不过,Nehalem 可以宏融合 cmp eax,0 / jl。 (Core2 不能,但 Core2 只能在 32 位模式下进行宏熔断)。 See Agner Fog's microarch pdf
  • 具体来说,请参阅我在Test whether a register is zero with CMP reg,0 vs OR reg,reg? 上的回答了解更多信息。 (并且回复:“在现实世界中没有实际用处”:除非您是编译器/JIT 开发人员。人类必须知道如何创建高效的 asm,然后才能让机器为他们做这件事。)
【解决方案2】:

#差异(理论)

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

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

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

#Operation(TEST)

HTML except 来自英特尔的vol.2 PDF manual

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 *)

受影响的标志

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

#Operation(CMP)

temp ← SRC1 − SignExtend(SRC2); 
ModifyStatusFlags; 
   (* Modify status flags in  the same manner as the SUB instruction*)

受影响的标志

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-05
    • 2013-09-10
    • 1970-01-01
    • 2011-02-11
    • 2023-03-25
    • 2016-05-29
    • 2022-01-15
    相关资源
    最近更新 更多