gcc hello.c -o hello
./hello
Hello, World!
constant folding 常量折叠 (提高执行速度)
把常量表达式在编译时进行运算,程序运行时就可以省略这次运算,获得更快执行速度。
algebraic simplification 代数简化
利用表达式的数学性质,对表达式进行简化。 x*1 x+0 x-0 相当于x, 直接替换成x,。
x*0,用0来代替。
common-subexpression elimination 削除公共子表达式
把多次运算压缩为一次运算,提取出公共子表达式,这样不需要重复计算多次。
dead code elimination 消除无效语句
删除程序中逻辑上执行不到的指令
function inlining 函数内联
把小的函数体直接嵌入到函数调用处,使得函数调用的作用域归零的方法。 注意,如果这个函数是全局的,编译时的优化仅限于同一个文件中定义的函数调用,如果想对程序中所有函数调用都进行函数内敛,那么链接时也需要进行代码优化。
根据优化目的来分类 1,减少执行的指令数:常量折叠。 2,使用更快速的指令:乘法运算换成位移运算,降低运算强度。 3,并行地执行指令:不存在依赖关系的指令同时执行。
寄存器访问速度 比内存访问速度更快,多用寄存器,减少使用访问内存指令。
根据作用范围的优化分类
1, 专注于优化程序的某一部分 local optimization
针对于一部分机器码的指令进行优化窥视孔优化,peep-hole optimization. 将惩罚运算转换成位移运算也算是一种peep-hole optimization。
2,对全局程序进行优化 global optimization 至少以函数为单位的优化。 函数内联
局部优化更为简单,有时候得到的优化效果却更好,是非常实惠的优化方法。
基于作用阶段的优化
编译器可以从以下几个时间节点进行优化。
1,语义分析后,针对抽象语法树的优化
2,生成中间代码后,针对中间代码的优化
3,生成汇编代码后,针对汇编代码的优化
4,连接后,针对程序整体的优化。
越早进行优化,越能针对语言结构,语义进行优化。
抽象语法树阶段,可以简单识别循环,这阶段对循环进行优化。
在中间代码阶段,可以进行语言无关的优化,该阶段可以局部优化,也可以全局优化。
一旦编译成汇编代码,就很难进行大范围优化,只能集中在peep-hole 优化了。
链接后优化:构成程序主体的各种处理流程(function)已经固定,可以对程序整体进行大范围的解析优化。 Intel c compiler, Microsoft Visual Studio 链接时优化。
instruction selection by pattern matching
把中间代码的树,根据预先定义的节点的模式进行分割,从而生成指令,基于模式匹配选择指令。
用好寄存器也是很好的优化,减少内存访问,给局部变量,临时变量分配寄存器 (register allocation)。充分利用为数不多的寄存器,就必须灵活的在不同变量间重复利用寄存器。
为了判断某个寄存器是否同时被两个变量使用,需要分析变量的性质,liveness analysis. 在此基础上使用 graph coloring 的算法来分配寄存器。
CFG分析,以bb为单位。
为对单个函数或者多个函数优化,对代码整体数据流分析,(这个表达式中计算的值在哪了被使用了),使用SSA形式(static single assignment form),这种中间代码形式超越了基本代码块范围的数据流分析。
SSA形式,为了使每个变量只会被赋值(初始化)一次,而为变量起一个别名,并将变量变形。
变量的值非常明确,
代码的Meta info 包括: 代码size,转换前的源代码文件名,符号,重定位信息,调试信息。
symbol, 变量或者函数的名称。
LINK 就是把多个目标文件关联为一个整体。 关联多个目标文件,可以生成使用多个目标文件定义的变量,函数。
relocation 根据程序实际加载到内存时的地址,对目标文件中的代码和数据进行调整。
Comments