优化 = 在不改变运行结果的前提下,对代码作等价变换以提高效率(省时间/空间)。按范围分:局部优化(基本块内)、循环优化、全局优化[1]。
基本块:连续的语句序列,只有一个入口(第一条)、一个出口(最后一条),中间不能有跳转进出。
① 先找全部入口语句:㈠程序第一条;㈡任何转移语句的目标;㈢紧跟在转移语句之后的语句。
② 每个入口语句 → 到下一个入口语句之前(或到一条转移语句为止)= 一个基本块。
块内常用变换:删除公共子表达式、删除无用(死)代码、合并已知量(常量折叠)、临时变量改名、交换语句次序、代数变换(x*1=x、x*2=x+x)。
DAG(无环有向图):叶结点是变量/常量初值,内部结点是运算;相同子表达式共享同一结点 → 自动暴露公共子表达式、无用赋值。
(1) read x (2) t1 = x * 2 (3) if t1 > 100 goto (7) (4) t2 = t1 + 1 (5) y = t2 (6) goto (8) (7) y = 0 (8) write y入口语句:(1)首条;(7)、(8) 是跳转目标;(4) 紧跟转移语句(3)之后;(7) 也紧跟(6)之后。⟹ 入口 = {(1),(4),(7),(8)}。
B1: (1)(2)(3) B2: (4)(5)(6) B3: (7) B4: (8)
(1) a = b + c (2) b = a - d (3) c = b + c (4) d = a - d建 DAG 时发现:(2) 的
a-d 与 (4) 的 a-d 操作数相同 ⟹ 共享同一结点,a-d 只需算一次((4) 是公共子表达式,d 与(2)算出的值同源)。
原循环: 外提 + 强度削弱后: i = 1 i = 1; t = 4 // t=4*i 初值,外提 while i<=n: while i<=n: t = 4 * i A[t] = 0 A[t] = 0 i = i + 1 i = i + 1 t = t + 4 // 乘法→加法(强度削弱)
4*i 随 i 每次 +1 而每次 +4,故把乘法 t=4*i 改为加法 t=t+4(强度削弱),初值在循环外算一次(外提)。