死代码消除
通过活跃变量分析和常量传播进行死代码消除优化
算法实现
注意不同stmt的判定
/**
* 死代码检测
* 检测不可达代码和无用赋值
* 1. 不可达代码:控制流不可达代码和分支不可达代码
* 1.1 控制流不可达代码:返回语句之后的代码
* 1.2 分支不可达:
* 1.2.1 if语句中如果条件值为常量则其中一个分支不会走到
* 1.2.2 case语句中如果case为常量则其他case分支不可达
* 2. 无用赋值
* 一个局部变量在一条语句中被赋值,但没有被该语句后的语句读取,这样的变量为无用变量
* 但是所有x = exp语句都不能去除,因为等号右边语句可能带有副作用
* @param ir
* @return
*/
@Override
public Set<Stmt> analyze(IR ir) {
// obtain CFG
CFG<Stmt> cfg = ir.getResult(CFGBuilder.ID);
// obtain result of constant propagation
DataflowResult<Stmt, CPFact> constants =
ir.getResult(ConstantPropagation.ID);
// obtain result of live variable analysis
DataflowResult<Stmt, SetFact<Var>> liveVars =
ir.getResult(LiveVariableAnalysis.ID);
// keep statements (dead code) sorted in the resulting set
Set<Stmt> deadCode = new TreeSet<>(Comparator.comparing(Stmt::getIndex));
Set<Stmt> reachableCode = new TreeSet<>(Comparator.comparing(Stmt::getIndex));
Queue<Stmt> workList = new ArrayDeque<>();
workList.add(cfg.getEntry());
while(!workList.isEmpty()){
Stmt stmt = workList.poll();
if(reachableCode.contains(stmt))
continue;
reachableCode.add(stmt);
Set<Edge<Stmt>> edges = cfg.getOutEdgesOf(stmt);
// if statement
// 计算if表达式
// 根据if结果加入边
if(stmt instanceof If ifStmt){
Value value = ConstantPropagation.evaluate(ifStmt.getCondition(), constants.getInFact(ifStmt));
// if(!value.isConstant()){
// workList.addAll(cfg.getSuccsOf(stmt));
// continue;
// }
for(Edge<Stmt> stmtEdge : edges){
if((value.getConstant() >= 1 && stmtEdge.getKind() == Edge.Kind.IF_TRUE) ||
(value.getConstant() <= 0 && stmtEdge.getKind() == Edge.Kind.IF_FALSE)){
workList.add(stmtEdge.getTarget());
break;
}
}
}
// switch statement
// 常量传播获得case的值
// 将相应的边加入
else if (stmt instanceof SwitchStmt switchStmt) {
Value value = constants.getResult(switchStmt).get(switchStmt.getVar());
int caseResult = value.getConstant();
boolean matched = false;
for(Edge<Stmt> stmtEdge : edges){
if(stmtEdge.getKind() == Edge.Kind.SWITCH_CASE && stmtEdge.getCaseValue() == caseResult){
workList.add(stmtEdge.getTarget());
matched = true;
break;
}
}
if(!matched){
workList.add(switchStmt.getDefaultTarget());
}
}
// Assign statement:x = exp
// 查看x是否活跃
// exp 是否有影响
else if (stmt instanceof AssignStmt<?,?> assignStmt) {
workList.addAll(cfg.getSuccsOf(stmt));
if(!hasNoSideEffect(assignStmt.getRValue()))
continue;
if(assignStmt.getLValue() instanceof Var LValue){
SetFact<Var> varSetFact = liveVars.getResult(stmt);
if(!varSetFact.contains(LValue))
reachableCode.remove(assignStmt);
}
}
// control flow: fall through
else{
workList.addAll(cfg.getSuccsOf(stmt));
}
}
for(Stmt stmt : cfg){
if(!reachableCode.contains(stmt))
deadCode.add(stmt);
}
// Your task is to recognize dead code in ir and add it to deadCode
return deadCode;
}