Bit-Vector框架(2) — Live Variables Analysis

Bit-Vector框架(2) — Live Variables Analysis

x>=0 ∧ y>0
q := 0
r := x
r >= y
r := r-y
q := q+1
r < y
out!r
q0
qx
q1
q2
q3
q4
q5
q6
图2.3 取模函数的程序图

以下是4个Bit-Vector Framework的数据流分析经典例子。

  • Reaching Definition Analysis:变量/数组在哪里最新被定义它们的值
  • Live Variables Analysis(本文):变量/数组的值在重新被定义之前(或者程序结束之前),是否被使用
  • Available Expressions Analysis:哪些表达式之前已经被计算过,当再次进行计算时能够得到相同的值
  • Very Busy Expressions Analysis:哪些表达式在哪些点被计算后,程序结束前仍然被计算,并且计算的结果相等。

2. Live Variables

2.1 Live Variables简介

LV分析求解的信息

  • 求解程序图中的每个节点处哪些变量/数组在它们被重新定义前(或者程序结束前)可能被使用。这些变量我们认为是活跃(live)变量,否则是死(dead)变量。

例子(图2.3 中)

  • 在程序计算到q3处,之后就不再有变量x的使用。Dead(q3) = {x},Live(q3) = {y, q, r}
  • 在程序计算到q6处,只有变量r的值需要被后续使用。Live(q6) = {r},Dead(q6) = {x, y, q}

LV求解信息的用途

  • 编译器构造中很有用。比如:一个变量存储在寄存器中,LV的信息可以确定是否该寄存器(该变量)可能会被重用(reuse)作其它用途(没有的话,我们可以直接随意覆盖该寄存器的值,以节约寄存器资源)。
  • 编译器构造和程序理解:程序中执行某些计算,在程序的后续执行中从没有使用过。(这种问题可能出现在一个被多个程序员维护的程序中)
  • 安全: 检测变量违规使用:本意是只让某个变量被某次使用后就不再使用,但是通过LV信息得到它仍然还在使用。
2.2 分析的结果定义

定义LV函数,它映射每个程序点到一个变量/数组的集合。
L V : Q → P o w e r S e t (    ( V a r ∪ A r r )    ) LV: Q \rightarrow PowerSet(\ \ (Var \cup Arr)\ \ ) LV:QPowerSet(  (VarArr)  )
LV映射程序图中每个节点到一个变量/数组的集合。

在图2.3中,我们知道
Q = { q 0 , q 1 , q 2 , q 3 , q 4 , q 5 , q 6 , q x } Q = \{q_0, q_1, q_2, q_3, q_4, q_5, q_6, q_x\} Q={q0,q1,q2,q3,q4,q5,q6,qx}
而求解出来的LV应该满足如下条件(后续会介绍怎么一步步求解LV函数):
L V ( q 0 )     ⊇ { x , y } L V ( q 1 )     ⊇ { x , y } L V ( q 2 )     ⊇ { x , y , q } L V ( q 3 )     ⊇ { y , q , r } L V ( q 4 )     ⊇ { y , q , r } L V ( q 5 )     ⊇ { y , q , r } L V ( q 6 )     ⊇ { r } L V ( q x )     ⊇ { } \begin{aligned} LV(q_0) \ & \ \supseteq \{x, y\} \\ LV(q_1) \ & \ \supseteq \{x, y\} \\ LV(q_2) \ & \ \supseteq \{x, y, q\} \\ LV(q_3) \ & \ \supseteq \{y, q, r\} \\ LV(q_4) \ & \ \supseteq \{y, q, r\} \\ LV(q_5) \ & \ \supseteq \{y, q, r\} \\ LV(q_6) \ & \ \supseteq \{r\} \\ LV(q_x) \ & \ \supseteq \{\} \\ \end{aligned} LV(q0) LV(q1) LV(q2) LV(q3) LV(q4) LV(q5) LV(q6) LV(qx)  {x,y} {x,y} {x,y,q} {y,q,r} {y,q,r} {y,q,r} {r} {}
右侧的集合在任何情况下(不管程序如何执行)都满足,并且这个集合是满足条件的最小集合,那么我们就认为这是最好/最小的解。

2.3 路径上使用了什么
2.3.1 定义程序单个行为的语义函数

首先分析对于每个行为act,那个变量/数组会被使用:
U s e ( x : = a ) = f v ( a ) U s e ( A [ a 1 ] = a 2 ) = f v ( a 1 )   ∪   f v ( a 2 ) U s e ( c ? x ) = { } U s e ( c ? A [ a ] ) = f v ( a ) U s e ( c ! a ) = f v ( a ) U s e ( b ) = f v ( b ) U s e ( s k i p ) = { } \begin{aligned} &Use(x := a) &&= fv(a) \\ &Use(A[a_1]=a_2) &&= fv(a1) \ \cup \ fv(a2) \\ &Use(c?x) && = \{\} \\ &Use(c?A[a]) &&= fv(a) \\ &Use(c!a) &&= fv(a) \\ &Use(b) &&= fv(b) \\ &Use(skip) &&= \{\} \\ \end{aligned} Use(x:=a)Use(A[a1]=a2)Use(c?x)Use(c?A[a])Use(c!a)Use(b)Use(skip)=fv(a)=fv(a1)  fv(a2)={}=fv(a)=fv(a)=fv(b)={}
对于一个表达式a,我们使用一个函数fv(a)表示表达式a中所使用到的变量集合,例如,a: x + y, 其中x,y为简单变量,那么fv(a) = {x, y}

下面给出fv函数定义:
f v ( n ) = { } n 为 整 数 字 面 量 f v ( x ) = { x } x 为 简 单 变 量 f v ( A [ a 0 ] ) = { A }   ∪   f v ( a 0 ) f v ( a 1    O P a    a 2 ) = f v ( a 1 )   ∪   f v ( a 2 ) f v ( − a 0 ) = f v ( a 0 ) f v ( t r u e ) = { } f v ( f a l s e ) = { } f v ( a 1    O P r    a 2 ) = f v ( a 1 )   ∪   f v ( a 2 ) f v ( b 1    O P b    b 2 ) = f v ( b 1 )   ∪   f v ( b 2 ) f v (   b 0 ) = f v ( b 0 ) \begin{aligned} &fv(n) &&= \{\} && n为整数字面量\\ &fv(x) &&= \{x\} && x为简单变量\\ &fv(A[a0]) &&= \{A\} \ \cup \ fv(a0) && \\ &fv(a1 \ \ OPa \ \ a2) &&= fv(a1) \ \cup \ fv(a2) \\ &fv(-a0) &&= fv(a0) \\ &fv(true) &&= \{\} \\ &fv(false) &&= \{\} \\ &fv(a1 \ \ OPr \ \ a2) &&= fv(a1) \ \cup \ fv(a2) \\ &fv(b1 \ \ OPb \ \ b2) &&= fv(b1) \ \cup \ fv(b2) \\ &fv(\text{~}b0) &&= fv(b0) \end{aligned} fv(n)fv(x)fv(A[a0])fv(a1  OPa  a2)fv(a0)fv(true)fv(false)fv(a1  OPr  a2)fv(b1  OPb  b2)fv( b0)={}={x}={A}  fv(a0)=fv(a1)  fv(a2)=fv(a0)={}={}=fv(a1)  fv(a2)=fv(b1)  fv(b2)=fv(b0)nx
例如:

  • fv(x * y) = fv(x) ∪ \cup fv(y) = {x} ∪ \cup {y} = {x, y}
  • fv(A[i] = x) = fv(i) ∪ \cup fv(x) = {i} ∪ \cup {x} = {i, x}
2.3.2 一条路径上变量x的Use函数

对于程序中的一条路径Pi:
P i =   q 0 , a 1 , q 1 , a 2 , q 2 , . . . , q n − 1 , a n , q n 其 中 , n ≥ 0 q i ∈ Q , 0 ≤ i < n a j ∈ A c t , 1 ≤ j ≤ n \begin{aligned} Pi = &\ q_0, a_1, q_1, a_2, q_2, ..., q_{n-1}, a_n,q_n \\ 其中,&n \geq 0 \\ &q_i \in Q, 0 \leq i < n\\ &a_j \in Act, 1 \leq j \leq n \end{aligned} Pi= q0,a1,q1,a2,q2,...,qn1,an,qnn0qiQ,0i<najAct,1jn
我们定义一条路径Pi上对于变量x的Use函数为:

U s e ( P i , x ) = ∃ i : x ∈ U s e ( a i ) ∧ ∀ j < i : x ∉ D e f ( a j ) Use(Pi, x) = \exist i:x\in Use(a_i) \wedge \forall j < i: x \notin Def(a_j) Use(Pi,x)=i:xUse(ai)j<i:x/Def(aj)

Use(Pi, x)表示对于一条路径Pi,变量x是否被使用。Use(Pi, x)的true/false与否取决于,是否:

  • 路径中存在某个行为a,使得x被使用;并且在该路径中a前面所有路径节点中,不存在任何行为使得x被定义。

也就是说,路径上使用了未被定义过的变量x,那么我们就认为这条路径使用过变量x,记作

Use(Pi, x) = true

例如,对于图2.3中的路径Pi:
P i = { q 0 ,   x > = 0 ∧ y > 0 ,   q 1 ,   q : = 0 ,   q 2 ,   r : = x ,   q 3 , r < y ,   q 6 ,   o u t ! r ,   q x } Pi = \{q_0, \ x>=0 \wedge y>0, \ q_1, \ q:=0, \ q_2, \ r:=x, \ q_3, r<y, \ q_6, \ out!r, \ q_x\} Pi={q0, x>=0y>0, q1, q:=0, q2, r:=x, q3,r<y, q6, out!r, qx}

  • Use(Pi, x) = true

  • Use(Pi, y) = true

  • Use(Pi, q) = false

  • Use(Pi, r) = false

2.3.3 一条路径上数组A的Use函数

而对于数组变量,Use(Pi, A)函数的定义为:
U s e ( P i , A ) = ∃ a i : A ∈ U s e ( a i ) Use(Pi, A) = \exist a_i: A \in Use(a_i) Use(Pi,A)=ai:AUse(ai)
这里对数组作保守分析,只要路径上使用了数组A,那么我们就认为该路径使用了数组A

2.3.4 总结

综上,对于一条路径Pi,它的Use函数Use(Pi)定义了该路径使用到的变量/数组的集合:
U s e ( P i ) = { x ∈ V a r   ∣   U s e ( P i , x ) = t r u e }   ∪   { A ∈ A r r   ∣   U s e ( P i , A ) = t r u e } Use(Pi) = \{x \in Var \ | \ Use(Pi, x)=true \} \ \cup \ \{A \in Arr \ | \ Use(Pi, A) = true\} Use(Pi)={xVar  Use(Pi,x)=true}  {AArr  Use(Pi,A)=true}

通过上面的概念,我们能够重新定义Live Variables Analysis的目的:

对于程序图上每个节点q,我们想要求解出从节点q开始,到节点qx​的所有路径中,将要被使用到的所有变量/数组的集合。

LV分析的结果总结了(summaries)程序图上每条从节点q到节点qx的路径Pi,使得Use(Pi) ⊆ \subseteq LV(q)。

能够总结出程序点q的所有从q到qx路径的最小(least)分析结果,我们也称之为 MOP解(Merge Over Paths solution)

2.4 LV分析的约束

2.3是通过将所有路径的定义结果进行merge合并,这并不是一种有效的计算正确的RD分析的方法。因为很多时候我们静态地并不能够分析出所有的可能执行路径,所以很难将所有路径的结果进行merge。

为了改进上述方法。现在,我们定义一个约束系统,LV函数必须满足,之后我们会给出算法来求解这些约束。

程序图
提取出LV分析的约束
求解约束
LV分析的结果集

在定义约束系统之前,我们先定义一下约束系统中的约束因子:KILL和GEN

对于程序图中每条边(qs, a, qt),我们定义所谓的对Live Variables的KILL函数和GEN函数:

aKILL(q s _s s, a, q t _t t)GEN(q s _s s, a, q t _t t)解释
x := a{x}fv(a)1. 此边重定义x,x到此为止不是live variable
A[a1] := a2{}fv(a1) ∪ \cup fv(a2)2. 保守分析,不Kill掉数组;生成新的Live Variables
c?x{x}{}同1
c?A[a]{}fv(a)同2
c!a{}fv(a)3. 使用到表达式a,生成fv(a)
b{}fv(b)同3
Skip{}{}无语义

KILL,GEN的目的是为RD分析的约束服务。现在我们定义约束:

  • 对于程序图上的每条边edge(qs, a, qt),必须满足:

∀ ( q s , a , q t )   ∈   E d g e L V ( q s )   ⊇   (   L V ( q t ) − K I L L ( q s , a , q t )   )   ∪   G E N ( q s , a , q t ) \begin{aligned} \forall (q_s, a, q_t)\ &\in \ Edge \\ LV(q_s) \ &\supseteq \ (\ LV(q_t) - KILL(q_s, a, q_t) \ ) \ \cup \ GEN(q_s, a, q_t) \end{aligned} (qs,a,qt) LV(qs)  Edge ( LV(qt)KILL(qs,a,qt) )  GEN(qs,a,qt)

  • 对于程序结束点qx,额外要求:

L V ( q x ) ⊇ { } LV(q_x) \supseteq \{\} LV(qx){}

前者表示,从边(qs, a, qt)的终点qt传递过来的Live variables集合可能会通过该边的a行为kill掉部分live variables。于此同时a行为又会产生live variables。约束条件中存在一个子集的概念,也就是说,无论qs的后继节点是哪个qt,右侧求出的集合一定是LV(qs)的子集。因此,可以这么认为:对qs的所有后继qt,求解右侧的集合结果运算,并将这些计算并集,就会得到LV(qs)。

后者约束条件默认为空。当然我们也能指定某些变量,用于表示我们对某个变量感兴趣(让它在程序终点处于Live状态,即使它是dead状态,我们也强制认为它是Live状态)。如 L V ( q x ) ⊇ { y } {LV(q_x) \supseteq} \{y\} LV(qx){y} 表示我们对变量y感兴趣,它在程序终点处于Live状态。(比如:我们不想要让y变量所在的寄存器被重用)

下面是一个简单的例子:

r = y
y = x
x = 10
y = x
q0
LV(q0) = {}
q1
LV(q1) = {}
q2
LV(q2) = {}
q3
LV(q3) = {}
qx
LV(qx) = {}
r = y
y = x
x = 10
y = x
q0
LV(q0) = {}
q1
LV(q1) = {}
q2
LV(q2) = {}
q3
LV(q3) = {x}
qx
LV(qx) = {}
r = y
y = x
x = 10
y = x
q0
LV(q0) = {}
q1
LV(q1) = {}
q2
LV(q2) = {}
q3
LV(q3) = {x}
qx
LV(qx) = {}
r = y
y = x
x = 10
y = x
q0
LV(q0) = {}
q1
LV(q1) = {x}
q2
LV(q2) = {}
q3
LV(q3) = {x}
qx
LV(qx) = {}
r = y
y = x
x = 10
y = x
q0
LV(q0) = {x, y}
q1
LV(q1) = {x}
q2
LV(q2) = {}
q3
LV(q3) = {x}
qx
LV(qx) = {}

根据上述约束,我们重新定义一下Live Variables Analysis的目的:

LV分析就是根据约束来求解出每个程序点的LV函数值,上述约束要在任何时候(等同于任何执行路径)都满足

2.5 求解约束

输 入 : 集 合 Q 包 含 程 序 图 中 所 有 节 点 ; 程 序 结 束 节 点 q x ; 边 集 合 E 输 出 : L V : L i v e   V a r i a b l e s   A n a l y s i s 分 析 的 结 果 函 数 算 法 : ∀ q ∈ Q , 让 L V ( q ) = { } W h i l e   仍 然 存 在 ( q s , a , q t ) ∈ E , 使 得 L V ( q s ) ⊉ (   L V ( q t ) − K I L L ( q s , a , q t )   )   ∪   G E N ( q s , a , q t )              那 么 令 L V ( q s ) : = L V ( q s )   ∪   (   L V ( q t ) − K I L L ( q s , a , q t )   )   ∪   G E N ( q s , a , q t ) \begin{aligned} 输入:&集合Q包含程序图中所有节点;程序结束节点q_x;边集合E \\ 输出:&LV:Live \ Variables \ Analysis分析的结果函数 \\ 算法:&\\ &\forall q \in Q,让LV(q) = \{\} \\ &While \ 仍然存在(q_s, a, q_t) \in E,使得LV(q_s) \not\supseteq (\ LV(qt)-KILL(q_s, a, q_t) \ ) \ \cup \ GEN(q_s, a, q_t) \\ & \ \ \ \ \ \ \ \ \ \ \ \ 那么令LV(qs) := LV(qs) \ \cup \ (\ LV(qt)-KILL(q_s, a, q_t) \ ) \ \cup \ GEN(q_s, a, q_t) \end{aligned} QqxELVLive Variables AnalysisqQLV(q)={}While (qs,a,qt)E使LV(qs)( LV(qt)KILL(qs,a,qt) )  GEN(qs,a,qt)            LV(qs):=LV(qs)  ( LV(qt)KILL(qs,a,qt) )  GEN(qs,a,qt)

此算法求解约束,得到最小分析结果,我们也称之为MFP解(Minimal Fixed Point solution)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值