静态程序分析chapter4 - 基于格(Lattice)理论的数据流分析


三、

格理论

函数不动点

      函数不动点用初等数学可以这么理解:连续映射 f 的定义域包含值域,则存在一个 x 使得 f(x) = x 。其中点 (x , f(x))为函数的不动点。

      下面对前面三个示例采用的迭代算法进行分析,以前向分析 & may analysis 为例:little_ant_

      假设给定一个 CFG,节点数量为 k ,抽象域容量为 V。k 是程序中的基本块数量,V 在 RDA 中是程序中的 definition 数量。一次迭代需要更新 k 个 V,描述为集合(V1 × V2 … × Vk),表示为Vk(V 的 k 次方)。Vk是一个 k 元组,里面的每一个元素都是一个抽象域。

      所以每一轮迭代可以看做是应用转换函数和控制流处理之后,从旧的Vk到新的Vk之间的转换,这里用函数 F:Vk Vk 来表示。算法的停止条件是旧的 Vk 和新的 Vk 相同的时候。对应于当所有的 OUT 不发生变化时。

      假设第 i 次迭代之后的结果为 Xi,并且有 Xi+1 = F(Xi)。如果 Xi+1 = Xi ,那么表示在第 i+1 次迭代时算法停止(所有 OUT 不发生变化了),做一个简单的代换可以得到:Xi = F(Xi) 。那么按照函数不动点的定义,认为此时达到了迭代算法的不动点(fixed point)。

      在数据流分析中,通过采用迭代算法产生了一个解决方案。所以产生了三个问题:

      问题1:算法能够保证一定会停止吗或者一定能够达到不动点吗?即迭代算法真的能产生一个解决方案吗?

      问题2:如果问题1的回答是肯定的话,那是否只有一个不动点或一个解决方案?如果解决方案多于一个的话,迭代算法得到的会是最优的吗?

      问题3:什么时候迭代算法能够达到不动点,即什么时候能够得到解决方案?

偏序(Partial Order)

      We define poset as a pair (P, ⊑) where ⊑ is a binary relation that defines a partial ordering over P, and ⊑ has the following properties:
      (1) ∀x ∈ P, x ⊑ x (Reflexivity)
      (2) ∀x, y ∈ P, x ⊑ y ∧ y ⊑ x ⟹ x = y (Antisymmetry)
      (3) ∀x, y, z ∈ P, x ⊑ y ∧ y ⊑ z ⟹ x ⊑ z (Transitivity)

       ⊑ 是集合 P 上的一个二元关系 ,并且满足上面三个属性:自反、反对称和传递,称 ⊑ 定义了在 P 上的偏序关系,(P, ⊑) 是一个偏序集。

      例如:
      1,当 P 为整数集合,⊑ 为小于等于关系时。(P, ⊑) 是一个偏序集。
      2,当 P 为整数集合,⊑ 为小于关系时。(P, ⊑) 不是一个偏序集。因为不满足自反性。
      3,当 P 为英文单词集合,⊑ 为一个单词是另一个单词的子串关系时(比如 a ⊑ b ,意味着单词 a 是单词 b 的子串)。(P, ⊑) 是一个偏序集。

      偏序集中的偏序指的是什么意思呢?
little_ant_
      在上图中,下方的英文单词集合便是一个偏序集。偏序指的是允许集合中的任意两个元素不存在可比性,比如单词 pin 和 sin 之间不存在子串关系。也就是说:没有必要让集合中的任意两个元素满足 ⊑。
      4,当 P 为集合 {a ,b ,c} 的幂集,⊑ 为一个集合是另一个集合的子集关系时。(P, ⊑) 是一个偏序集。

上界和下界

      定义如下:Given a poset (P, ⊑) and its subset S that S ⊆ P, we say that
                        u ∈ P is an upper bound of S, if ∀x ∈ S, x ⊑ u. Similarly,
                        l ∈ P is an lower bound of S, if ∀x ∈ S, l ⊑ x.

      注意:这里上界和下界针对的是偏序集 P 的子集 S。

最小上界和最大下界

      定义如下:We define the least upper bound (lub or join) of S, written ⊔S,if for every upper bound of S, say u, ⊔S ⊑ u.
                        We define the greatest lower bound (glb, or meet) of S, written ⊓S, if for every lower bound of S, say l, l ⊑ ⊓S.

      下图以幂集为例来说明这几个概念之间的区别:
little_ant_

      Usually, if S contains only two elements a and b (S = {a, b}), then
⊔S can be written a ⊔ b (the join of a and b)
⊓S can be written a ⊓ b (the meet of a and b)

glb 和 lub的属性

      一共有两个属性,见下图:
little_ant_

格(lattice)、半格、完备格、乘积格

      格的定义:Given a poset (P, ⊑), ∀a, b ∈ P, if a ⊔ b and a ⊓ b exist, then (P, ⊑) is called a lattice .

      也就是说:对于一个偏序集,如果任意两个元素对存在 lub 和 glb,它就是一个格。

      例如:
      1,当 P 为整数集合,⊑ 为小于等于关系时。(P, ⊑) 是一个格。
      2,当 P 为英文单词集合,⊑ 为一个单词是另一个单词的子串关系时(比如 a ⊑ b ,意味着单词 a 是单词 b 的子串)参见上图。(P, ⊑) 不是一个格。 因为对于单词 pin 和 sin ,它们的 lub 在 P 中不存在。
      3,当 P 为集合 {a ,b ,c} 的幂集,⊑ 为一个集合是另一个集合的子集关系时。(P, ⊑) 是一个格。


      半格的定义:Given a poset (P, ⊑), ∀a, b ∈ P,
                              if only a ⊔ b exists, then (P, ⊑) is called a join semilattice
                              if only a ⊓ b exists, then (P, ⊑) is called a meet semilattice


      完备格的定义:Given a lattice (P, ⊑), for arbitrary subset S of P, if ⊔S and ⊓S exist, then (P, ⊑) is called a complete lattice.

      例如:
      1,当 P 为整数集合,⊑ 为小于等于关系时。(P, ⊑) 不是一个完备格。因为对于所有正整数构成的子集,它不存在上界,也就不存在 ⊔S。
      2,当 P 为集合 {a ,b ,c} 的幂集,⊑ 为一个集合是另一个集合的子集关系时。(P, ⊑) 是一个完备格。
little_ant_


      乘积格的定义:Given lattices L1 = (P1, ⊑1), L2 = (P2, ⊑2), …, Ln = (Pn, ⊑n), if for all i, (Pi , ⊑i) has ⊔i (least upper bound) and ⊓i (greatest lower bound), then we can have a product lattice Ln = (P, ⊑) that is defined by:

• P = P1 × … × Pn
• (x1, …, xn) ⊑ (y1, …, yn) ⟺ (x1 ⊑ y1) ∧ … ∧ (xn ⊑ yn) (乘积格中两个元素满足偏序关系,等价于对应于每一个格中的两个元素满足偏序关系的交集)
• (x1, …, xn) ⊔ (y1, …, yn) = (x1 ⊔1 y1, …, xn ⊔n yn)(乘积格中两个元素的 lub,等价于对应于每一个格中的两个元素的 lub 的集合)
• (x1, …, xn) ⊓ (y1, …, yn) = (x1 ⊓1 y1, …, xn ⊓n yn)(乘积格中两个元素的 glb,等价于对应于每一个格中的两个元素的 glb 的集合)

      并且有:乘积格是一个格。 如果一个乘积格是完备格的乘积,那么这个乘积格也是一个完备格。

数据流分析框架

      见图:

little_ant_

      对上图的说明:

      其中 L 是包含抽象域 V 的一个格,并且具有一个 meet ⊓ o或者 join ⊔ 操作,在数据流分析中,一般取 lub 和 glb 中的一个,比如在 may analysis 中,采用 join ⊔,取 lub;在 must analysis 中,采用 meet ⊓,取 glb。

      左下方采用 RDA 来说明,右下方为一个格,其中的每一个元素都是一个抽象域 V 。可以看到对 OUT[s1] 的值 {a} 和 OUT[s3] 的值 {b} 取 ⊔得到的结果为 {a,b},在 s2 上的转换函数令 IN[s2] = {a,b} 变为 OUT[s2] = {a,b,c},当然 OUT[s2] 也可以为 {a,b}。结合右下方的格来看,may analysis 的初始化为空,即 bottom,通过采用 join ⊔ 操作,不断地往 top 方向上靠拢。

单调性和不动点原理

      在格上函数的单调性定义:A function f: L → L (L is a lattice) is monotonic if ∀x, y ∈ L, x ⊑ y ⟹ f(x) ⊑ f(y)

      不动点原理(定理):Given a complete lattice (L, ⊑), if
                  (1) f: L → L is monotonic and (2) L is finite, then
            the least fixed point of f can be found by iterating
                  f(⊥), f(f(⊥)), …, fk(⊥) until a fixed point is reached
            the greatest fixed point of f can be found by iterating
                  f(T), f(f(T)), …, fk(T) until a fixed point is reached

      这里简单提一句:对于 may analysis ,它是从 bottom 向 top 变化的,不动点原理告诉我们从 ⊥ 出发不断的迭代函数 f ,最后得到的不动点是最小不动点,也就是最优的一个不动点。对于 may analysis ,它一定存在一个最大的不动点 T,在前面的示例中为 11111…111。must analysis 刚好相反,它一定存在一个最小的不动点 ⊥,在前面的示例中为 0000…000。


      关于不动点原理的证明,一是要证明不动点原理的存在,二是要证明所得的不动点为最优的一个。下面仅证明从 ⊥ 出发的红色语句。

little_ant_
little_ant_
      最小不动点的证明中:因为通过不动点原理假设在 k 次迭代得到的不动点小于任意存在的一个不动点( fFix = fk(⊥) ⊑ x ),所以得证。

对前面问题的回答

      问题1:算法能够保证一定会停止吗或者一定能够达到不动点吗?即迭代算法真的能产生一个解决方案吗?
      可以,回忆之前提到的 OUT 的增长是单调的,总会存在一个极限。 may 最大为 T, must 最小为 ⊥。

      问题2:如果问题1的回答是肯定的话,那是否只有一个不动点或一个解决方案?如果解决方案多于一个的话,迭代算法得到的会是最优的吗?
      对于一个函数来讲,只要满足 x = f(x) 即可称 x 为不动点,所以不动点并不唯一。目前我们知道的是根据不动点原理得到的不动点是最优的,而迭代算法是单调的,并且抽象域的大小是有限的,它满足不动点原理的应用条件,所以迭代算法得到的结果是最优的。

      问题3:什么时候迭代算法能够达到不动点,即什么时候能够得到解决方案?
little_ant_
      上面得到的结论是迭代次数的最大值,即最多迭代 i 次就可以达到不动点。其中节点数量 k 很好理解,而格的高度 h 在数据流分析指的是抽象域的大小,上图中幂集格对应的就是抽象域的大小为 3 的数据流分析。

从格的角度来看 may 、must analysis

      宝藏图片如下,这个图片详细介绍了两种数据流分析的特点:
little_ant_

      右边的 may analysis 是 reach definition analysis,最下方为初始化值 ⊥ ,表示在每一个程序点没有一个 definition 能够达到,这是一个不安全的结论(或者说是错误的结论);最上方为 T ,表示在每一个程序点每一个 definition 都可能达到,这是一个安全但是无用的结论(正确但无用)。而迭代算法需要从 unsafe → safe,在 safe 中有多个不动点,其中最小不动点处精度最高,而迭代算法到达的便是最小不动点。 must analysis 类似。

      另一种角度来解释最小、最大不动点。以 may 的最小不动点为例,算法迭代意味着一次次地执行控制流处理和转换函数,其中,转换函数是比较固定的,因为每一个基本块的 genB 和 killB 是不变的。而控制流处理在 may 中采用的 join U ,执行结果为两个元素的最小上界。例如:000 U 001 = 001, 010 U 100 =110 … 而不会一下子就得到 111 。因为在迭代中,我们每次取的都是最小的一步,所以最后达到的不动点必然是最小不动点。

MOP 和迭代算法的精度

      Meet-Over-All-Paths Solution (MOP)指的是分别在 entry 到 exit 之间的每一条路径上执行转换函数,然后将每一条路径的最终结果进行控制流处理。在某些路径不执行的情况下仍进行控制流处理是不精确的,在碰到循环时无法确定边界,在大型程序中路径的数量很多的,不可枚举,所以它不太实用。见下图:
little_ant_
      在下面的例子上看看迭代算法和 MOP 的差别:
little_ant_
      证明如下:
little_ant_
      采用比特位向量或者用 与和或 来代替 join和meet的 Gen/Kill 问题,是可分配的(distributive)。

工作集算法(Worklist Algorithm)

      工作集算法是对迭代算法的优化,在迭代算法的一次迭代中,可以发现,如果某个 OUT[B] 在上一次迭代之后没有变化,那么在下一次迭代中仍然会重复计算 OUT[B]。为了减少这种不必要的运算,引入了工作集算法,算法的思路比较简单,就不谈了。算法如下:
little_ant_

总结

      本文主要介绍了格理论的相关知识,并应用到了数据流分析的迭代算法中,从理论上证明了迭代算法的一些优良特性。从格的视角总结了 may、must analysis的差异性,并对迭代算法的进一步优化产生了工作集算法。后面会单独介绍常量传播分析(Constant Propagation Analysis),这会是一个在格上进行数据流分析的不错的练习。未完待续~

      分享一首小阿七的歌曲《酒家》:https://www.bilibili.com/medialist/play/ml1297618174/BV1Z5411b7YX

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值