编译器对于加法运算的优化
优化常见的几种方式
常量传播
将编译期间可计算出结果的变量转换为常量,减少变量的使用
#include <iostream>
int main()
{
int nVar = 1;
printf("nVar = %d \n",nVar);
}
对于上述代码,如果没有进行优化,那么处理的逻辑为:
会先将该值放入栈中,在 printf要输出它时,再将其拿到 esi中,通过 rsi传给 printf进行输出
进行 O1优化以后
由于变量 nVar是一个在编译期间可以计算出结构的变量,所以将其替换为常量直接用1来替代
printf要使用时直接传入1即可。
O2优化中在对变量的处理一致
常量折叠
在公式中出现多个常量进行计算的情况中,且编译器可以算出结果的情况下,在编译期间直接用计算结果替代
#include <iostream>
int main()
{
int nNum = 1 + 8 * 7 - 10;
printf("nNum = %d \n",nNum);
}
对于上述代码,如果没有进行优化,那么处理的逻辑为:
但其实这也进行了一定的优化,没有将常量的计算生成对应的计算指令,而是编译器直接将计算的结
果传入栈中,接下来再从栈中拿值
进行 O1优化以后
此时在上面的基础上,没有将结果放入栈中,由于后面 printf要使用该参数,直接传入 edx
后面通过 rdx直接传入 printf
复写传播
#include <iostream>
int main(int argc)
{
int nNum = argc;
printf("nNum = %d \n",nNum);
}
此时我们将 main函数的参数值赋给了 main中的变量 nNum
对于上述代码,如果没有进行优化,那么处理的逻辑为:
可以看到,为了将 edi中的的参数 1 (argc)放入到栈 nNum的位置,进行了很繁琐的操作
进行O1优化以后
直接删除掉了 nNum(因为之后没有对 nNum重新赋值) 用存在于 edi中刚刚传入的 argc
值直接代替他就完事了
后面调用 printf时,由于其已经被传入了 edi,若直接通过 rdi传给 printf就完事了,非常的简便
具体在代码中的优化
#include <cstdio>
#include <iostream>
int main()
{
int nVarOne = 0;
int nVarTwo = 0;
nVarOne = nVarOne + 1;
nVarOne = 1 + 2;
nVarOne = nVarOne + nVarTwo;
printf("nVarOne = %d \n",nVarOne);
return 0;
}
对于上述代码,如果没有进行优化,那么处理的逻辑为:
但还是在编译期间提前做了进行了简单的将常量的计算
进行O1优化以后
代码结构发生大变,处理的流程为:
常量替换变量,所以 nVarOne``nVarTwo开始都被直接替换为常量 0
接下来代码中对 nVarOne做了两次赋值操作,由于第二次赋值操作会覆盖第一次赋值的操作
所以直接去掉第一次赋值,第二次赋值为 3
再次用常量替换变量,由于 printf会使用到该参数,直接把 3 传入 edx,等待后续通过 rdx传入 printf即可
所以最终反映到汇编指令中,只有一条 mov edx,0x3实属省事啊。。。 |