CH8.1 编译器自动优化
2019-05-14 本文已影响0人
磊宝万岁
编译器能做什么
1. Function inlining
对于一些比较简单的函数,编译器会直接进行inlining, 即使你的代码里并没有声明该函数是inline的。但是为了保险还是把需要inline的函数声明为inline为好。
函数内联的好处是
(1). 节省函数跳转的时间
(2). 有利于code caching
(3). 有利于后续的编译器优化
当然也有坏处,就是如果某函数调用次数过多或者被内联的函数很长的情况下会使得代码变得过大.
2. 简单的常数计算
编译器会在编译阶段把你代码里的一些常数计算的结果给算出来.
比如
double a, b;
a = b + 2.0/3.0;
编译完成会变成这样:
double a, b;
a = b + 0.666666666666666667;
注意:有时候你需要做一些显式的的指示,比如 b2.0/3.0 编译器会认为计算是从左往右计算的(事实也是这样,为了保证不丢精度),这样就不会进行提前计算,所以如果你想再编译阶段进行计算的话你需要显示的加括号:b(2.0/3.0)。这样就不会有上述问题了。
一些简单的函数编译器会直接inline进去的,像sqrt、pow这样的,但是一些比较麻烦的像sin函数就不会inline进去。
3. Pointer elimination
如果Pointer 或者reference指向的内容是已知的话,编译器可能会把指针给消除掉,其实就是相当于inline了函数。
void Plus2(int *p){
*p = *p + 2;
}
int a;
Plus2(&a);
编译器会优化成:
a += 2;
4. 多次相同运算只算一次
int a, b, c;
b = (a+1) * (a+1);
c = (a+1) * 4;
可以优化成如下:
int a, b, c, temp;
tmp = 1 + a;
b = tmp * tmp;
c = tmp * 4;
5. 寄存器变量
一般来说32位系统中有6个整数寄存器8个浮点数寄存器,在64位系统中有14个整数寄存器16个浮点数寄存器。不包括XMM、YMM、ZMM这些向量寄存器。
- 如果一个变量被引用了的话(不论是通过pointer还是reference)那么这个变量就不可能被放到寄存器里。所以说如果你想让让某个变量放到寄存器来加速程序的话就不要使用它的引用或者指针。