Lec 23静态分析 I(Static Analysis I)——数据流分析框架与格
Lec 23 静态分析 I(Static Analysis I)——数据流分析框架与格
把前面零散用过的分析(类型分析、值分析/常量传播、活跃性)统一到一个通用静态分析框架。本讲讲清楚五个关键概念:事实 (Facts)、合并 (Merging)、转移函数 (Transfer Functions)、算法 (Chaotic Iteration)、终止 (Fixpoints),并引入格 (lattice) 来刻画分析的精度与合并操作。
TL;DR
- 数据流分析与抽象解释把类型、常量、活跃性等问题统一为 CFG 上的事实、转移函数、合并、迭代与不动点。
- 事实空间可以跟踪常量、符号表达式、区间或值集;追踪能力越强,精度越高,但时间和空间成本也越大。
- 控制流汇合点需要安全地合并不同路径事实,格用精度偏序与 join / meet 定义这种过近似。
1. 回顾:我们已经用过的优化
定义(高级优化清单)
-
类型分析:尽量确定操作数类型(→ 消除类型检查);
-
形状分析:尽量确定操作数形状(如 record
{a:1,b:2}的字段集{a,b}); -
值分析:尽量确定操作数值(→ 常量传播);
-
依赖与活跃性分析:→ 死代码消除、寄存器分配。
四条 takeaway 同 L19:可推断的信息很多、IR 是编码载体、从变换后程序生成代码、优化彼此交互需多轮。
优化的版图自 1960s 起极其丰富——Frances Allen 1966 的《Program Optimization》奠定了系统化分析与变换的概念基础(图灵奖引文)。用基准测试 (benchmarks) 指导选哪些优化。 更多内容见 P5 概览、6.035、Berkeley CS294。
本讲的问题:前面这些分析各写各的,有没有统一的理论框架? 有——数据流分析 / 抽象解释。
2. 引子:常量传播需要"到达定义"
例子(CFG,循环里 s = s + a*b):
s = 0; a = 4; i = 0;
if (k == 0): b = 1; else: b = 2;
while (i < n):
s = s + a*b;
i = i + 1;
return s
例题(a 是常量吗?b 是常量吗?)
-
s = s + a*b处 a 是常量 4?—— 是! 因为所有到达此处的定义 (reaching definitions) 都是a = 4。 -
b 是常量?—— 否! 一条到达定义是
b = 1,另一条是b = 2(来自 if 的两支),合并后值不唯一。 :::
于是可做常量传播变换:s = s + a*b → s = s + 4*b(a 换成 4,b 不能换)。
关键难点:循环带回边、if 有分叉合并——必须有办法沿 CFG 传播事实、在合并点汇总、且在循环里收敛终止。这正是数据流框架要解决的。
3. 静态分析的五个关键概念
::: definition 定义(Static Analysis: Key Concepts)
-
事实 (Facts):要追踪的性质空间——一个集合,更确切地是一个格 (lattice),以支持控制流、循环与终止性推理;
-
符号/抽象执行 (Transfer Functions):如何刻画一个基本块对事实的影响;
-
合并 (Merging):多分支汇合时如何合并事实(join / meet);
-
算法 (Chaotic Iteration):如何计算(混沌迭代 / 工作表);
-
终止 (Termination):分析何时停(不动点 fixpoint)。 :::
4. 通用分析框架:数据流分析 vs 抽象解释
::: definition 定义(两大框架)
-
数据流分析 (Dataflow Analysis):Kildall, 1973;传统用于编译优化;
-
抽象解释 (Abstract Interpretation):Cousot & Cousot, 1977;意图相近但理论更丰富。
共同点:把分析问题表述成 CFG 上的一组方程,求解之。
我们在 L21 写过的活跃性方程(IN/OUT/USE/DEF + 工作表)正是这个框架的一个实例;本讲把它一般化。
5. 事实 / 性质:选择追踪什么
定义(分析 = 它追踪的一组事实/性质)
不同分析 = 不同的事实空间:
-
常量分析:变量的事实是 Z 中一个已知值(例:常量传播);
-
符号分析 (Sign):事实 ∈ {0, 正, 负};
-
区间分析 (Range):事实是闭区间 [a,b](a,b 整数);用于缩小整数表示位宽或检查溢出(Stephenson, Babb, Amarasinghe, Bitwidth Analysis, PLDI'00);
-
值集合 (Value Set):追踪变量可能取值的集合;用于对少量取值特化代码。 :::
精度从粗到细:符号 ⊂ 区间 ⊂ 值集合 ⊂ 精确值——越精确越能优化,但越贵、越难收敛。选哪种是工程权衡。
6. 合并事实(Merging)与精度
在控制流汇合点,要把多条分支的事实合并成一个新事实:
-
新事实应是两支事实的并 (union);
-
新事实仍须落在该分析的事实集合内;
-
常常是过近似 (overapproximation)——合并结果的取值集合可能比真正的并集还大。
由此引入精度 (precision) 概念:分析可能追踪不到最精确的事实。
6.1 不同分析合并同一对值的结果
合并左支 b=v1、右支 b=v2,看四种分析给出什么:
| 左/右 | 常量 (Constant) | 符号 (Sign) | 区间 (Interval) | 值集合 (Set) |
|---|---|---|---|---|
| 1 / 1 | 1(精确) | + | [1,1] | {1} |
| 1 / 2 | ⊤/?(非常量) | + | [1,2] | {1,2} |
| 0 / 1 | ? | 非负 | [0,1] | {0,1} |
| -1 / 1 | ? | ⊤(任意符号) | [-1,1] | {-1,1} |
同样是
1和2合并:常量分析只能放弃说"不是常量"(精度低),而区间分析能说[1,2]、值集合能说{1,2}(精度高)。合并算子的设计决定精度。
6.2 关键问题:合并用哪个事实?"?" 是什么?
定理(用格来回答合并)
把事实放进一个格 (lattice)——它给事实之间建立精度的偏序关系,并提供把事实并起来的运算(join/meet)。合并 = 在格上取相关元素的最小上界 (join)(或对偶的 meet)。
那个 "?" 通常就是格的顶 ⊤("不知道/任意");对偶的底 ⊥ 表示"尚无信息"。
格的引入解决三件事:① 合并有了良定义的运算(join);② 精度有了序(越往上越粗);③ 配合"格高度有限 + 转移函数单调"可证明不动点迭代必终止(详见 L24)。
7. 算法预告:混沌迭代(Chaotic Iteration)
定义(Chaotic Iteration)
反复对 CFG 各结点套用"转移函数 + 合并",直到所有结点的事实不再变化(达到不动点)。结点处理顺序可以任意("混沌"),只要持续直到稳定即可——这与 L21 活跃性的工作表算法是同一思想。
例(示意,求各点的事实):
y=0; t=1;
x=x+1; y=y+2; t=t+2;
y=t-1;
end
在 P1…P5 各点反复传播常量/值事实,直至收敛。具体的转移函数定义、单调性与不动点终止性证明,是 L24 的内容。
8. 与参考资料的对应(补充)
- 数据流分析:Kildall (1973);抽象解释:Cousot & Cousot (1977)。这两篇是本框架的源头。
- 区间/位宽分析:Stephenson, Babb, Amarasinghe, Bitwidth Analysis, PLDI'00。
- 更多数据流优化(公共子表达式消除、自动并行化、数据布局优化)见 MIT 6.035、Berkeley CS294 (wolczko.com/CS294)。
- 形式化的格/不动点理论亦见姊妹课 6.5110《Foundations of Program Analysis》(index.md 列出)。Crafting Interpreters 不涉及数据流分析。
9. 本讲小结
- 把类型/值/活跃性等分析统一到通用静态分析框架:数据流分析 (Kildall) / 抽象解释 (Cousot²),核心是把问题写成 CFG 上的方程。
- 五个关键概念:事实、转移函数、合并、混沌迭代算法、不动点终止。
- 常量传播依赖到达定义:所有到达定义一致才是常量(a=4 是,b 因 if 两支不一致而否)。
- 事实空间的选择(常量/符号/区间/值集合)决定精度与成本。
- 合并发生在控制流汇合点,常是过近似;用格 (lattice) 给事实建立精度偏序并定义 join 合并,"?" 即格顶 ⊤。
- 下一讲(L24):转移函数的形式化、格的单调性、以及不动点迭代为何终止。