为什么在检查 0 时使用 OR 代替 CMP

  • 本文关键字:OR 代替 CMP assembly x86
  • 更新时间 :
  • 英文 :


使用"or"而不是"cmp"时是否有重大的积极品质?

考虑以下功能序幕:

push  ebp
mov   ebp,esp
push  ebx
xor   eax,eax        ;error return code
mov   ecx,[ebp +8]   ;first integer arg after return addr.
mov   edx,[ebp +12]  ;second integer argument

该函数应计算a / ba % b
首先,我需要检查 0 除数。

我的直觉是组装

cmp  edx,0
je   InvalidDivisor

但是当我查看有关汇编程序的高级书籍时,会使用以下内容:

or   edx,edx
jz   InvalidDivisor   

我的问题是为什么第二种解决方案"更正确"?
计算 or 操作并检查零标志不会比仅比较两个值花费更长的时间吗?

这只是更高级的编码风格问题吗?

or edx,edx是两个字节,cmp edx, 0是三个字节,所以如果你关心大小,你知道该选择哪个。

如果你更关心速度,那么你实际上需要测量。 Or显然会"改变"寄存器,如果下一条指令使用相同的寄存器,可能会增加延迟。

比较寄存器与零的最佳选择是 test reg, reg

83 fa 00  cmp    edx,0x0
09 d2     or     edx,edx ; Smaller
85 d2     test   edx,edx ; Smaller and better, updates ZF but does not store the result

两个指令组合在一起:

83 fa 00                cmp    edx,0x0
09 d2                   or     edx,edx

如您所见,使用 or 更短(因此在运行时加载的代码更少(并且具有相同的效果。但是,实际上最好使用:

85 d2                   test   edx,edx 

如果edx为零,并且进一步的操作知道即使 CPU 尚未弄清楚,它们也不需要依赖结果,这也设置了零标志。

虽然问题中的示例适用于英特尔 x86,但 CMP 和 OR 指令也存在于其他处理器中。

在 MOS 6502 上,寄存器不多,并且您可能也在状态标志中传递参数或返回值,您可能希望避免影响 C 标志的指令。因此,您可能更喜欢 EOR(排他性或(、与 OR 或 CMP。在 6502 上,几乎所有复制数据的指令都会影响 N 和 Z 标志。

在 Atmel 8 位 AVR 微控制器系列上,有一个方便的指令 CPSE(如果相等,则比较和跳过(,如果我没记错的话,它不会影响任何标志。AVR-GCC将32个寄存器中的一个指定为"零寄存器",然后发出代码以在该寄存器中使用CPSE。

您没有明确说明这是针对哪个处理器的,但一般而言:

你在汇编程序中编码,因此你关心内存和时钟周期。

您要做的只是检测EAX是否为零。如果EAX为零,ORinx EAX本身将设置Z状态位,对EAX的内容没有任何副作用,并且比直接与零比较更快。

将寄存器与即时值进行比较可能需要(至少(一个额外的周期来加载,并且常量值"0"需要一个额外的字节(或 2 或 4(。
另一方面,寄存器数量有限,对EAX的引用可能直接使用3位或4位在指令中编码。

最新更新