纯纯傻逼课
从数学上讲, 为给定源程序生成一个最优的目标程序是不可判定问题. 但还好我们有一系列较为可靠的启发式算法.
代码生成器主要有三个任务: 指令选择, 寄存器分配, 指令排序.
Chapter-8: 代码生成和优化
8.1 基本块的划分
- 基本块是程序中最大限度顺序执行的语句序列,其中只有一个入口和出口,入口是其第一个语句,出口是其最后一个语句
- 基本块的入口语句可能是
- 程序的第一个语句
- 跳转的目标语句
- 条件跳转的下一条语句
- 基本块的结束语句可能是
- 停机语句
- 跳转语句
- 跳转目标语句的前一个语句(词法序)
- 基本块的入口语句可能是
构造方法:
- 确定首指令:
- 中间代码的第一个三地址指令是一个首指令
- 任意一个条件或无条件转移指令的目标指令是一个首指令
- 紧跟在一个条件或无条件转移指令之后的指令是一个首指令
- 每个首指令对应的基本块包括了从它自己开始,直到下一个首指令(不含)或者中间程序的结尾指令之间的所有指令
过程调用语句作为一个新的基本块的开始,甚至独立成为一个基本块
8.2 三地址语句中名字的使用(use)定义
- 假定三地址语句i把a的值赋给x,如果语句j用x作为运算对象,并且控制从i流到j,这条路径中没有x的其它赋值,则称j引用x在i定的值
- 此时,称x在语句i处活跃(live)
确定算法:
- 输入:一个三地址语句的基本块B,假设在基本块B开始时,所有的非临时变量都是活跃的
- 输出:对于每一个语句i:x = y op z,将x、y及z的活跃性信息及后续使用信息关联到i
- 方法:从基本块B的最后一个语句开始,反向扫描到B的开始处。对每一个三地址语句 i:x := y op z,依次执行下述步骤:
- 把当前符号表中x、y和z的后续使用信息和活跃信息附加到语句i上;(若x不活跃,则这个语句可以删掉)
- 在符号表中设置x为“无后续使用”和“不活跃”;
- 把符号表中y和z的后续使用信息均置为i,活跃信息均置为“活跃”。
目前还不知道有什么用???????
8.3 基本块内优化
采用DAG表示
8.3.1 消除局部公共子表达式
- 方法:检测公共子表达式的“值编码”方法
- 当一个新的结点M将被加入到DAG中时
- 检查是否存在一个结点N,它和M具有同样的运算符和子结点,且子结点顺序相同
- 若存在,则N计算的值和M计算的值是一样的,可以用N替换M
如果有不活跃的公共表达式, 则可以删除一个. 如果都活跃, 则必须要有赋值语句去复制.
这种对不活跃的考察, 就是删除死代码
8.3.2 代数恒等式的使用
- 局部强度削弱: 如 x^2 -> x*x
- 常量合并
- 交换律结合律检查
8.3.3 数组引用的表示
对数组而言, 情况较为不同, 比如下列式子:
x = a[ i ];
a[ j ] = y;
z = a[ i ];
其中a[i]
并不是CSE, 因为i=j
有可能成立.
在DAG中, 表示数组访问如下:
- 取数组元素的右值(如x = a[ i ]),用新创建的运算符为=[ ]的结点表示,其左右子结点分别代表数组初始值(本例中为a0)和下标i,变量x是该结点标号之一
- 取数组元素的左值(如a[ j ] = y),用新创建的运算符为[ ]=的结点表示,这个结点的三个子结点分别表示a0 、j和y,没有变量用这个结点标号
- 左值结点的创建杀死了所有当前已建立的,其值依赖于a0的结点
- 被杀死的结点都不再有标号,且不能作为CSE
8.4 控制节点
控制结点(必经结点)描述了流图上如下关系
- 控制节点
- n是m的控制节点(n dominates m)
- 当且仅当, 从root到m的所有路径都经过n(想到m必须先到n)
- 控制关系构成偏序集
- 后控制节点
- n是m的后控制节点(n post-dominates m)
- 当且仅当, 从m到exit的所有路径都经过n(m想离开必须经过n)
- 控制关系构成偏序集
到达-定值的迭代算法
变量x的定值:是一个语句,它(可能)赋值给x
- 无二义的定值:语句真正对x定一个值
- 二义的定值:
- x作为形式参数,或由于别名的关系
- 通过引用x的指针对x赋值 变量a的定值d到达一点p:如果有路径从紧跟d的点到达p,并且在这条路径上d没有被注销 定值的注销:如果在这条路径上有对变量a的其它定值,则称前面的定值被注销
- 只有控制结点的无二义的定值才能注销其它的定值
- 到达-定值可能是不精确的
几个集合:
- gen[B]:基本块B中的定值d到达B的结束点,则d∈gen[B]
- kill[B]:程序中不能到达B的结束点的定值d,则d∈kill[B]
- in[B]:到达B的开始点的定值集合
- out[B]:到达B的结束点的定值集合
例子如下:
可用表达式
- 表达式x+y在点p可用:如果从初始结点到p的每条路径上(不必是无环)都计算x+y,并且在最后一个这样的计算和p之间没有对x或y的赋值
- 基本块注销表达式x+y:如果它对x或y赋值(或可能赋值),并且随后没有重新计算x+y
- 基本块产生表达式x+y:如果它计算x+y,并且随后没有重新对x或y定义
对每个基本块有:
- in[B]:块B开始点的可用表达式集合
- out[B]:块B结束点的可用表达式集合
- e_gen[B]:块B生成的可用表达式集合
- e_kill[B]:U中被块B注销的可用表达式集合
活跃变量分析
活跃变量:反向计算流信息
- 如果对于变量x和点p,x的值在由p点开始的路径上是否引用,如果引用,则称x在p点活跃
- 否则称x在p点死亡
- 如果寄存器中的值在基本块结束死亡,则不用写回内存,这个寄存器也可以优先被分配它用 几个集合
- in[B]:块B开始点的活跃变量集合
- out[B]:块B结束点的活跃变量集合
- def[B]:块B中无二义定值且在该定值前没有引用的变量集
- use[B]:块B中可能引用且在该引用前没有定值的变量集