目录
(1)什么是Liveness?
我们说,变量v在程序点p处是活跃的,如果:
a. 变量v在程序点p'处被使用,且程序点p和p'之间存在一条路径;
b. 变量v在上述路径中没有被定义过;
示意图如下:
(2)什么是Liveness Analysis?
LA是针对程序中的每个程序点(通常是一条指令的前后处),分析出活跃于此处的所有变量。
从 Liveness的定义可看出,LA分析出的活跃变量在程序执行过程中不一定是活跃的,原因在于LA分析中程序点p和p'之间可能存在多条路径,假设变量v在其中一条路径中未被定义过,而在另一条路径中被定义过,那么依据 Liveness的定义,变量v在p处仍是活跃的。但在程序实际执行过程中,被执行的从p到p'的路径,可能恰好是变量v被定义过的那一条,那么此时变量v是非活跃的。 由此可以看出,LA属于may分析。
(3)Liveness Analysis有何用处?
举两个例子来说明
a. 死代码去除。针对每个程序点处的活跃变量集合和程序中出现的每个变量,若某变量v在某程序点之前被赋值过,但v又不在此程序点的活跃变量集合中,这就说明赋予v的值没有被使用过,故此赋值语句没有任何意义,可直接删除以优化程序;
b. 优化寄存器分配。当进行运算时,运算所需的变量需要从内存读取到寄存器中。如果此时所有寄存器已被装满,那么需要将部分变量从寄存器中取出,并存回内存中。将哪些变量从寄存器中取出,而哪些变量可以继续存放在寄存器中这个问题,可利用活跃变量集合来回答。首先获取此运算所位于的程序点处的活跃变量集合,假设一寄存器中存有变量v,另一寄存器中存有变量w,而w在此活跃变量集合中,v不在,那么优先将v从寄存器中取出,保证后续还会很快用到的变量w继续存放于寄存器中。
(4)如何实现Liveness Analysis?
与Reaching Definition Analysis不同,在LA分析之前,我们就知道结束程序点(可能有多个)处的活跃变量集合是空,因为没有任何变量在此后被使用过。而入口程序点处的活跃变量集合则需要分析。因此应以结束程序点作为分析的起点。
此外,要确定某程序点处的活跃变量集合,必须先把此程序点到所有结束程序点的所有可能路径上的指令都扫描一遍。这也表明LA应采用backward分析。
与Reaching Definition Analysis一样,为了实现Liveness Analysis,我们需要知道在LA中,信息是如何传播的。
- 信息在通过指令时的传播规则
首先,分析信息在通过一条指令后会发生什么变化。
我们举例分析:
从上图可以看到,我们分析的方向与程序执行方向相反。在指令p处变量v被重新赋值,因此v在程序点w2处本应不再活跃。但同时v在p处被使用过,因此v在w2处仍活跃。变量b在p处被使用,因此b活跃于w2处。由于未被重新赋值,活跃变量c可以顺利传递到w2。
总结一下规则:
变量v活跃于指令p之前的紧邻程序点q,如果:
a. 变量v在p处被使用(新鲜的活跃变量);
或者
b. 变量v在p之后的紧邻程序点就是活跃的,且在p处未被重新赋值(旧的活跃变量得以顺利传递);
- 信息在汇聚时的传播规则
其次,分析多条信息在某程序点汇聚时会发生什么变化。
与Reaching Definition Analysis一样,LA属于may分析,即在程序点p往后延伸出的所有路径中,只要存在一条路径,变量v在其上被使用过且使用之前未被重新赋值过,那么v在p处就是活跃的。因此当来自不同分支的活跃变量集合在某程序点发生汇聚时,此程序点处的活跃变量集合应是各集合的并集。
- 信息传播规则的形式化表述
因此,对于LA,其在附近的传播规则如下:
其中IN(p)是指令p之前的紧邻程序点处的活跃变量集合,OUT(p)是指令p之后的紧邻程序点处的活跃变量集合,succ(p)是指令p的后继指令,vars(E)是表达式E中所使用的变量。
我们也能从传播规则看出LA属于backward分析,因为IN(p)由OUT(p)运算得来。
为什么是而不是?
前者先把被重新赋值过的变量从活跃变量集合中去掉,再加入刚被使用过的变量,这能正确处理诸如v = v + b,这种对于同一变量既存在赋值操作也存在使用操作的指令。而后者则无法正确处理。
- 基于信息传播规则,求解活跃变量集合
未完待续。