课程主页:

https://www.edx.org/course/compilers

课程视频:

https://www.bilibili.com/video/BV1NE411376V?p=20&t=6

备注:

图片均来自于课件。

这次回顾全局优化。

数据流分析

简介

  • 回顾简单的基本块优化

    • 常数传播

    • 消除死亡代码

  • 这些优化可以扩展到整个控制流图

  • 我们如何知道可以全局传播常量?

  • 要用常数$\mathrm k$代替$\mathrm x$的使用,我们必须知道:

    • 在使用$\mathrm x$的每条路径上,对$\mathrm x$的最后一个赋值是$\mathrm {x:= k}$

  • 正确性条件不容易检查

  • 因为“所有路径”包括循环的路径以及通过条件分支的路径

  • 检查条件需要全局数据流分析

    • 以及整个控制流图的分析

全局优化

  • 全局优化任务具有以下几个特征:

    • 优化取决于在程序执行的特定点上知道属性$\mathrm X$
    • 在任何时候证明$\mathrm X$都需要整个程序的知识
    • 优化可以是保守的,我们需要知道如下三个事实之一
      • $\mathrm X$绝对正确
      • 不知道$\mathrm X$是否正确
      • 说“不知道”总是安全的
  • 全局数据流分析是解决具有这些特征的问题的标准技术

  • 全局常数传播是需要全局数据流分析的优化例子之一

常数传播

常数传播是指将变量用常数替换的方法,但是,要用常数$\mathrm k$代替$\mathrm x$的使用,我们必须知道:在使用$\mathrm x$的每条路径上,对$\mathrm x$的最后一个赋值是

  • 可以在性质$\star\star$成立的任何位置执行全局常数传播。
  • 考虑在所有程序点为单个变量$\mathrm X$计算$\star\star$的情况。

为了使问题更精确,我们在每个程序点将以下值之一与$\mathrm X$关联:

解释
$\perp$ 该语句从未执行
$\mathrm c$ $\mathrm{X=c}$($\mathrm c$为常数)
$\mathrm T$ $\mathrm X$不是常数

问题描述

  • 给定全局常数信息,可以轻松执行优化
    • 只需检查$\mathrm {x =?}$ ,使之与使用$\mathrm x$的语句相关联
    • 如果$\mathrm x$在那个点是常数,则用常数代替对$\mathrm x$的使用

基本规则

  • 但是我们如何计算属性$\mathrm {x =?}$

  • 可以将复杂程序的分析表示为相邻语句之间信息更改的简单规则组合

  • 想法是将信息从一个语句“推送”或“转移”到下一个语句

  • 对于每个语句$\mathrm s$,我们计算紧跟在$\mathrm s$之前和之后的$\mathrm x$值的信息

  • 定义将信息从一个语句传递到另一个语句的传递函数

  • 在以下规则中,令语句$\mathrm s$的前驱语句为$\mathrm{p_1,\ldots,p_n}$

规则1

规则图示:

规则描述:

规则2

规则图示:

规则描述:

规则3

规则图示:

规则描述:

规则4

规则图示:

规则描述:

  • 规则1-4指定语句结果和后续语句输入的关系
  • 现在,我们需要将语句的输入与同一语句的输出相关的规则
规则5

规则图示:

规则描述:

规则6

规则图示:

规则描述:

规则7

规则图示:

规则描述:

规则8

规则图示:

规则描述:

应用

  1. 对于程序的每个入口$\mathrm s$,设置$\mathrm{C(s,x,in)=T}$
  2. 在其他所有地方设置$\mathrm{C(s,x,in)=C(s,x,out)=\perp}$
  3. 重复,直到所有点都满足1-8:
    • 选择不满足1-8的$\mathrm s$并使用适当的规则进行更新

例子

习题

选择第三项。

循环分析

$\perp$的必要性

为了理解为什么需要$\perp$,考虑循环

  • 考虑语句$\mathrm{Y:=0}$
  • 要计算此时$\mathrm{X}$是否恒定,我们需要知道$\mathrm X$在两个前驱语句中是否恒定
    • $\mathrm{X:= 3}$
    • $\mathrm {A:= 2 \star X}$
  • 但是$\mathrm {A:= 2 \star X}$的信息取决于其前驱语句,包括$\mathrm{Y:=0}$
  • 由于循环的缘故,所有点必须始终具有值
  • 直观上,分配一些初始值可以使分析中断循环
  • 初始值$\perp$表示“到目前为止,控制流没有到达这一点”

例子

习题

选择第三项。

排序

引入排序

  • 我们可以通过对值进行排序来简化分析的表示方式,这里假设

  • 画图得到

分析

  • $\mathrm T$最大值,$\perp$是最小值

  • 所有常数都介于两者之间并且无法比较

  • 令$\mathrm{lub}$是在此排序下的最小上界:

  • 规则1-4可以使用$\text{lub}$简化:

说明

  • 之前简单地说“重复直到没有改变”并不能保证循环会终止
  • 使用$\mathrm{lub}$解释了为什么算法终止
    • 值以$\perp$开始,并且只会增加
    • $\perp$会变成为常数,而常数可以变成为$\mathrm T$
    • 因此,$\mathrm{C(s,x,in),C(s,x,out)}$最多会改变两次
  • 因此,常数传播算法的时间复杂度关于的程序大小是线性的
  • 步骤数 = $\mathrm{C(….)}$计算数量$\times 2$ = 程序语句的数量$\times 4$

生存分析

常量在全局范围内传播后,我们希望消除无效代码:

常数传播后,$\mathrm{X:=3}$消失(假设$\mathrm X$在其他地方未使用)

例子

  • $\mathrm x$的第一个值dead(从未使用)
  • $\mathrm x$的第二个值live(可能使用)
    • live = 可能在未来使用
  • 生存性是一个重要概念

概念介绍

live
  • 变量$\mathrm x$在语句$\mathrm s$处live,如果
    • 存在使用$\mathrm x$的语句$\mathrm s’$
    • 从$\mathrm s$到$\mathrm s’$之间有一条道路
    • 该路径没有对$\mathrm x$的中间分配

dead
  • 语句$\mathrm {x:= …}$为dead代码,如果$\mathrm x$在赋值后为$\mathrm {dead}$
  • dead语句可以从程序中删除
  • 但是我们首先需要liveness信息
小结
  • 我们可以用相邻语句之间传递的信息来表达liveness,就像复制传播一样
  • liveness比常数传播更简单,因为它是一个布尔属性(true或false)

规则

规则1

规则图示:

规则描述:

规则2

规则图示:

规则描述:

规则3

规则图示:

规则描述:

规则4

规则图示:

规则描述:

处理步骤

  1. 最初让所有$\text{L(…) = false}$
  2. 重复直到所有语句都满足规则1-4
    • 选择规则1-4之一不成立的$\mathrm s$,并使用适当的规则进行更新

例子

小结
  • 值可以从false更改为true,但不能相反
  • 每个值只能更改一次,因此可以保证终止
  • 一旦完成分析,就很容易消除无效代码

习题

选择$X,W$。

小结

  • 我们已经看到了两种分析:
    • 常数传播是一种前向分析:信息从输入推送到输出
    • liveness是一种后向分析:信息从输出推回到输入
  • 还有许多其他全局流分析
  • 大多数可以分为前向或后向
  • 大多数还遵循与相邻程序点之间的信息相关的本地规则方法