跳转至

9 Liveness Analysis

活跃变量分析是一种后向数据流分析,确定每个变量在程序各点是否"活跃"——即当前值是否会在未来被使用。

  • def:变量被赋值的位置(如 a = 1)。
  • use:变量被读取的位置(如 b = a + 1)。
  • live:变量 v 在程序点 p 活跃,当且仅当存在一条从 p 出发的路径,在路径上 v 被使用前未被重新定义。
  • interference:两个变量在程序某点同时活跃,则它们干涉——不能共享同一寄存器。

为什么是后向分析

活跃性是"从未来看现在"——一个变量在点 p 是否活跃,取决于它之后是否被用到。因此信息沿控制流的反方向传播。

整个过程:建图 → 设方程 → 求解

9.1 Build CFG

基本块 (Basic Block) 是满足单一入口、单一出口的最大指令序列。划分时先找出所有首指令(程序首条、跳转目标、跳转指令的下一条),每个首指令到下一个首指令之前构成一个基本块。

Note

实际分析时常将单条语句视为一个基本块,使每个 def/use 精确对应到一个节点,干涉分析更准确。

CFG 的节点为每个基本块(或语句),表示控制流走向(顺序边和跳转边)。为每个节点 \(n\) 记录前驱 pred[n] 和后继 succ[n]

Example

CFG 示例 (以语句为节点): (1) a = 0 (2) b = a + 1 (3) c = c + b ← 循环头 (4) a = b * 2 (5) if a < N goto (3)

pred[3] = {2, 5}    succ[3] = {4}
pred[5] = {4}       succ[5] = {3, exit}

9.2 Dataflow Equations

活跃分析是后向 (Backward) 分析。为每个节点 \(n\) 定义四个集合:

集合 含义
\(\text{in}[n]\) \(n\) 执行活跃的变量
\(\text{out}[n]\) \(n\) 执行活跃的变量
\(\text{use}[n]\) \(n\)被读取的变量(先读后写也算,如 a = a+ba, b 都属于 use)
\(\text{def}[n]\) \(n\)被写入的变量

核心方程:

\[\text{in}[n] = \text{use}[n] \cup (\text{out}[n] - \text{def}[n])\]
\[\text{out}[n] = \bigcup_{s \in \text{succ}[n]} \text{in}[s]\]
  • in 方程:进入时活跃的 = 本节点要用的 + 离开后仍然活跃且没被本节点重新定义的。
  • out 方程:离开时活跃的 = 所有后继入口活跃变量的并集(变量只要在某一条后继路径上活跃,出口就是活跃的)。

9.3 Solving (Fixed-Point Iteration)

数据流方程递归定义,通过不动点迭代求解:

  • 初始化:所有 \(\text{in}[n] = \text{out}[n] = \varnothing\)
  • 迭代:按逆后序(从出口往入口方向)反复更新每个节点,直到全部集合不再变化。
  • 终止:活跃变量集合单调递增而变量总数有限,必然在有限步内收敛。
repeat:
    for each node n in reverse CFG order:
        out[n] = ∪ in[s]  for s ∈ succ[n]
        in[n]  = use[n] ∪ (out[n] - def[n])
until no change

复杂度

最坏 \(O(N \cdot V)\)\(N\) 个节点,\(V\) 个变量)。但实际中通常 2~3 轮即收敛。

9.4 Example

下面完整演示一个程序的活跃分析过程。

程序:计算 1 到 N 的平方和。

a = 0;          // (1)
b = 1;          // (2)
c = 1;          // (3)
a = a + c;      // (4)  ← 循环开始
c = c + 1;      // (5)
b = b + c;      // (6)
if (c <= N)     // (7)
    goto (4);   // (8)
return a;       // (9)

CFG(每条语句一个节点):

     (1) → (2) → (3) → (4) → (5) → (6) → (7)
                         ↑               /   \
                         └── (8) ←──────┘    (9)
节点 pred succ
(1) (2)
(2) (1) (3)
(3) (2) (4)
(4) (3), (8) (5)
(5) (4) (6)
(6) (5) (7)
(7) (6) (8), (9)
(8) (7) (4)
(9) (7)

use/def

节点 语句 use def
(1) a = 0 \(\varnothing\) {a}
(2) b = 1 \(\varnothing\) {b}
(3) c = 1 \(\varnothing\) {c}
(4) a = a + c {a, c} {a}
(5) c = c + 1 {c} {c}
(6) b = b + c {b, c} {b}
(7) if (c <= N) {c, N} \(\varnothing\)
(8) goto (4) \(\varnothing\) \(\varnothing\)
(9) return a {a} \(\varnothing\)

迭代求解(初始所有 in/out 为空,逆序从 (9) 向 (1) 计算):

Round 1

n out 计算 in 计算 out in
(9) 无后继 {a} ∪ ({}−{}) {} {a}
(8) in[4]={} {} ∪ ({}−{}) {} {}
(7) in[8]∪in[9]={a} {c,N} ∪ ({a}−{}) {a} {a,c,N}
(6) in[7]={a,c,N} {b,c} ∪ ({a,c,N}−{b}) {a,c,N} {a,b,c,N}
(5) in[6]={a,b,c,N} {c} ∪ ({a,b,c,N}−{c}) {a,b,c,N} {a,b,c,N}
(4) in[5]={a,b,c,N} {a,c} ∪ ({a,b,c,N}−{a}) {a,b,c,N} {a,b,c,N}
(3) in[4]={a,b,c,N} {} ∪ ({a,b,c,N}−{c}) {a,b,c,N} {a,b,N}
(2) in[3]={a,b,N} {} ∪ ({a,b,N}−{b}) {a,b,N} {a,N}
(1) in[2]={a,N} {} ∪ ({a,N}−{a}) {a,N} {N}

Round 2

n out in 变化?
(9) {} {a}
(8) in[4]={a,b,c,N} {a,b,c,N}
(7) in[8]∪in[9]={a,b,c,N} {a,b,c,N}
(6)~(1) 与 R1 相同 与 R1 相同

Round 3:全部无变化 → 终止。

不动点结果

节点 out in
(1) a=0 {a,N} {N}
(2) b=1 {a,b,N} {a,N}
(3) c=1 {a,b,c,N} {a,b,N}
(4) a=a+c {a,b,c,N} {a,b,c,N}
(5) c=c+1 {a,b,c,N} {a,b,c,N}
(6) b=b+c {a,b,c,N} {a,b,c,N}
(7) if c≤N {a,b,c,N} {a,b,c,N}
(8) goto(4) {a,b,c,N} {a,b,c,N}
(9) return a {} {a}

评论区

对你有帮助的话请给我个赞和 star => GitHub stars
欢迎跟我探讨!!!