0%

编译原理-代码优化3

阅读更多

1 活跃变量分析

活跃变量

  • 对于变量$x$和程序点$p$,如果在流图中沿着从$p$开始的某条路径会引用变量$x$在$p$点的值,则称变量$x$在点$p$是活跃live)的,否则称变量$x$在点$p$是不活跃dead)的

fig1

1.1 活跃变量信息的主要用途

删除无用赋值

  • 无用赋值:如果$x$在点$p$的定值在基本块内所有后继点都不被引用,且$x$在基本块出口之后又是不活跃的,那么$x$在点$p$的定值就是无用的

为基本块分配寄存器

  • 如果所有寄存器都被占用,并且还需要申请一个寄存器,则应该考虑使用已经存放了死亡值的寄存器,因为这个值不需要保存到内存
  • 如果一个值在基本块结尾处是死的不必在结尾处保存这个值

1.2 活跃变量的传递函数

活跃变量是一个典型的逆向数据流问题

$$IN[B] = f_B(OUT[B]$$

其中,$f_B(x) = use_B \cup (x-def_B)$

  • $def_B$:在基本块B中定值,但是定值前在B中没有被引用的变量的集合
  • $use_B$:在基本块B中引用,但是引用前在B中没有被定值的变量集合

fig2

1.3 活跃变量数据流方程

符号及其说明

  1. $IN[B]$:在基本块B的入口处的活跃变量集合
  2. $OUT[B]$:在基本块B的出口处的活跃变量集合

方程

  • $IN[EXIT] = \Phi$
  • $IN[B] = f_B(OUT[B]) ( B \ne EXIT )$
  • $f_B(x) = use_B \cup (x-def_B)$
  • $OUT[B]= \cup_{S是B的一个后继}\;\;\;\;\;\;\;\;IN[S], ( B \ne EXIT )$

1.4 计算活跃变量的迭代算法

输入:流图G,其中每个基本块B的$use_B$和$def_B$都已计算出来

输出:$IN[B]$和$OUT[B]$

方法:

  • fig3

例子

fig4

1.5 定值-引用链(Definition-Use Chains)

定值-引用链:设变量$x$有一个定值$d$,该定值所有能够到达的引用$u$的集合称为$x$在$d$处的定值-引用链,简称$du$链

如果在求解活跃变量数据流方程中的$OUT[B]$时,将$OUT[B]$表示成从B的末尾处能够到达的引用的集合,那么,可以直接利用这些信息计算基本块B中每个变量$x$在其定值处的$du$链

  • 如果B中$x$的定值$d$之后有$x$的第一个定值$d^{\prime}$,则$d$和$d^{\prime}$之间$x$的所有引用构成$d$的$du$链
  • 如果B中$x$的定值$d$之后没有$x$的新的定值,则B中$d$之后$x$的所有引用以及$OUT[B]$中$x$的所有引用构成$d$的$du$链

2 可用表达式分析

可用表达式

  • 如果从流图的首节点到达程序点$p$的每条路径都对表达式$x\;op\;y$进行计算,并且从最后一个这样的计算到点$p$之间没有再次对$x$或$y$定值,那么表达式$x\;op\;y$在点$p$是可用的(available)

表达式可用的直观意义

  • 在点p上,x op y已经在之前被计算过,不需要重新计算

2.1 可用表达式信息的主要用途

  1. 消除全局公共子表达式
  2. 进行复制传播
    • fig5
    • 在$x$的引用点$u$可以用$y$代替$x$的条件:从流图的首节点到达u的每条路径都存在复制语句$x = y$,并且从最后一条复制语句$x = y$到点$u$之间没有再次对$x$或$y$定值(就是可用表达式的定义)

2.2 可用表达式的传递函数

对于可用表达式数据流模式而言,如果基本块B对$x$或者$y$进行了(或可能进行)定值,且以后没有重新计算$x\;op\;y$,则称B杀死表达式$x\;op\;y$。如果基本块B对$x\;op\;y$进行计算,并且之后没有重新定值$x$或$y$,则称B生成表达式$x\;op\;y$

传递函数定义如下:

  • $f_B(x)= e\_gen_B ∪(x- e\_kill_B)$
  • $e\_gen_B$ :基本块B所生成的可用表达式的集合
  • $e\_kill_B$ :基本块B所杀死的U中的可用表达式的集合
  • $U$:所有出现在程序中一个或多个语句的右部的表达式的全集

2.3 $e\_gen_B$的计算

初始化:$e\_gen_B = \Phi$

顺序扫描基本块的每个语句:$z = x\;op\;y$

  1. 把$x\;op\;y$加入$e\_gen_B$
  2. 从$e\_gen_B$中删除和$z$相关的表达式
  • 上述两个操作顺序不能颠倒

2.4 $e\_kill_B$的计算

初始化:$e\_kill_B = \Phi$

顺序扫描基本块的每个语句:$z = x\;op\;y$

  1. 从$e\_kill_B$中删除表达式$x\;op\;y$
  2. 把所有和$z$相关的表达式加入到$e\_kill_B$中

2.5 可用表达式的数据流方程

符号及其说明

  1. $IN[B]$:在B的入口处可用的$U$中的表达式集合
  2. $OUT[B]$:在B的出口处可用的$U$中的表达式集合

方程

  • $OUT[ENTRY]= \Phi$
  • $OUT[B]=f_B(IN[B]), ( B \ne ENTRY )$
    • $f_B(x)= e\_gen_B \cup (x- e\_kill_B)$
  • $IN[B]= \cap_{P是B的一个前驱}\;\;\;\;\;\;\;OUT[P], ( B \ne ENTRY )$

2.6 计算可用表达式的迭代算法

输入:流图G,其中每个基本块B的$e\_gen_B$和$e\_kill_B$都已计算出来

输出:$IN[B]$和$OUT[B]$

方法:

  • fig6

2.6.1 为什么将$OUT[B]$集合初始化为$U$

将OUT集合初始化为$\Phi$局限性太大

  • fig7

如果$OUT[B_2]^0 = \Phi$

  • 那么$IN[B_2]^1= OUT[B_1]^1 \cap OUT[B_2]^0 = \Phi$

如果$OUT[B_2]^0 = U$

  • 那么$IN[B_2]^1= OUT[B_1]^1 \cap OUT[B_2]^0 = OUT[B_1]$

3 参考

  • 《MOOC-编译原理-陈鄞》