第第第 第 第 第 第 第第第第第第 第第第第第第第第第第 第第第第第第 第第第第 (), • 第第第第第第第第第第 第第第第第第第第第第第第第第第第第 , • 第第第第第第第第 • 第第第第第 • 第第第第第第
Jan 24, 2016
第九章 代 码 优 化
通过程序变换(局部变换和全局变换)来改进程序,称为优化
• 介绍独立于机器的优化,即不考虑任何目标机器性质的优化变换
• 流图中循环的识别• 数据流分析• 代码改进变换
9.1 优化的主要种类
9.1.1 代码改进变换的标准• 代码变换必须保程序的含义• 采取安全稳妥的策略• 变换减少程序的运行时间平均达到一个可度
量的值• 变换所作的努力是值得的
9.1 优化的主要种类
本节所用的例子i = m 1; j = n; v = a[n]; (1) i := m 1while (1) { (2) j := n
do i = i +1; while(a[i]<v); (3) t1 := 4 * n
do j =j 1;while (a[j]>v); (4) v := a[t1]
if (i >= j) break; (5) i := i + 1
x=a[i]; a[i]=a[j]; a[j]=x; (6) t2 := 4 * i
} (7) t3 := a[t2]
x=a[i]; a[i]=a[n]; a[n]=x; (8) if t3>v goto (5)
9.1 优化的主要种类
本节所用的例子i = m 1; j = n; v = a[n]; (9) j := j 1
while (1) { (10) t4 := 4 * j
do i = i +1; while(a[i]<v); (11) t5 := a[t4]
do j =j 1;while (a[j]>v); (12) if t5>v goto (9)
if (i >= j) break; (13) if i >=j goto (23)
x=a[i]; a[i]=a[j]; a[j]=x; (14) t6 := 4 * i
} (15 ) x := a[t6]
x=a[i]; a[i]=a[n]; a[n]=x; . . .
9.1 优化的主要种类i := m 1j := nt1 := 4 * nv := a[t1]
i := i + 1t2 := 4 * it3 := a[t2]if t3 > v goto B2
B1
B2
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
if i >= j goto B6B4
B3
B5 B6
9.1 优化的主要种类
9.1.2 公共子表达式删除B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * ix := a[t6]t7 := 4 * i t8 := 4 * jt9 := a[t8]a[t7] := t9
t10 := 4 * ja[t10] := xgoto B2
9.1 优化的主要种类
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * ix := a[t6]t7 := 4 * i t8 := 4 * jt9 := a[t8]a[t7] := t9
t10 := 4 * ja[t10] := xgoto B2
9.1 优化的主要种类
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * ix := a[t6]t7 := 4 * i t8 := 4 * jt9 := a[t8]a[t7] := t9
t10 := 4 * ja[t10] := xgoto B2
t6 := 4 * ix := a[t6]t8 := 4 * jt9 := a[t8]a[t6] := t9
a[t8] := xgoto B2
9.1 优化的主要种类i := m 1j := nt1 := 4 * nv := a[t1]
i := i + 1t2 := 4 * it3 := a[t2]if t3 > v goto B2
B1
B2
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
if i >= j goto B6B4
B3
B5 B6
9.1 优化的主要种类
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * ix := a[t6]t7 := 4 * i t8 := 4 * jt9 := a[t8]a[t7] := t9
t10 := 4 * ja[t10] := xgoto B2
t6 := 4 * ix := a[t6]t8 := 4 * jt9 := a[t8]a[t6] := t9
a[t8] := xgoto B2
9.1 优化的主要种类
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * ix := a[t6]t7 := 4 * i t8 := 4 * jt9 := a[t8]a[t7] := t9
t10 := 4 * ja[t10] := xgoto B2
t6 := 4 * ix := a[t6]t8 := 4 * jt9 := a[t8]a[t6] := t9
a[t8] := xgoto B2
x := a[t2]t9 := a[t4]a[t2] := t9
a[t4] := xgoto B2
9.1 优化的主要种类i := m 1j := nt1 := 4 * nv := a[t1]
i := i + 1t2 := 4 * it3 := a[t2]if t3 > v goto B2
B1
B2
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
if i >= j goto B6B4
B3
B5 B6
9.1 优化的主要种类
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * ix := a[t6]t7 := 4 * i t8 := 4 * jt9 := a[t8]a[t7] := t9
t10 := 4 * ja[t10] := xgoto B2
t6 := 4 * ix := a[t6]t8 := 4 * jt9 := a[t8]a[t6] := t9
a[t8] := xgoto B2
x := a[t2]t9 := a[t4]a[t2] := t9
a[t4] := xgoto B2
9.1 优化的主要种类
B5 x=a[i]; a[i]=a[j]; a[j]=x;
t6 := 4 * ix := a[t6]t7 := 4 * i t8 := 4 * jt9 := a[t8]a[t7] := t9
t10 := 4 * ja[t10] := xgoto B2
t6 := 4 * ix := a[t6]t8 := 4 * jt9 := a[t8]a[t6] := t9
a[t8] := xgoto B2
x := a[t2]t9 := a[t4]a[t2] := t9
a[t4] := xgoto B2x := t3
a[t2] := t5
a[t4] := xgoto B2
9.1 优化的主要种类
B6 x = a[i]; a[i] = a[n]; a[n] = x;
t11 := 4 * ix := a[t11]t12 := 4 * i t13 := 4 * nt14 := a[t13]a[t12] := t14
t15 := 4 * n a[t15] := x
x := t3
t14 := a[t1]a[t2] := t14
a[t1] := x
9.1 优化的主要种类
B6 x = a[i]; a[i] = a[n]; a[n] = x;a[t1] 能否作为公共子表达式?
t11 := 4 * ix := a[t11]t12 := 4 * i t13 := 4 * nt14 := a[t13]a[t12] := t14
t15 := 4 * n a[t15] := x
x := t3
t14 := a[t1]a[t2] := t14
a[t1] := x
9.1 优化的主要种类i := m 1j := nt1 := 4 * nv := a[t1]
i := i + 1t2 := 4 * it3 := a[t2]if t3 > v goto B2
B1
B2
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
if i >= j goto B6B4
B3
B5 B6
把 a[t1]
作为公共子表达式是不稳妥的
9.1 优化的主要种类
9.1.3 复写传播• 形成为 f := g 的赋值叫做复写语句• 优化过程中会大量引入复写
t := d + ea := t
删除局部公共子表达式期间引进复写
t := d + eb := t
c := tc := d + e
b := d + ea := d + e
9.1 优化的主要种类
9.1.3 复写传播• 形成为 f := g 的赋值叫做复写语句• 优化过程中会大量引入复写• 复写传播变换的做法是在复写语句 f := g 后,
尽可能用 g 代表 f
x := t3
a[t2] := t5
a[t4] := t3
goto B2
x := t3
a[t2] := t5
a[t4] := xgoto B2
9.1 优化的主要种类
9.1.3 复写传播• 形成为 f := g 的赋值叫做复写语句• 优化过程中会大量引入复写• 复写传播变换的做法是在复写语句 f := g 后,
尽可能用 g 代表 f• 复写传播变换本身并不是优化,但它给其它
优化带来机会– 常量合并– 死代码删除
9.1 优化的主要种类
9.1.4 死代码删除• 死代码是指计算的结果决不被引用的语句• 一些优化变换可能会引起死代码例:debug := true; debug := false;. . . 测试后改成 . . .if (debug) print … if (debug) print
…
9.1 优化的主要种类
9.1.4 死代码删除• 死代码是指计算的结果决不被引用的语句• 一些优化变换可能会引起死代码例:复写传播可能会引起死代码删除
x := t3
a[t2] := t5
a[t4] := t3
goto B2
a[t2] := t5
a[t4] := t3
goto B2
9.1 优化的主要种类
9.1.5 代码外提• 代码外提是循环优化的一种• 循环优化的其它重要技术
– 归纳变量删除– 强度削弱
例: while (i <= limit 2 ) … 变换成
t = limit 2;while (i <= t ) …
9.1 优化的主要种类
9.1.6 强度削弱和归纳变量删除• j 和 t4 的值步伐一致地变化• 这样的变量叫做归纳变量• 在循环中有多个归纳变量时, 也许只需要留下一个• 这个操作由归纳变量删除 过程来完成• 对本例可以先做强度削弱 它给删除归纳变量创造机会
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
B3
9.1 优化的主要种类i := m 1j := nt1 := 4 * nv := a[t1]
B1
B2
j := j 1t4 := t4 4t5 := a[t4]if t5 > v goto B3
B4
B3
B5 B6
t4 := 4 * j
if i >= j goto B6
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
B3
除第一次外,t4 = 4 * j 在 B3 的入口一定保持在 j := j 1 后,关系 t4 = 4 * j + 4
也保持
9.1 优化的主要种类i := m 1j := nt1 := 4 * nv := a[t1]
i := i + 1t2 := 4 * it3 := a[t2]if t3 > v goto B2
B1
B2
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
if i >= j goto B6B4
B3
B5 B6
B2 也可以进行类似的变换循环控制条件可以用 t2 和 t4
来表示
9.1 优化的主要种类i := m 1j := nt1 := 4 * nv := a[t1]t2 := 4 * it4 := 4 * j
t2 := t2 + 4t3 := a[t2]if t3 > v goto B2
B1
B2
t4 := t4 4t5 := a[t4]if t5 > v goto B3
if t2 >= t4 goto B6
a[t2] := t5a[t4] := t3goto B2
B4
B3
B5 t14 := a[t1]a[t2] := t14a[t1] := t3
B6
9.1 优化的主要种类
9.1.7 优化编译器的组织• 实现高级结构的操作在中间代码中是显式的• 中间代码基本上独立于目标机器
前 端 代 码生成器
代 码优化器
变 换数据流分 析
控制流分 析
9.2 流图中的循环
9.2.1 必经结点结点 d 是结点 n 的必经结点,如果从初始结点起,每条到达 n 的路径都要经过 d ,写成 d dom n每个结点是它本身的必经结点 循环的入口是循环中所有结点的必经结点
1
23
4
5 6
7
8
9 10
9.2 流图中的循环
9.2.2 自然循环• 循环
– 循环必须有唯一的入口点,叫做首结点,首结点是循环中所有结点的必经结点
– 至少有一种办法重复循环,也就是至少有一条路径回到首结点
• 回边– 如果有 a dom b ,那么边 b a 叫做回边
• 寻找流图中所有循环的一个办法是找出流图的回边
9.2 流图中的循环
自然循环• 回边 10 7 循环 {7, 8, 10}• 回边 7 4 循环 {4, 5, 6, 7, 8, 10}• 回边 4 3 和 8 3 循环 {3, 4, 5, 6, 7, 8, 10}• 回边 9 1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
1
23
4
5 6
7
8
9 10
9.2 流图中的循环
内循环若一个循环的结点集合是另一个循环的结点集合的子集。
两个循环有相同的首结点 ,但并非一个结点集是另一个的子集,则看成一个循环。
B0
B1
B2 B3
有相同首节点的两个循环
9.2 流图中的循环
9.2.3 前置结点某些变换要求我们移动语句到首结点的前面
B0
循环 L
(a) 整理前, B0 是首结点
B0
B0
循环 L
(b) 整理后,增加前置结点B0
9.2 流图中的循环
9.2.4 可归纳流图一个流图 G 是可归约的,当且仅当有向边集合 = 正向边子集回边子集,并有性质 :
•正向边子集形成有向无环图,在这个图中,每个结点可以从 G 的初始结点到达
• 回边子集仅由前面所讲的回边组成
9.2 流图中的循环1
23
4
5 6
7
8
9 10
1
23
4
5 6
7
8
9 10
9.2 流图中的循环
非归约流图的例子• 初始结点是 1• 2 3 和 3 2 都不是回边•该图不是无环的• 从结点 2 和 3 两处进入由 它们构成的环
32
1
9.3 全局数据流分析介绍
• 编译器需要把程序流图作为一个整体来收集信息
• 并把这些信息分配给流图的各个基本块• 数据流信息可以通过建立和解数据流方程来收集
• 典型方程out [B] = gen [B] (in [B] kill [B] )
9.3 全局数据流分析介绍
建立和解数据流方程依赖三个因素out [B] = gen [B] (in [B] kill [B] )
•产生和注销的概念依赖于数据流方程所要解决的问题,也会出现反向前进,由 out[B] 来定义 in[B]
• 数据流分析受程序控制结构影响• 过程调用、通过指针赋值、甚至对数组变量
的赋值等的存在使得数据流分析大大复杂
9.3 全局数据流分析介绍
9.3.1 点和路径• 点
– 基本块中,两个相邻的语句之间为程序的一个点– 基本块的开始点和结束点
• 路径点序列 p1, p2, …, pn ,对 1 和 n - 1 间的每个 i ,满足– pi 是先于一个语句的点, pi + 1 是同一块中位于该
语句后的点,或者– pi 是某块的结束点, pi + 1 是后继块的开始点
9.3 全局数据流分析介绍
9.3.2 到达 -定值• 确切定值:赋值语句或读语句• 可能定值:过程调用 , 别名 , 通过指针来赋值•确切引用• 可能引用• 在给出简单的例子加以区别后,我们将不考
虑过程调用 , 别名 , 通过指针来赋值等引起不确定性的情况。
9.3 全局数据流分析介绍
x 的定值语句 d 能到达点 pd: x := … d: x := … d: x := … . . . . d1: x := … d1: *y := …
. . . p p p
d 到达 p d 不能到达 p d 到达 p d 被注销 d1 也能到达
p
9.3 全局数据流分析介绍
• i := m 1 和 j := n 都能到达 B2 的开始点
• j := j 1 也能到达 B2 的开始点• j := n 不能到 B4
d1: i := m 1d2: j := nd3: a := u1
B1
B2
B4
B3
B5B6
d4: i := i + 1
d5: j := j 1
d6: a := u2
9.3 全局数据流分析介绍
d: x := … d: x := … d: x := … . . . . d1: x := … d1: *y := …
. . . p p pD 可以到达 p d 不能到达 p d 能到达 p
d 被注销 d1 也能到达p
到达 - 定值是不精确的,但是稳妥的会使我们失去某些实际是安全的变换
9.3 全局数据流分析介绍
到达 - 定值的迭代算法gen [B] : B 中能到达 B 的结束点的定值语句kill [B] :整个程序中决不会到达 B 结束点的定
值in [B] :能到达 B 的开始点的定值集合out [B] :能到达 B 的结束点的定值集合两组方程(根据 gen 和 kill 求解 in 和 out )
in [ B ] = out [P] P 是 B 的前驱
out [B] = gen [B] (in [B] kill [B])
9.3 全局数据流分析介绍 in [B]B1 000 0000
B2 000 0000
B3 000 0000
B4 000 0000
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 000 0000 000 1100
B3 000 0000 000 0010
B4 000 0000 000 0001
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 111 0001 000 1100
B3 000 0000 000 0010
B4 000 0000 000 0001
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 111 0001 001 1100
B3 000 0000 000 0010
B4 000 0000 000 0001
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 111 0001 001 1100
B3 001 1100 000 0010
B4 000 0000 000 0001
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 111 0001 001 1100
B3 001 1100 000 1110
B4 000 0000 000 0001
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 111 0001 001 1100
B3 001 1100 000 1110
B4 001 1110 000 0001
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 111 0001 001 1100
B3 001 1100 000 1110
B4 001 1110 001 0111
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 111 0111 001 1100
B3 001 1100 000 1110
B4 001 1110 001 0111
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 111 0111 001 1110
B3 001 1100 000 1110
B4 001 1110 001 0111
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍 in [B] out [B] B1 000 0000 111 0000
B2 111 0111 001 1110
B3 001 1110 000 1110
B4 001 1110 001 0111
gen [B1] = {d1, d2, d3}kill [B1]={d4, d5, d6, d7}
gen [B2] = {d4, d5}kill [B2] = {d1, d2, d7}
gen [B3] = {d6}kill [B3] = {d3}
gen [B4] = {d7}kill [B4] = {d1, d4}
d1: i := m 1d2: j := nd3: a := u1
B1
B2
d7: i := u3 B4
d4: i := i + 1d5: j := j 1
d6: a := u2 B3
9.3 全局数据流分析介绍
in [ B ] = out [P] P 是 B 的前驱
out [B] = gen [B] (in [B] kill [B]) • 到达 -定值方程是正向的方程,另一类数据流方程是反向的
• 到达 -定值方程的合流算符是求并集,另一类数据流方程的合流算符是求交集
到达 -定值的信息存储为引用 -定值链(或叫 ud链),指能到达变量的某个引用的所有定值
9.3 全局数据流分析介绍
9.3.3 可用表达式 x := y + z x := y + z x := y + z . . . . y := … z := …
. . . p p p
y + z 在 p 点 y + z 在 p 点 y + z 在 p 点可用 不可用 不可用
9.3 全局数据流分析介绍
t1 := 4*i
?
t2 := 4*i
B1
B2
B3
t1 := 4*i
i :=t0 := 4*i
t2 := 4*i
B1
B2
B3
9.3 全局数据流分析介绍
• 计算可用表达式的方程out [B] = e_gen [B] (in [B] e_kill [B] )in [ B ] = out [P] ( B 不是初始块)
P 是 B 的前驱
in [B1] = ( B1 是初始块)• 和到达 -定值方程的区别
– 初始块的 in处理为特殊情况– 合流算符是交集运算而不是并集运算– 到达 -定值求最小解,可用表达式求最大解
9.3 全局数据流分析介绍
in 集合的不同初值比较 in [B2] = out [B1] out [B2]
(以 B2 为例) out [B2] = G (in [B2] K)
B1
B2
O j+1 = G (I j K)I j+1 = out [B1] O j+1
I 0 = I 0 = UO 1 = G O 1 = U KI 1 = out [B1] G I 1 = out [B1] KO 2 = G O 2 = G (out [B1] K)
9.3 全局数据流分析介绍
9.3.4 活跃变量分析• x 的值在 p 点开始的路径上被引用,我们说 x
在 p 点活跃,否则称 x 在 p 点是死亡的• in [B] :开始点的活跃变量集合• out[B] :结束点的活跃变量集合• def[B] :块 B 中有定值且该定值前无引用的
变量集• use[B] :块 B 中有引用且在该引用前无定值
的变量集
9.3 全局数据流分析介绍
• in [B] :开始点的活跃变量集合• out[B] :结束点的活跃变量集合• def[B] :块 B 中有定值且该定值前无引用的
变量集• use[B] :块 B 中有引用且在该引用前无定值
的变量集• in [B] = use [B] (out [B] def [B] )• out[B] = in [S]
S 是 B 的后继
9.3 全局数据流分析介绍
定值引用链( du链)• du链问题是计算对变量(如 x )定值的所有
引用语句 s 的集合• 可以建立数据流方程来求解定值引用信息
9.4 代码改进变换
•依赖于上节收集的数据流信息进行代码改进变换
• 有些变换可以一起完成,但这里是逐个讨论• 代替不了局部变换
9.4 代码改进变换
9.4.1 公共子表达式删除对每个 s: x := y + z ,若 y + z 在块的开始点可
用 ,在 s 前没有 y 或 z 的定值,则执行下面的步骤:• 从该块开始反向搜索,找出到达该块开始点
的 y + z 的计算•建立新变量 u• 把上面找到的每个语句 w := y + z 改成
– u := y + z– w := u
• 用 x := u 代替语句 s
9.4 代码改进变换
例
c := d + e
b := d + ea := d + e t := d + ea := t
t := d + eb := t
c := t
9.4 代码改进变换
该方法并非都是改进(若运行时主要走那条红色路径)
c := d + e
b := d + ea := d + e t := d + ea := t
t := d + eb := t
c := t
9.4 代码改进变换
只能删除明显的公共子表达式
a := x + y 和 c := x + yb := a * z d := c * z
漏掉了 a * z 和 c * z 有相同的值这个事实
但是若和复写传播联系起来,可以找出这样的公共子表达式
9.4 代码改进变换
t2 := 4 * it3 := a [ t2 ]
t6 := 4 * it7 := a [ t6 ]
(a)
u := 4 * it2 := ut3 := a [ t2 ]
t6 := ut7 := a [ t6 ]
(b)
u := 4 * it2 := ut3 := a [u ]
t6 := ut7 := a [u ]
(c)
9.4 代码改进变换
9.4.2 复写传播s: x := y
.
.
. u: := x …用 y 代替 x 的前提是:• 语句 s 是到达 u 的唯一的 x 定值• 从 s 到 u 的每条路径,包括穿过 u 若干次的
路径上,没有对 y 的赋值
9.4 代码改进变换
建立新的数据流分析方程来解决第二个前提
in [B] 和 out [B] :复写语句 s: x := y 的集合c_gen [B] :出现在块 B 中的 s: x := y ,且块 B
中该语句的后面没有对 x 或 y 的定值c_kill [B] :不在块 B 中的 s: x := y ,且 x 或 y
在块 B 中赋值
9.4 代码改进变换
建立新的数据流分析方程来解决第二个前提
in [B] 和 out [B] :复写语句 s: x := y 的集合c_gen [B] :出现在块 B 中的 s: x := y ,且块 B
中该语句的后面没有对 x 或 y 的定值c_kill [B] :不在块 B 中的 s: x := y ,且 x 或 y
在块 B 中赋值out [B] = c_gen [B] (in [B] c_kill [B])in [B] = out [P] ( B 不是初始块)
P 是 B 的前驱in[ B1 ] = ( B1 是初始块)
9.4 代码改进变换
c_gen [B1] = {x := y}
c_gen [B3] = {x := z}
c_kill [B1] = {x := z}
c_kill [ B2] = {x := y}
c_kill [B3] = {x := y}
in [B1]= , in [B2] = in [B3] = out [B1] = {x := y}
out [B2] =, out [B3] = in [B4] = out [B4] = {x := z}
in [B5] = out [B2] out [B4] =
x := y
:= x
:= x
y := x := z
B4
B5
B3B2
B1
9.4 代码改进变换9.4.3 寻找循环不变计算输入 循环 L ,对 L 的每个三地址语句,有 ud链可用。输出 从控制进入 L 一直到离开 L ,每次都计算同样值
的三地址语句被输出。方法• 把运算对象都是常量(或其所有的到达定值都在 L
外)的语句,标记为“不变”语句。• 重复下一步,直到没有新的语句标记为“不变”为止• 给下面的语句标记“不变”:它们先前没有标记,并且所有的运算对象都是下列三种情况之一:
( a )常量;( b )其所有的到达定值都在 L 外;( c )只有一个到达定值,这个定值是循环中已标记
为“不变”的语句。
9.4 代码改进变换
9.4.4 代码外提•将循环不变语句提到循环的前置结点中• 并不是所有的循环不变语句都可以外提• 我们讨论三个条件(并非是必要条件)
9.4 代码改进变换
语句 s : x := y+ z 可以外提的条件• 含 s 的块是循环所有出口结点的必经结点
i := 1
if u < v goto B3
v := v 1if u <=20 goto B5
i := 2u := u + 1
j := i B5
B4
B3
B2
B1
9.4 代码改进变换
语句 s : x := y+ z 可以外提的条件• 循环中没有其它语句对 x 定值 i := 1
i := 3if u < v goto B3
v := v 1if u <=20 goto B5
i := 2u := u + 1
j := i B5
B4
B3
B2
B1
9.4 代码改进变换
语句 s : x := y+ z 可以外提的条件• x 的其它定值都不能到达循环中 x 的引用
i := 1
if u < v goto B3
k := iv := v 1if u <=20 goto B5
i := 2u := u + 1
j := i B5
B4
B3
B2
B1
9.4 代码改进变换
9.4.5 归纳变量删除• 循环归纳变量 :在循环中,其值的每次改变都增加或减少某个固定的常量
• 基本归纳变量:在循环中只有一个形如 i := i c 的 i ,其中 c 是常量
• 其它归纳变量 :在循环中仅定值一次,并且其值是某个基本归纳变量的线性函数。
9.4 代码改进变换
寻找归纳变量• 找出所有基本归纳变量 i := i c ,描述为 (i,
1, 0) 的形式• 寻找只有一个赋值的 k ,其形式为
k := j*b, k := b*j, k := j / b, k := j b, k := b j
其中 b 是常数, j 是基本的或非基本的归纳变量– 若 j 是 基 本 的且 k := j * b ,则 k 属 j 族, 为
(j,b,0)– 若 j 属 I族,为 (i, c, d) , k := b * j ,则 k 属 I族
,为 (i, b * c, b * d )
9.4 代码改进变换
• 循环 B2– i族 i: (i, 1, 0)– i族 t2 : (i, 4, 0)
• 循环 B3– j族 j: (j, 1, 0)– j族 t4 : (j, 4, 0)
• 循环 B2、 B3、 B4 和B5– 和上面一样的 i族和 j族
i := m 1j := nt1 := 4 * nv := a[t1]
B1
B2i := i +1t2 := 4 * it3 := a[t2]if t3 < v goto B2
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
if i >= j goto B6B4
B3
B5B6
9.4 代码改进变换
归纳变量的强度削弱i族 j: (i,c,d)
• 用 j := s 代替 j 的赋值
• 在每个赋值 i := i + n 的后面,紧接着它加上s := s + c * n
i族 s: (s,c,d)
• 在前置块的末尾加上s := c * i /* 如果 c 为 1 ,则 s := i */s := s + d /* 如果 d 为 0 则被省略 */
9.4 代码改进变换• 循环 B2
– i族 i: (i, 1, 0)– i族 t2 : (i, 4, 0)
s2 := 4 * i (前置结点)s2 := s2 + 4 (循环内)t2 := s2 (循环内)
• 循环 B3– j族 j: (j, 1, 0)– j族 t4 : (j, 4, 0)
s4 := 4 * j (前置结点)s4 := s4 + 4 (循环内) t4 := s4 (循环内)
i := m 1j := nt1 := 4 * nv := a[t1]
B1
B2i := i +1t2 := 4 * it3 := a[t2]if t3 < v goto B2
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
if i >= j goto B6B4
B3
B5B6
9.4 代码改进变换
归纳变量删除• if i relop x goto B 的测试( x 不是归纳变量)
– 取 i 族的某个 j ,优先取 c=1 和 d = 0 的 j:(i,c,d )
– 把每个含 i的测试改成对 j的测试 ( 假定 c 为正 )r := c * x /* 如果 c等于 1 ,则 r := x */r := r + d /* 如果 d 为 0 ,则省略 */if j relop r goto B
9.4 代码改进变换
归纳变量删除• if i relop x goto B 的测试( x 不是归纳变量)
– 取 i 族的某个 j ,优先取 c=1 和 d = 0 的 j:(i,c,d )
– 把每个含 i的测试改成对 j的测试 ( 假定 c 为正 )r := c * x /* 如果 c等于 1 ,则 r := x */r := r + d /* 如果 d 为 0 ,则省略 */if j relop r goto B
• if i1 relop i2 goto B 的测试– 最简单的情况是 j1:(i1,c1,d1) 和 j2:(i2,c2,d2) ,还有
c1=c2 且 d1=d2
– 那么, i1 relop i2等价于 j1 relop j2
9.4 代码改进变换归纳变量删除• if i relop x goto B 的测试( x 不是归纳变量)– 取 i 族的某个 j ,优先取 c=1 和 d = 0 的 j:(i,c,d )– 把每个含 i的测试改成对 j的测试 ( 假定 c为正 )
r := c * x /* 如果 c等于 1 ,则 r := x */r := r + d /* 如果 d 为 0 ,则省略 */if j relop r goto B
• if i1 relop i2 goto B 的测试– 最简单的情况是 j1:(i1,c1,d1) 和 j2:(i2,c2,d2) ,还有 c1=c2 且
d1=d2
– 那么, i1 relop i2等价于 j1 relop j2
•更复杂的情况,测试的替换可能没有价值
9.4 代码改进变换• 循环 B2
– i族 i: (i, 1, 0)– i族 t2 : (i, 4, 0)
s2 := s2 + 4 (循环内)s2 := 4 * i (前置结点)
• 循环 B3– j族 j: (j, 1, 0)– j族 t4 : (j, 4, 0)
s4 := s4 + 4 (循环内)s4 := 4 * j (前置结点)
i := m 1j := nt1 := 4 * nv := a[t1]
B1
B2i := i +1t2 := 4 * it3 := a[t2]if t3 < v goto B2
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
if i >= j goto B6B4
B3
B5B6
9.4 代码改进变换• 循环 B2
– i族 i: (i, 1, 0)– i族 t2 : (i, 4, 0)
s2 := s2 + 4 (循环内)s2 := 4 * i (前置结点)
• 循环 B3– j族 j: (j, 1, 0)– j族 t4 : (j, 4, 0)
s4 := s4 + 4 (循环内)s4 := 4 * j (前置结点)
• 测试 i >= j 由 s2 > = s4代替, i 和 j 都被删除
i := m 1j := nt1 := 4 * nv := a[t1]
B1
B2i := i +1t2 := 4 * it3 := a[t2]if t3 < v goto B2
j := j 1t4 := 4 * jt5 := a[t4]if t5 > v goto B3
if i >= j goto B6B4
B3
B5B6
本 章 要 点• 对各类优化的理解,包括常量合并、公共子表
达式删除、复写传播、死代码删除、循环优化(代码外提、归纳变量删除、强度削弱)等
•掌握建立程序流图的算法和流图中自然循环的识别算法
• 对各种数据流分析方程的认识和区分,和对这些方程迭代求解方法的理解
•了解如何利用控制流分析的信息和各种数据流分析的信息进行各类代码改进变换
例 题 1UNIX 下的 C 编译命令 cc 的选择项 g 和 O 的解释如下 ,
其中dbx 的解释是“ dbx is an utility for source-level debugging and execution of programs written in C” 。试说明为什么用了选择项 g 后,选择项O便被忽略。-g Produce additional symbol table information for dbx(1) and dbxtool(1) and pass -lg option to ld(1) (so as to include the g library, that is: /usr/lib/libg.a). When this option is given, the -O and -R options are suppressed.-O[level] Optimize the object code. Ignored when either -g, -go, or -a is used. ...
例 题 2
一个 C 语言程序如下:main() pushl %ebp { movl %esp,%ebp
int i,j,k; movl $1,%eax -- j=1 i=5; movl $6,%edx -- k=6 j=1; L4: while(j<100){ addl %edx,%eax -- j=j+6
k=i+1; cmpl $99,%eax j=j+k; jle .L4 --
while(j99) }
}
例 题 2
一个 C 语言程序如下:main() pushl %ebp { movl %esp,%ebp
int i,j,k; movl $1,%eax -- j=1 i=5; movl $6,%edx -- k=6 j=1; L4: while(j<100){ addl %edx,%eax -- j=j+6
k=i+1; cmpl $99,%eax j=j+k; jle .L4 -- while(j99)
} 复写传播、常量合并、代码外提、删除无用赋值 } 对 i , j 和 k 分配内存单元也成为多余,从而被取消
例 题 3
一个 C 语言程序
main()
{
long i,j;
while (i) {
if (j) { i = j; }
}
}
生成的汇编码见右边
pushl %ebpmovl %esp,%ebpsubl $8,%esp
.L2:cmpl $0,-4(%ebp)jne .L4jmp .L3
.L4:cmpl $0,-8(%ebp)je .L5movl -8(%ebp),%eaxmovl %eax,-4(%ebp)
.L5:jmp .L2
.L3:
例 题 3
一个 C 语言程序
main()
{
long i,j;
while (i) {
if (j) { i = j; }
}
}
优化编译的汇编码见右边
pushl %ebpmovl %esp,%ebp
.L7:testl %eax,%eaxje .L3testl %edx,%edxje .L7movl %edx,%eaxjmp .L7
.L3:
例 题 4
求最大公约数的函数long gcd(p,q)
long p,q;
{
if (p%q == 0)
return q;
else
return gcd(q, p%q);
}
其中的递归调用称为尾递归 .对于尾递归 , 编译器可以产生和一般的函数调用不同的代码 ,使得目标程序运行时 ,这种递归调用所需的存储空间大大减少 , 也缩短了运行时间 .对于尾递归 , 编译器应怎样产生代码 ?
例 题 4
求最大公约数的函数long gcd(p,q)
long p,q;
{
if (p%q == 0)
return q;
else
return gcd(q, p%q);
}
• 计算调用的实在参数 q和 p%q ,存放在不同的寄存器中
•将上述寄存器中实在参数的值存入当前活动记录中形式参数 p 和 q的存储单元
•转到本函数第一条语句的起始地址继续执行
例 题 4
求最大公约数的函数long gcd(p,q)
long p,q;
{
if (p%q == 0)
return q;
else
return gcd(q, p%q);
}
movl 8(%ebp),%esimovl 12(%ebp),%ebx
.L4:movl %esi,%eaxcltdidivl %ebxmovl %edx,%ecxtestl %ecx,%ecxje .L2movl %ebx,%esimovl %ecx,%ebxjmp .L4
.L2:
习 题