使用"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 / b
或a % 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位在指令中编码。