【编译原理笔记18】代码优化:活跃变量分析,可用表达式分析
作者:互联网
本次笔记内容:
8-8 活跃变量分析
8-9 可用表达式分析
本节课幻灯片,见于我的 GitHub 仓库:第18讲 代码优化_3.pdf
文章目录
活跃变量分析活跃变量
对于变量x
和程序点p
,如果在流图中沿着从p
开始的某条路径
会引用变量x
在p
点的值,则称变量x
在点p是活跃
(live)的,否则称变量x
在点p不活跃
(dead)。
例:各基本块的出口处的活跃变量
有再次定值(且定值与本身无关),则不活跃。
活跃变量信息的主要用途
删除无用赋值:
-
无用赋值
:如果x在点p的定值在基本块内所有后继点都不被引用,且x在基本块出口之后又是不活跃
的,那么x在点p的定值就是无用的。
为基本块分配寄存器:
- 如果
所有寄存器都被占用
,并且还需要申请一个寄存器,则应该考虑使用已经存放了死亡值的寄存器,因为这个值不需要保存到内存; - 如果一个值
在基本块结尾处是死的
就不必在结尾处保存这个值
。
活跃变量的传递函数
逆向数据流问题: I N [ B ] = f B ( O U T [ B ] ) IN[B] = f_B(OUT [B]) IN[B]=fB(OUT[B])
f B ( x ) = u s e B ∪ ( x − d e f B ) f_B (x) = use_B \cup(x-def_B) fB(x)=useB∪(x−defB)
-
d
e
f
B
def_B
defB:在基本块
B
B
B中定值,但是
定值前
在 B B B中没有被引用
的变量的集合; -
u
s
e
B
use_B
useB:在基本块
B
B
B中引用,但是
引用前
在 B B B中没有被定值
的变量集合。
例:各基本块B的use_B和def_B
如上依次构建各表达式的
u
s
e
use
use 与
d
e
f
def
def 集合,很直观。
活跃变量数据流方程
I
N
[
B
]
IN[B]
IN[B]:在基本块B的入口处的活跃变量集合;
O
U
T
[
B
]
OUT[B]
OUT[B]:在基本块B的出口处的活跃变量集合。
u
s
e
B
use_B
useB和
d
e
f
B
def_B
defB的值可以直接从流图计算出来,因此在方程中作为已知量
。
计算活跃变量的迭代算法
- 输入:流图G,其中每个基本块B的 u s e B use_B useB和 d e f B def_B defB都已计算出来
- 输出: I N [ B ] IN[B] IN[B]和 O U T [ B ] OUT[B] OUT[B]
例
如上,依次迭代,得到最后的
I
N
[
B
]
IN[B]
IN[B]和
O
U
T
[
B
]
OUT[B]
OUT[B]。由 OUT 值,得到各个基本块的活跃变量。结果与人工分析的结果一致。
定值-引用链(Definition-Use Chains)
- 定值-引用链:设变量x有一个定值d,该定值所有能够到达的引用u的集合称为x在d处的
定值-引用链
,简称du链
。 - 如果在求解
活跃变量
数据流方程中的OUT[B]时,将OUT[B]表示成从B的末尾处能够到达的引用的集合
,那么,可以直接利用这些信息计算基本块B中每个变量x在其定值处的du链。 - 第一种情况:如果B中x的定值d之后有x的第一个定值d′,则d和d′之间x的所有引用构成d的du链。
- 第二种情况:如果B中x的定值d之后没有x的新的定值,则B中d之后x的所有
引用
以及OUT[B]中x的所有引用
构成d的du链。
可用表达式:
- 如果从流图的
首节点
到达程序点p
的每条路径
都对表达式x op y
进行计算,并且从最后一个这样的计算到点p之间没有再次对x或y定值
,那么表达式x op y
在点p
是可用
的(available)。
表达式可用的直观意义:
- 在点p上,x op y已经在
之前被计算过
,不需要重新计算。
可用表达式信息的主要用途
-
消除全局公共子表达式
如上,如果在 B3 的入口处,表达式 4 ∗ i 4 * i 4∗i 是可用表达式的话,那么B3中的 4 ∗ i 4 * i 4∗i 是一个全局公共子表达式,可以将其删除。那么,B2中的表达式满足什么条件,在 B3 的入口处,表达式 4 ∗ i 4 * i 4∗i 是可用表达式呢?则要求,在B2中,i没有重新定值,或者,即使重新定之后,计算了表达式 4 ∗ i 4*i 4∗i 的值。 -
进行复制传播
在x的引用点u可以用y代替x的条件:从流图的首节点
到达u的每条路径
都存在复制语句x = y,并且从最后一条复制语句x = y到点u之间没有再次对x或y定值
。这个概念即:复制语句x=y在引用点u处可用
。
可用表达式的传递函数
对于可用表达式数据流模式而言,如果基本块B对x或者y进行了(或可能进行)定值,且以后没有重新计算x op y
,则称B杀死表达式x op y。如果基本块B对x op y进行计算,并且之后没有重新定值
x或y,则称B生成表达式
x op y。
f B ( x ) = e _ g e n B ∪ ( x − e _ k i l l B ) f_B(x)= e\_gen_B \cup(x- e\_kill_B) fB(x)=e_genB∪(x−e_killB)
- e _ g e n B e\_gen_B e_genB:基本块B所生成的可用表达式的集合
- e _ k i l l B e\_kill_B e_killB:基本块B所杀死的 U U U中的可用表达式的集合
-
- U U U:所有出现在程序中一个或多个语句的右部的表达式的全集
e_gen_B的计算
- 初始化: e _ g e n B = Φ e\_gen_B = \Phi e_genB=Φ
- 顺序扫描基本块的每个语句: z = x o p y z = x op y z=xopy
-
- 把
x op y
加入 e _ g e n B e\_gen_B e_genB
- 把
-
- 从 e _ g e n B e\_gen_B e_genB中删除和 z z z相关的表达式
如上,最终得到的集合是空集。
e_kill_B的计算
- 初始化: e _ k i l l B = Φ e\_kill_B = \Phi e_killB=Φ
- 顺序扫描基本块的每个语句: z = x o p y z = x op y z=xopy
-
- 从
e
_
k
i
l
l
B
e\_kill_B
e_killB中删除表达式
x op y
- 从
e
_
k
i
l
l
B
e\_kill_B
e_killB中删除表达式
-
- 把所有和 z z z 相关的表达式加入到 e _ k i l l B e\_kill_B e_killB 中
可用表达式的数据流方程
e
_
g
e
n
B
e\_gen_B
e_genB 和
e
_
k
i
l
l
B
e\_kill_B
e_killB 的值可以直接从流图计算出来,因此在方程中作为已知量
。
计算可用表达式的迭代算法
输入:流图
G
G
G ,其中每个基本块B的
e
_
g
e
n
B
e\_gen_B
e_genB 和
e
_
k
i
l
l
B
e \_kill_B
e_killB 都已计算出来。
为什么将OUT[B]集合初始化为U?
标签:分析,活跃,变量,18,基本块,定值,代码优化,表达式,OUT 来源: https://blog.51cto.com/u_15279775/2936195