14.1 x86
以一种十分容易预测的方式编译的
_a$ = 8 ; size = 4
_f PROC
push ebp
mov ebp, esp
mov eax, DWORD PTR _a$[ebp]
cdq ; sign extend EAX to EDX:EAX
mov ecx, 9
idiv ecx
pop ebp
ret 0
_f ENDP
IDIV 有符号数除法指令 64位的被除数分存在两个寄存器EDX:EAX,除数放在单个寄存器ECX中。运算结束后,商放在EAX,余数放在EDX。f()函数的返回值将包含在eax寄存器中,也就是说,在进行除法运算之后,值不会再放到其他位置,它已经在合适的地方了。正因为IDIV指令要求被除数分存在EDX:EAX里,所以需要在做除法前用CDQ指令将EAX中的值扩展成64位有符号数,就像MOVSX指令(13.1.1)所做的一样。如果我们切换到优化模式(/0x),我们会得到
清单14.2:MSVC优化模式
_a$ = 8 ; size = 4
_f PROC
mov ecx, DWORD PTR _a$[esp-4]
mov eax, 954437177 ; 38e38e39H
imul ecx
sar edx, 1
mov eax, edx
shr eax, 31 ; 0000001fH
add eax, edx
ret 0
_f ENDP
这里将除法优化为乘法。乘法运算要快得多。使用这种技巧可以得到更高效的代码。
在编译器优化中,这也称为“strength reduction”
GCC4.4.1甚至在没有打开优化模式的情况下生成了和在MSVC下打开优化模式的生成的几乎一样的代码。
清单14.3 GCC 4.4.1 非优化模式
public f
f procnear
arg_0 = dword ptr 8
push ebp
mov ebp, esp
mov ecx, [ebp+arg_0]
mov edx, 954437177 ; 38E38E39h
mov eax, ecx
imul edx
sar edx, 1
mov eax, ecx
sar eax, 1Fh
mov ecx, edx
sub ecx, eax
mov eax, ecx
pop ebp
retn
f endp
当前内容版权归 Dennis Yurichev 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 Dennis Yurichev .