其他分享
首页 > 其他分享> > 【编译原理笔记16】代码优化:流图,常用代码优化方法, 基本块的优化

【编译原理笔记16】代码优化:流图,常用代码优化方法, 基本块的优化

作者:互联网

本次笔记内容:
8-1 流图
8-2 常用代码优化方法一
8-3 常用代码优化方案二
8-4 基本快的优化

本节课幻灯片,见于我的 GitHub 仓库:第16讲 代码优化_1.pdf

文章目录

流图

基本块(Basic Block)

基本块是满足下列条件的最大连续三地址指令序列:

基本块划分算法

输入:

输出:

方法:

  1. 指令序列的第一个三地址指令是一个首指令
  2. 任意一个条件或无条件转移指令的目标指令是一个首指令
  3. 紧跟在一个条件或无条件转移指令之后的指令是一个首指令


如上是快速排序法的部分源代码。

根据跳转指令找首指令(如跳转指令后的一条指令)。

流图(Flow Graphs)

此时称B是C的前驱(predecessor) ,C是B的后继(successor)。

有两种方式可以确认这样的边:



感觉像是描述各个运算部分的关系。

常用的代码优化方法(1)

优化的分类

常用的优化方法

①删除公共子表达式

公共子表达式:


将 B3 重构如黄色区域。


由 B3 “逆流而上”,发现 4 ∗ i 4*i 4∗i 没有被修改过,则其是一个公共子表达式。

进行了再次的画家如上。

发现 a [ t 2 ] a[t_2] a[t2​] 与 a [ t 4 ] a[t_4] a[t4​] 也是公共子表达式。




a [ t 1 ] a[t_1] a[t1​]能否作为公共子表达式?

把 a [ t 1 ] a[t_1] a[t1​]作为公共子表达式是不稳妥的,因为控制离开 B 1 B_1 B1​进入 B 6 B_6 B6​之前可能进入 B 5 B_5 B5​,而 B 5 B_5 B5​有对 a a a的赋值。



关键问题:如何自动识别公共子表达式?

会在后面的课程详细介绍。

常用的代码优化方法(2)

②删除无用代码

复制传播:常用的公共子表达式消除算法和其它一些优化算法会引入一些复制语句(形如x=y的赋值语句)


复制传播:在复制语句x= y之后尽可能地用y代替x。

无用代码(死代码Dead-Code):其计算结果永远不会被使用的语句。


程序员不大可能有意引入无用代码,无用代码通常是因为前面执行过的某些转换而造成的。

如何自动识别无用代码?

也将在后文详细介绍。

如上,通过删除公共子表达式删除无用代码,将 B5 与 B6 简化了不少。

③常量合并(Constant Folding)

如果在编译时刻推导出一个表达式的值是常量,就可以使用该常量来替代这个表达式。该技术被称为常量合并

④代码移动(Code Motion)

这个转换处理的是那些不管循环执行多少次都得到相同结果的表达式(即循环不变计算,loop-invariant computation) ,在进入循环之前就对它们求值。


如何自动识别循环不变计算?

循环不变计算的相对性

对于多重嵌套的循环,循环不变计算是相对于某个循环而言的。可能对于更加外层的循环,它就不是循环不变计算。

⑤强度削弱(Strength Reduction)

用较快的操作代替较慢的操作,如用加代替乘。

循环中的强度削弱

对于一个变量x ,如果存在一个正的或负的常数c使得每次x被赋值时它的值总增加c ,那么x就称为归纳变量(Induction Variable)。


归纳变量可以通过在每次循环迭代中进行一次简单的增量运算(加法减法)来计算。

⑥删除归纳变量

在沿着循环运行时,如果有一组归纳变量的值的变化保持步调一致,常常可以将这组变量删除为只剩一个。


如上, i i i 与 j j j 都无用了。

基本块的优化

很多重要的局部优化技术首先把一个基本块转换成为一个无环有向图(directed acyclic graph,DAG)。

基本块的 DAG 表示

基本块中的每个语句s都对应一个内部结点N:

例,有基本块:

a = b + c
b = a - d
c = b + c
d = a - d


对于形如 x=y+z 的三地址指令,如果已经有一个结点表示 y+z,就不往 DAG 中增加新的结点,而是给已经存在的结点附加定值变量x。

基于基本块的 DAG 删除无用代码

从一个DAG上删除所有没有附加活跃变量(活跃变量是指其值可能会在以后被使用的变量)的根结点(即没有父结点的结点) 。重复应用这样的处理过程就可以从DAG中消除所有对应于无用代码的结点。

数组元素赋值指令的表示


如上,因为有可能出现 i = j i=j i=j ,因此不能轻易把 a [ i ] a[i] a[i] 算作公共子表达式。

根据基本块的DAG可以获得一些非常有用的信息

从 DAG 到基本块的重组

对每个具有若干定值变量的节点,构造一个三地址语句来计算其中某个变量的值。

倾向于把计算得到的结果赋给一个在基本块出口处活跃的变量(如果没有全局活跃变量的信息作为依据,就要假设所有变量都在基本块出口处活跃,但是不包含编译器为处理表达式而生成的临时变量)。

如果结点有多个附加的活跃变量,就必须引入复制语句,以便给每一个变量都赋予正确的值。


构建 DAG 如右边。常量直接标记出来。

最终,根据 DAG 得到优化后的基本块如下:

D = A + C
E = A * C
F = E + D
L = 15 + F

标签:结点,DAG,变量,16,基本块,代码优化,指令,表达式
来源: https://blog.51cto.com/u_15279775/2936196