使用“或”代替“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 / b
或a % b
首先,我需要检查0除数。
我的直觉行动是组装
cmp edx,0
je InvalidDivisor
但是当我查看关于汇编程序的高级书籍时,会使用它:
or edx,edx
jz InvalidDivisor
我的问题是为什么第二种解决方案“更正确”? 是否不需要花费更长的时间来计算or-operation并检查零标志,而不仅仅是比较两个值?
这只是一种更高级的编码风格吗?
答案 0 :(得分:4)
or edx,edx
是两个字节,cmp edx, 0
是三个,所以如果你关心大小,你知道要选哪个。
如果你更关心速度,那么你实际上需要测量。 Or
显然会“改变”寄存器,如果下一条指令使用相同的寄存器,可能会增加延迟。
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与该寄存器一起使用。