概览
- 优化
对中间代码进行等效变化,以便生成更有效的目标代码 - 局部优化
- 循环优化
10.1 概述
(关键是了解优化的三大原则(等价、有效、合算),其余内容不用看,在接下来的各个小节中都有详解)
10.2 局部优化
- 优化单位:基本块
- 划分基本块
- 优化方式:DAG无环图
- 删除公共子表达式
- 复写传播
- 删除无用代码
10.3 循环优化
- 优化方法
- 代码外提
- 强度消弱
- 删除归纳变量
10.4 数据流分析
略
10.1 概述
优化原则
- 等价原则
经过优化后不应改变程序运行的结果 - 有效原则
使优化后所产生的目标代码运行时间较短,占用内存空间较小 - 合算原则
应尽可能以较低的代价取得较好的优化效果
删除公共子表达式
避免对一个变量的重复计算
复写传播
如果一个临时变量由另一个变量赋值得到而不修改,则用该变量代替临时变量(大概)
删除无用代码
将对不再使用(运算结果无影响)的变量赋值代码删除
代码外提
将循环中引用的不变的变量提取到循环外
强度消弱
将与I具有线性的变量用加减法在每回合逐次加减替代
删除归纳变量
(和强度消弱一同处理)
利用必须保留的归纳变量(与I有线性关系的变量)替代I
10.2 局部优化
10.2.1 基本块及其流图
- 基本块
程序中一顺序执行的语句序列,只有一个入口和一个出口 - 定值
x : = y + z x:=y+z x:=y+z中的 x x x,为x定值 - 引用
x : = y + z x:=y+z x:=y+z中的 y y y、 z z z,引用y、z - 活跃的
一个变量的值在以后被引用(可以跨基本块) - 基本块内的优化/局部优化
局限于基本块内的优化 - 流图
有向图,按照跳转关系由一个基本块指向另一个基本块(流图即为DAG)
基本块的划分
基本块外的中间代码不会被读取使用,删除(删除无用赋值)
基本块入口的确定
- 程序入口
- 转移语句的目标语句
- 条件转移语句的下一条语句
基本块出口的确定
- halt(程序出口)
- 转移语句
- 另一基本块的入口的上一条语句
10.2.2 基本块的DAG表示及其应用
DAG(有向无环图)是的局部优化的实现基础
1. 如果没必要算的就不算了
2. 如果算过的就不算了
- 标记
- 附加信息
DAG组成
叶节点
n
i
n_i
ni:标识符(变量名)/常数
内部结点
n
i
n_i
ni:运算符(通常还有注记符T,用于确定其代表的值)
中间代码型式
- A := B
- A := op B
- A := B op C 或 A := B[C]
DAG构造&使用
DAG构造(合并已知变量、删除公共子表达式)
-
代码含(未知)变量
引用的变量/常量- 已存在
不操作,直接引用(合并已知变量) - 未存在
在最低层添加新节点 n i n_i ni表示该变量/常量(注意左右关系,A[B]类似op对顺序有要求,A要在B左侧)
op操作
- 已存在
不操作,直接引用,添加注释(删除公共子表达式)
(:=赋值操作,直接为用于赋值的节点添加注释) - 未存在
添加新节点 n i n_i ni表示该op(注意左右关系,理由同上)
- 已存在
-
代码含不含变量/变量已知
在最下一层创建新节点,用新节点直接代表计算后的结果(合并已知变量)
删除无用赋值
以基本块的活跃变量为根发展树,删除除树子树覆盖范围外的所有节点(该部分操作不影响基本块的运算结果)
10.3 循环优化
- 循环优化
- 循环
确定哪些基本块构成了循环
基本块在程序流图通过转移语句组成的“单向环”结构
10.3.1 代码外提
(简单说,就是一个不变的量在循环里被算/赋值了好多次,不如直接把它放在循环外,只在循环开始前做一次运算)
- 定值到达
流图中从一点a有一通路到达令一点b且该通路上没有变量C的其他定值
变量C的某点a的定值到达另一点b - 前置结点
将常量/不变量有关代码外提,生成前置结点
⋆ \star ⋆ 代码外提生成前置结点时,前置节点一般不包含转移语句,该操作有可能生成新的基本块,也有可能向上一个基本块添加新的元素,因此,可能在上一个基本块产生局部优化可能。 - 活跃变量
A的值在从b开始的某条通路上被引用(可以理解为这个变量出了循环还会被引用)
变量A的在程序中某点b是活跃变量
部分代码外提可能导致变量在循环结束后数值不同,若该变量不是活跃变量,则该修改可以接收
代码外提算法
- 求出循环L的所有不变运算
- 对步骤1求得的每一个不变运算s: A:=B op C 或 A := B,检查它是否满足一下条件
- 条件1
- s所在的结点是L的所有出口结点的必经结点(必经)
- A在L中其他地方未再定值(未再定值)
- L中所有A的引用点只有s中A的定值才能到达(专一到达)
- 条件2
- A在离开L后不再是活跃的
- A在L中其他地方未再定值(未再定值)
- L中所有A的引用点只有s中A的定值才能到达(专一到达)
- 条件1
- 按步骤(1)所找出的不变运算的顺序,依次把符合条件1/2的不变运算提到L的前直结点中。
(简单说,就是把定值提出去,再把由全定值变量计算得来的(也是定值)都提出去)
10.3.2 强度消弱
- 强度消弱
把程序中执行时间较长的运算替换为执行时间较短的运算- 加法替换乘法
- 加法多用常量
(主要针对的是用于跳出循环判断的变量i及其线性变量)
操作
- 寻找每次循环中自增一个常数的变量(i比较常见)
- 根据该变量寻找与其有线性关系的变量(T:=A*i+B)
- 将线性变量前提,原本代码修改为在相关自增变量后添加前提变量的自增常量指令(前提代码:T:=Ai+B / T:=Ai+B-A,原有位置:T:=T+A)
(这个前提结点中的代码如何选择根据具体题目判断)
10.3.3 删除归纳变量
(主要针对的是用于跳出循环判断的变量i及其线性变量)
- 删除归纳变量
(简单说,就是一般i在循环中只负责给线性变量赋值,而强调削弱已经把i和线性变量分开了,因此可以把i省去,用一个线性变量来判断跳出循环) - 基本归纳变量(I)
对变量I只有唯一形如 I : = I ± C I:=I\pm C I:=I±C的赋值,且其中C为循环不变量 - 归纳变量(J)
J = C 1 ∗ I ± C 2 J=C_1*I\pm C_2 J=C1∗I±C2
强度消弱后,将I基本归纳变量删除,用归纳变量替代,进行循环跳出的判断
10.4 数据流分析
略
- 全局数据流分析
10.4.1 任意路径数据流分析
- 向前流
10.4.2 全路径数据流分析
- 任意路径
- 全路径
- 可用性
- 可用的
10.4.3 数据流问题的分类
10.4.4 其他主要的数据流问题
- Ud-链
- Du-链
10.4.5 利用数据流信息进行全局优化
- 非常忙表达式
- 删除全局公共子表达式
- 活跃变量分析
- 未初始化变量分析
- 常量传播和复写传播