为什么在检查0时使用或代替cmp

时间:2017-03-20 17:41:44

标签: assembly

使用“或”代替“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-operation并检查零标志,而不仅仅是比较两个值?

这只是一种更高级的编码风格吗?

4 个答案:

答案 0 :(得分:4)

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

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

Rule of Zero

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

答案 1 :(得分:3)

两条指令汇编为:

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

正如您所看到的,使用or更短(因此在运行时加载的代码更少)并具有相同的效果。然而,使用它实际上更好:

85 d2                   test   edx,edx 
如果edx为零,

也会设置零标志,并且进一步的操作知道即使CPU没有计算出来也不需要依赖结果。

答案 2 :(得分:1)

您没有明确说明这是什么处理器,但一般来说:

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

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

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

答案 3 :(得分:1)

虽然问题中的示例是针对Intel x86的,但CMP和OR指令也存在于其他处理器中。

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

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