编译原理 中间代码表示
控制流图在程序分析,程序优化中有重要的作用
将抽象层次逐渐降低,有的优化只能在特定的中间表示上才行。
三地址码:
不绑定特定的指令集,是抽象的类型
每个三地址码只完成一条指令,没有复合的情况出现。
如何生成三地址码?
F*代表0个或者多个F,正则文法,X是函数,可以有多个参数
S 函数体:内部可以再调用函数
x1中存放E的值。
控制流图
有多少个语句可以跳转到L2,实际上转化为了有向图中,L2的入度。
B就是block 基本块 名字,语句以及jump 跳转
F 函数 一个函数由多个基本块构成 入口块,出口块
控制流图包括了三地址码中的信息,并且增加了block,更加精细。
list 表明语句的链表
jump 地址跳转
three address code-> control flow graph
线性扫描算法
scan_stm 对三地址码的所有语句进行扫描
遇到跳转语句,则当前块跳转到j,并生成新的block,否则归并到block中。时间复杂度为O(n)
拓扑序只对有向无环图有意义,近似拓扑序对图的要求没有那么高。
L3死块 从入口块,走不到L3,即从L0出发,遍历不可达。
深度优先遍历所有的节点,并标记,未被标记的则为死块。
死块删除一般做在早期,方便后续处理。
数据流分析:
静态保守
到达定义分析
如x=y+y+1,那么虽然永远走不到L1,但是编译器是不知道的。
到达定义分析
定义和使用:
即判断哪些对变量值进行的更改能够传递到当前语句
gen 产生集合 表示当前的语句给出了什么样的定义
kill 杀死集合 即被当前定义点杀死的集合
常数传播优化,结合到达定义分析,会发现第一条语句的y=3,一直没有传递到5,6中。
这就是顺序对一个基本块中的所有语句进行分析。
不动点算法:
对于所有的基本块
在循环的计算过程中,只要有一个发生变化,就可能影响后面,因此要持续的对循环进行计算。
这是对每一句都进行分析,而不单单是block
不动点算法为什么会终止.....我感觉只要是静态的就一定会中止啊。
活性分析:
有交集的就不能共用一个寄存器了。
c=b+3,b和c可以共用一个寄存器r
变量在边上活跃:
return c 返回c是一定要在寄存器中的
从尾部向上推出活跃集合
观察每个活跃集合中的变量,即可明确需要几个寄存器。
in = 本块所使用的(依赖的)+(输出的-本块定义的)。后向!!!
每个语句都计算 in out两个集合,共n*2个集合
按照1,2,3,4,5,6的顺序进行计算
b黄色,与a红色不冲突,a恰好在内部没有使用寄存器的需要。
根据变量之间是否干扰,生成干扰图:
有边的变量相互冲突,不能共用一个寄存器,而a和b可以。
可以对图进行着色,即有几个寄存器就有几种色彩。