【编译之美】【5. 代码优化:数据流分析】

有些优化只能在全局优化中做,在本地优化中做不了,比如:

  • 代码移动(Code motion)能够将代码从一个基本块挪到另一个基本块,比如从循环内部挪到循环外部,来减少不必要的计算。(循环剥离)
  • 部分冗余删除(Partial Redundancy Elimination),把一个基本块给删除。

在做全局优化时,情况就要复杂一些:代码不是在一个基本块里简单地顺序执行,而可能经过控制流图(CFG)中的多条路径。我们来看一个例子(例子由 if 语句形成了两条分支语句):
在这里插入图片描述
基于这个 CFG,我们可以做全局的活跃性分析,从最底下的基本块开始,倒着向前计算活跃变量的集合(也就是从基本块 5 倒着向基本块 1 计算)。

这里需要注意,对基本块 1 进行计算的时候,它的输入是基本块 2 的输出,也就是{a, b, c},和基本块 3 的输出,也就是{a, c},计算结果是这两个集合的并集{a, b, c}。也就是说,基本块 1 的后序基本块,有可能用到这三个变量。这里就是与本地优化不同的地方,我们要基于多条路径来计算。

我们发现:全局优化总体来说跟本地优化很相似,唯一的不同,就是要基于多个分支计算集合的内容(也就是 V 值)。在进入基本块 1 时,2 和 3 两个分支相遇(meet),我们取了 2 和 3V 值的并集。这就是数据流分析的基本特征,你可以记住这个例子,建立直观印象。

不动点法

对于有环的情况,我们可以给每个基本块的 V 值都分配初始值,也就是空集合。
在这里插入图片描述
然后对所有节点进行多次计算,直到所有集合都稳定为止。第一遍的时候,我们按照 5-4-3-2-1 的顺序计算(实际上,采取任何顺序都可以),计算结果如下:
在这里插入图片描述
如果现在计算就结束,我们实际上可以把基本块 2 中的 d 变量删掉。但如果我们再按照 5-4-3-2-1 的顺序计算一遍,就会往集合里增加一些新的元素(在图中标的是橙色)。这是因为,在计算基本块 4 的时候,基本块 1 的输出{b, c, d}也会变成 4 的输入。这时,我们发现,进入基本块 2 时,活变量集合里是含有 d 的,所以 d 是不能删除的。
在这里插入图片描述
你再仔细看看,这个 d 是哪里需要的呢?是基本块 3 需要的:它会跟 1 去要,1 会跟 4 要,4 跟 2 要。所以,再次证明,1、2、3、4 四个节点是互相依赖的。

我们再来看一下,对于活变量集合的计算,当两个分支相遇的情况下,最终的结果我们取了两个分支的并集。
在这里插入图片描述
在上一讲,我们说一个本地优化分析包含四个元素:方向(D)、值(V)、转换函数(F)和初始值(I)。在做全局优化的时候,我们需要再多加一个元素,就是两个分支相遇的时候,要做一个运算,计算他们相交的值,这个运算我们可以用大写的希腊字母Λ(lambda)表示。包含了 D、V、F、I 和Λ的分析框架,就叫做数据流分析。

那么Λ怎么计算呢?研究者们用了一个数学工具,叫做“半格”(Semilattice),帮助做Λ运算。

半格可以画成图形,理解起来更直观,假设我们的程序只有 a, b, c 三个变量,那么这个半格画成图形是这样的:
在这里插入图片描述
沿着上面图中的线,两个值是可以比较大小的,按箭头的方向依次减少:{}>{a}>{a, b}> {a, b, c}。如果两个值之间没有一条路径,那么它们之间就是不能比较大小的,就像{a}和{b}就不能比较大小。

对于这个半格,我们把{}(空集)叫做 Top,Top 大于所有的其他的值。而{a, b, c}叫做 Bottom,它是最小的值。

在做活跃性分析时,我们的Λ运算是计算两个值的最大下界(Greatest Lower Bound)。怎么讲呢?就是比两个原始值都小的值中,取最大的那个。{a}和{b}的最大下界是{a, b},{a, b, c} 和{a, c}的最大下界就是{a, b, c} 。

常数传播

常数传播,就是如果知道某个变量的值是个常数,那么就把用到这个变量的表达式,都用常数去替换。看看下面的例子,在基本块 4 中,a 的值能否用一个常数替代?
在这里插入图片描述
答案是不能。到达基本块 4 的两条路径,一条 a=3,另一条 a=4。我们不知道在实际运行的时候,会从哪条路径过来,所以这个时候 a 的取值是不确定的,基本块 4 中的 a 无法用常数替换。

那么,运用数据流分析的框架怎么来做常数传播分析呢?

在这种情况下,V 不再是一个集合,而是 a 可能取的常数值,但 a 有可能不是一个常数啊,所以我们再定义一个特殊的值:Top(T)。

除了 T 之外,我们再引入一个与 T 对应的特殊值:Bottom(它的含义是,某个语句永远不会被执行)。总结起来,常数传播时,V 的取值可能是 3 个:

  • 常数 c
  • Top:意思是 a 的值不是一个常数
  • Bottom:某个语句不会被执行。

这些值是怎么排序的呢?最大的是 Top,中间各个常数之间是无法比较的,Bottom 是最小的。

在这里插入图片描述
接下来,我们看看如何计算多个 V 值相交的值。

我们再把计算过程形式化一下。在这个分析中,当我们经过每个语句的时候,V 值都可能发生变化,我们用下面两个函数来代表不同地方的 V 值:

  • C(a, s, in)。表示在语句 s 之前 a 的取值,比如,C(a, b:=a+2, in) = 3。
  • C(a, s, out)。表示在语句 s 之后 a 的取值,比如,C(a, a:=4, out) = 4。
  1. 如果输入是 Bottom,那么输出也是 Bottom。也就是这条路径不会经过。
  2. 如果该 Statement 就是“ a := 常数”,那么输出就是该常数。3. 如果该 Statement 是 a 赋予的一个比较复杂的表达式,而不是常数,那么输出就是 Top。
  3. 如果该 Statement 不是对 a 赋值的,那么 V 值保持不变。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值