代码分析:分段,以块为单位看代码,逐个击破
流水线优化:在不影响结果的前提下,排列指令顺序,提高并行程度
除法
变化一
如果除数是变量,只能使用除法指令,有符号是idiv,无符号是div
这是经过数学论证的,当除数位置是没有优化的余地的
变化二
除数不是变量,且除数是2的幂
1.在无符号的情况下,采取向下取整的除法,,一般直接使用右移指令
2.有符号的情况下,需要经过数学推导:
数学除法会产生小数,C语言计算产生的误差只要在0- |1/b| 之间的范围,可以利用这个推导来忽略误差
由以上推导,处理有符号数的时候,例如
编译器的优化过程以推导7作为基础
可是,如何将 n > 0 和 n < 0 这两个分支优化,编译器采取的思路是利用cdq配合and指令
cdq ;符号拓展,将eax的符号拓展到edx,edx要么位0xffffffff要么为0
and edx,7 ;利用与运算,若n > 0 ,edx = 0, n < 0, edx = 7
add eax,edx
sar eax,3
定式:
cdq
and edx, immA
add eax, edx
sar eax, immB
验证:
(2^immB) -1 = immA
若不相等,则可能是作者内联汇编挖的坑,因为c语言语法是不会产生cdq指令的
还原:
eax / (2^immB)
除数不是变量,且除数不是2的幂
Debug:不做有优化
Release:
推导:
m = 2^n / c
n由编译器决定,一般16位环境从16开始,32位环境从32开始,以此类推。
所以2^n为常量
c为常量
n的取值由c决定,需要满足误差小于1/c
所以m为常量,又称为MagicNumber,这个值由编译器编译时产生
又因为 a*m = edx. eax
有可能直接使用edx,那么这就是结果 >>32 位
所以最后的结果需要以edx做移位,
所以edx的移位位数需要加上32
定式
mov eax, MagicNumber
imul ....
sar edx, ...
mov reg, edx
shr reg, 1fh
add edx, reg
还原
o = 2^n / c
n从右移的次数得到,MagicNumber作为c,代入公式求解到除数近似值,还原除法原型