编译原理冲刺 · 第 12 课 ⏱ 冲刺模式 · ≤1周

代码优化:基本块 · DAG · 循环优化

不改变结果、只让代码更快更省。对应教材第 10 章 10.1–10.3。
🎯 本课唯一目标
划分基本块、会用 DAG 找公共子表达式、会做循环优化(代码外提、强度削弱)。
为什么学它? 第 10 章常考"划分基本块"和"循环优化"两类题,规则明确、好拿分。这也是全景图里"代码优化"那一格。

一、概述(10.1)

优化 = 在不改变运行结果的前提下,对代码作等价变换以提高效率(省时间/空间)。按范围分:局部优化(基本块内)、循环优化全局优化[1]

二、局部优化(10.2)

基本块:连续的语句序列,只有一个入口(第一条)、一个出口(最后一条),中间不能有跳转进出。

⚑ 划分基本块 步骤

① 先找全部入口语句:㈠程序第一条;㈡任何转移语句的目标;㈢紧跟在转移语句之后的语句。

② 每个入口语句 → 到下一个入口语句之前(或到一条转移语句为止)= 一个基本块。

块内常用变换:删除公共子表达式、删除无用(死)代码、合并已知量(常量折叠)、临时变量改名、交换语句次序、代数变换(x*1=xx*2=x+x)。

DAG(无环有向图):叶结点是变量/常量初值,内部结点是运算;相同子表达式共享同一结点 → 自动暴露公共子表达式、无用赋值。

三、循环优化(10.3)

四、老师示范

例题① 划分下面三地址码的基本块。
(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)
例题② 为基本块构造 DAG,找公共子表达式。
(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(强度削弱),初值在循环外算一次(外提)。

五、你来做

1. 基本块的特点是?
2. 下列哪一项不一定是入口语句?
3. DAG 的主要作用是?
4. 代码外提(循环不变式外提)的条件是?
5. 强度削弱通常把什么换成什么?
得分:0 / 5
基本块:单入口单出口;入口=首条/跳转目标/跳转下一条
循环:不变就外提,乘法削弱成加法
📺 主源推荐 哈工大《编译原理》代码优化讲 — 中国大学MOOC[1]
🙋 划分基本块或画 DAG 卡住了?把那段四元式发我,我带你逐条标入口、连结点。下一站是综合模拟卷
  1. [1] 优化概述、基本块与 DAG、循环优化(外提/强度削弱/归纳变量):陈火旺《程序设计语言编译原理》10.1–10.3;哈工大 MOOC代码优化讲。