活跃变量分析
活跃变量分析(Live Variable Analysis)是编译器优化和静态分析的一项重要技术,用于确定在程序的每个程序点(通常是每个基本块的出口)上哪些变量仍然是“活跃”的,也就是在程序执行到该点时仍然会被使用。
活跃变量分析通常用于以下两个主要领域:
寄存器分配:在编译器优化中,了解哪些变量在每个程序点上仍然是活跃的,有助于进行寄存器分配。只有活跃的变量需要存储在寄存器中,因此可以在寄存器之间有效地分配变量,以最大程度地减少内存访问。
死代码消除:在静态分析中,了解哪些变量在程序中不再被使用,有助于进行死代码消除。通过删除不再使用的变量和相关代码,可以减小程序的大小并提高执行效率。
java样例
class Assign {
int assign(int a, int b, int c) {
int d = a + b;
b = d;
c = a;
return b;
}
}
分析结果
-------------------- <Assign: void <init>()> (livevar) --------------------
[0@L1] invokespecial %this.<java.lang.Object: void <init>()>(); []
[1@L1] return; []
-------------------- <Assign: int assign(int,int,int)> (livevar) --------------------
[0@L4] d = a + b; [a, d]
[1@L5] b = d; [a, b]
[2@L6] c = a; [b]
[3@L7] return b; []
活跃变量算法设计
方向:为了确定某BB后var是否live,只需从exit bb往前判断该var是否use而非def
边界条件:因为活跃算法分析是backward,边界条件为exit点处In、Out集合为空
初始化: 为每个BB的In、Out集合初始化为空
交汇处理:Out[S1] = ∪ In[S1后继]
转换函数 : In[B] = UseB ∪ (Out[B] - DefB)
数据结构设计与算法实现
数据结构:
- 集合,用来进行交、并操作。实现如下:
public class SetFact<E> {
protected final Set<E> set;
public SetFact(Collection<E> c) {
set = Sets.newHybridSet(c);
}
public SetFact() {
this(Collections.emptySet());
}
/**
* @return true if this set contains the specified element, otherwise false.
*/
public boolean contains(E e) {
return set.contains(e);
}
/**
* Adds an element to this fact.
*
* @return true if this fact changed as a result of the call, otherwise false.
*/
public boolean add(E e) {
return set.add(e);
}
/**
* Removes an element from this fact.
*
* @return true if an element was removed as a result of the call, otherwise false.
*/
public boolean remove(E e) {
return set.remove(e);
}
/**
* Removes all the elements of this fact that satisfy the given predicate.
*
* @return true if any elements were removed as a result of the call,
* otherwise false.
*/
public boolean removeIf(Predicate<E> filter) {
return set.removeIf(filter);
}
/**
* Unions other fact into this fact.
*
* @return true if this fact changed as a result of the call, otherwise false.
*/
public boolean union(SetFact<E> other) {
return set.addAll(other.set);
}
/**
* @return a new fact which is the union of this and other facts.
*/
public SetFact<E> unionWith(SetFact<E> other) {
SetFact<E> result = copy();
result.union(other);
return result;
}
/**
* Intersects this fact with other fact.
*
* @return true if this fact changed as a result of the call, otherwise false.
*/
public boolean intersect(SetFact<E> other) {
return set.retainAll(other.set);
}
/**
* @return a new fact which is the intersection of this and other facts.
*/
public SetFact<E> intersectWith(SetFact<E> other) {
SetFact<E> result = copy();
result.intersect(other);
return result;
}
/**
* Sets the content of this set to the same as other set.
*/
public void set(SetFact<E> other) {
clear();
union(other);
}
/**
* Creates and returns a copy of this fact.
*/
public SetFact<E> copy() {
return new SetFact<>(this.set);
}
/**
* Clears all content in this fact.
*/
public void clear() {
set.clear();
}
public boolean isEmpty() {
return set.isEmpty();
}
public Stream<E> stream() {
return set.stream();
}
public int size() {
return set.size();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof SetFact<?> that)) {
return false;
}
return set.equals(that.set);
}
@Override
public int hashCode() {
return set.hashCode();
}
@Override
public String toString() {
return CollectionUtils.toString(set);
}
}
- 结果数据流图,保存cfg上每一个BB对应的In、Out集合。实现如下:
public class DataflowResult<Node, Fact> implements NodeResult<Node, Fact> {
private final Map<Node, Fact> inFacts = new LinkedHashMap<>();
private final Map<Node, Fact> outFacts = new LinkedHashMap<>();
/**
* @return the flowing-in fact of given node.
*/
@Override
public Fact getInFact(Node node) {
return inFacts.get(node);
}
/**
* Associates a data-flow fact with a node as its flowing-in fact.
*/
public void setInFact(Node node, Fact fact) {
inFacts.put(node, fact);
}
/**
* @return the flowing-out fact of given node.
*/
@Override
public Fact getOutFact(Node node) {
return outFacts.get(node);
}
/**
* Associates a data-flow fact with a node as its flowing-out fact.
*/
public void setOutFact(Node node, Fact fact) {
outFacts.put(node, fact);
}
}
- 单IR语句数据结构。实现如下:
public interface Stmt extends Indexable {
/**
* @return the index of this Stmt in the container IR.
*/
@Override
int getIndex();
void setIndex(int index);
/**
* @return the line number of this Stmt in the original source file.
* If the line number is unavailable, return -1.
*/
int getLineNumber();
void setLineNumber(int lineNumber);
/**
* @return the (optional) left-value expression defined in this Stmt.
* In Tai-e IR, each Stmt can define at most one expression.
*/
Optional<LValue> getDef();
/**
* @return a list of right-value expressions used in this Stmt.
*/
List<RValue> getUses();
/**
* @return true if execution after this statement could continue at
* the following statement, otherwise false.
*/
boolean canFallThrough();
<T> T accept(StmtVisitor<T> visitor);
}
活跃变量算法实现
- 单BB处的LiveVariableAnalysis。实现如下:
public class LiveVariableAnalysis extends
AbstractDataflowAnalysis<Stmt, SetFact<Var>> {
public static final String ID = "livevar";
public LiveVariableAnalysis(AnalysisConfig config) {
super(config);
}
/**
* backward分析
* @return
*/
@Override
public boolean isForward() {
return false;
}
/**
* 边界条件初始化
* In[exit] = ∅
* @param cfg
* @return
*/
@Override
public SetFact<Var> newBoundaryFact(CFG<Stmt> cfg) {
return new SetFact<>();
}
/**
* 基本块初始化
* for(each BB b|exit)
* In[B] = ∅
* @return
*/
@Override
public SetFact<Var> newInitialFact() {
return new SetFact<>();
}
/**
* meet 操作
* 将fact集合并入target集合
* out[S1] = in[S2] ∪ in[S3]
* @param fact in[successor]
* @param target out[node]
*/
@Override
public void meetInto(SetFact<Var> fact, SetFact<Var> target) {
target.union(fact);
}
/**
* transfer函数操作单条语句
* In[B] = UseB ∪ (Out[B] - DefB)
* Rvalue 包括 var、literal、unaryexp、binaryexp
* 这里只考虑var
* @param stmt
* @param in
* @param out
* @return
*/
@Override
public boolean transferNode(Stmt stmt, SetFact<Var> in, SetFact<Var> out) {
boolean flag;
SetFact<Var> tmpOut = out.copy();
Optional<LValue> def = stmt.getDef();
List<RValue> use = stmt.getUses();
//判断左值是否存在
//左值只有一个
if(def.isPresent() && def.get() instanceof Var defVal){
tmpOut.remove(defVal);
}
// flag = in.union(tmpOut);
// for(RValue rvalue : use){
// if(rvalue instanceof Var useVal){
// flag |= in.add(useVal);
// }
// }
for(RValue rv : use){
if(rv instanceof Var useVal)
tmpOut.add(useVal);
}
flag = (!tmpOut.equals(in));
in.clear();
in.set(tmpOut);
return flag;
}
}
- 迭代求解器。实现如下:
public abstract class Solver<Node, Fact> {
protected final DataflowAnalysis<Node, Fact> analysis;
protected Solver(DataflowAnalysis<Node, Fact> analysis) {
this.analysis = analysis;
}
/**
* Static factory method to create a new solver for given analysis.
*/
public static <Node, Fact> Solver<Node, Fact> makeSolver(
DataflowAnalysis<Node, Fact> analysis) {
return new IterativeSolver<>(analysis);
}
/**
* Starts this solver on the given CFG.
*
* @param cfg control-flow graph where the analysis is performed on
* @return the analysis result
*/
public DataflowResult<Node, Fact> solve(CFG<Node> cfg) {
DataflowResult<Node, Fact> result = initialize(cfg);
doSolve(cfg, result);
return result;
}
/**
* Creates and initializes a new data-flow result for given CFG.
*
* @return the initialized data-flow result
*/
private DataflowResult<Node, Fact> initialize(CFG<Node> cfg) {
DataflowResult<Node, Fact> result = new DataflowResult<>();
if (analysis.isForward()) {
initializeForward(cfg, result);
} else {
initializeBackward(cfg, result);
}
return result;
}
protected void initializeForward(CFG<Node> cfg, DataflowResult<Node, Fact> result) {
throw new UnsupportedOperationException();
}
protected void initializeBackward(CFG<Node> cfg, DataflowResult<Node, Fact> result) {
result.setInFact(cfg.getExit(), this.analysis.newBoundaryFact(cfg));
result.setOutFact(cfg.getExit(), this.analysis.newBoundaryFact(cfg));
for(Node node : cfg){
if(cfg.isExit(node))
continue;
result.setInFact(node, this.analysis.newInitialFact());
result.setOutFact(node, this.analysis.newInitialFact());
}
}
/**
* Solves the data-flow problem for given CFG.
*/
private void doSolve(CFG<Node> cfg, DataflowResult<Node, Fact> result) {
if (analysis.isForward()) {
doSolveForward(cfg, result);
} else {
doSolveBackward(cfg, result);
}
}
protected abstract void doSolveForward(CFG<Node> cfg, DataflowResult<Node, Fact> result);
protected abstract void doSolveBackward(CFG<Node> cfg, DataflowResult<Node, Fact> result);
}
class IterativeSolver<Node, Fact> extends Solver<Node, Fact> {
public IterativeSolver(DataflowAnalysis<Node, Fact> analysis) {
super(analysis);
}
@Override
protected void doSolveForward(CFG<Node> cfg, DataflowResult<Node, Fact> result) {
throw new UnsupportedOperationException();
}
/**
* result存分析结果
* cfg为控制流图
* @param cfg
* @param result
*/
@Override
protected void doSolveBackward(CFG<Node> cfg, DataflowResult<Node, Fact> result) {
boolean flag = true;
while(flag){
flag = false;
for(Node node : cfg){
for(Node succ : cfg.getSuccsOf(node))
this.analysis.meetInto(result.getInFact(succ), result.getOutFact(node));
if(this.analysis.transferNode(node, result.getInFact(node), result.getOutFact(node))){
flag = true;
}
}
}
}
}