静态程序分析02

常量传播

常量传播(Constant Propagation)是一种编译器优化技术,旨在识别和利用在程序中使用的常量值,以替换变量或表达式的计算。这种优化可以显著提高程序的性能,因为它可以减少不必要的计算并消除冗余的代码。以下是常量传播的一些关键概念和工作原理:
常量值:在编程中,常量是指在程序执行期间不会改变的值,例如整数、浮点数、字符串等。常量传播的目标是识别和利用这些不变的值。
基本思想:常量传播的基本思想是跟踪程序中各个变量和表达式的值,并在编译器的优化阶段用已知的常量值替换它们。这样可以减少不必要的运算,提高程序的执行速度。
数据流分析:常量传播通常依赖于数据流分析技术,通过分析变量和常量值在程序中的传播和依赖关系,以确定哪些变量在某个点(例如,某个基本块或路径)的值是常量。
替代常量:一旦编译器确定某个变量或表达式的值在某个点是常量,它就会用该常量值替代变量或表达式,从而消除了不必要的计算。这个过程被称为"常量折叠"(Constant Folding)。
条件分支:在常量传播中,编译器还会处理条件分支语句,例如 if 和 switch。如果编译器能够确定条件表达式的值在编译时是常量,它可以根据条件的值来消除或简化分支。
限制和挑战:常量传播并不总是可行的,因为有些程序可能包含动态生成的数据,或者依赖于用户输入等不确定因素。在这种情况下,编译器可能无法确定常量值,因此无法进行常量传播。

总的来说,常量传播是一种用于提高程序性能的重要编译器优化技术。它可以消除不必要的计算和代码,从而减少程序的执行时间和资源消耗。然而,它需要精确的数据流分析和对程序的深入理解,以确保正确性和安全性。

java样例

class BranchConstant {

    void constant1(boolean b) {
        int x = 2;
        int y = 2;
        int z;
        if (b) {
            z = x + y;
        } else {
            z = x * y;
        }
        int n = z;
    }

    void constant2(boolean b) {
        int x;
        if (b) {
            x = 10;
        }
        int y = x;
    }
}

分析结果
-------------------- <BranchConstant: void <init>()> (constprop) --------------------
[0@L1] invokespecial %this.<java.lang.Object: void <init>()>(); {}
[1@L1] return; {}

-------------------- <BranchConstant: void constant1(boolean)> (constprop) --------------------
[0@L4] x = 2; {b=NAC, x=2}
[1@L5] y = 2; {b=NAC, x=2, y=2}
[2@L7] %intconst0 = 0; {%intconst0=0, b=NAC, x=2, y=2}
[3@L7] if (b == %intconst0) goto 8; {%intconst0=0, b=NAC, x=2, y=2}
[4@L7] goto 5; {%intconst0=0, b=NAC, x=2, y=2}
[5@L7] nop; {%intconst0=0, b=NAC, x=2, y=2}
[6@L8] z = x + y; {%intconst0=0, b=NAC, x=2, y=2, z=4}
[7@L7] goto 10; {%intconst0=0, b=NAC, x=2, y=2, z=4}
[8@L7] nop; {%intconst0=0, b=NAC, x=2, y=2}
[9@L10] z = x * y; {%intconst0=0, b=NAC, x=2, y=2, z=4}
[10@L10] nop; {%intconst0=0, b=NAC, x=2, y=2, z=4}
[11@L12] n = z; {%intconst0=0, b=NAC, n=4, x=2, y=2, z=4}
[12@L12] return; {%intconst0=0, b=NAC, n=4, x=2, y=2, z=4}

-------------------- <BranchConstant: void constant2(boolean)> (constprop) --------------------
[0@L17] %intconst0 = 0; {%intconst0=0, b=NAC}
[1@L17] if (b == %intconst0) goto 5; {%intconst0=0, b=NAC}
[2@L17] goto 3; {%intconst0=0, b=NAC}
[3@L17] nop; {%intconst0=0, b=NAC}
[4@L18] x = 10; {%intconst0=0, b=NAC, x=10}
[5@L18] nop; {%intconst0=0, b=NAC, x=10}
[6@L20] y = x; {%intconst0=0, b=NAC, x=10, y=10}
[7@L20] return; {%intconst0=0, b=NAC, x=10, y=10}

常量传播算法设计

格定义:变量在程序中只有三种状态UNDEF、CONSTANT、NAC
方向:forward
边界条件:将方法的参数定义为NAC
初始化:将每一个BB处定义为空(UNDEF)
交汇处理
交汇处理

转换函数:OUT[B] = gen ∪(IN[B] - {lvalue, _})

数据结构与算法实现

数据结构
使用键值对来保存变量信息。实现如下:

public class CPFact extends MapFact<Var, Value> {

    public CPFact() {
        this(Collections.emptyMap());
    }

    private CPFact(Map<Var, Value> map) {
        super(map);
    }

    /**
     * @return the value of given variable in this fact,
     * or UNDEF the variable is absent in this fact.
     */
    @Override
    public Value get(Var key) {
        return map.getOrDefault(key, Value.getUndef());
    }

    @Override
    public boolean update(Var key, Value value) {
        if (value.isUndef()) {
            // if the client code sets variable key to UNDEF,
            // then we remove the variable from the CPFact
            // as we use absence to represent UNDEF.
            return remove(key) != null;
        } else {
            return super.update(key, value);
        }
    }

    @Override
    public CPFact copy() {
        return new CPFact(this.map);
    }
}

常亮传播算法实现

  1. ConstantPropagation。实现如下:
public class ConstantPropagation extends
        AbstractDataflowAnalysis<Stmt, CPFact> {

    public static final String ID = "constprop";

    public ConstantPropagation(AnalysisConfig config) {
        super(config);
    }

    @Override
    public boolean isForward() {
        return true;
    }

    @Override
    public CPFact newBoundaryFact(CFG<Stmt> cfg) {
        CPFact cpFact = new CPFact();
        List<Var> vars = cfg.getIR().getParams();
        for(Var var : vars){
            if(canHoldInt(var))
                cpFact.update(var, Value.getNAC());
        }

        return cpFact;
    }

    @Override
    public CPFact newInitialFact() {

        return new CPFact();
    }

    @Override
    public void meetInto(CPFact fact, CPFact target) {
        for(Var var : fact.keySet())
            target.update(var, meetValue(fact.get(var), target.get(var)));
    }

    /**
     * Meets two Values.
     */
    public Value meetValue(Value v1, Value v2) {
        if(v1.isNAC() || v2.isNAC())
            return Value.getNAC();
        if(v1.isUndef())
            return v2;
        if(v2.isUndef())
            return v1;
        if(v1.getConstant() == v2.getConstant())
            return v1;

        return Value.getNAC();
    }

    @Override
    public boolean transferNode(Stmt stmt, CPFact in, CPFact out) {
        // x = 2
        // x = y
        // x = y op z
        //OUT = gen ∪ (IN - {x, _})
        if(stmt instanceof DefinitionStmt<?, ?> definitionStmt && definitionStmt.getLValue() instanceof Var lValue && canHoldInt(lValue)){
            RValue rValue = definitionStmt.getRValue();
            Value value = evaluate(rValue, in);
            CPFact tmp = in.copy();
            tmp.update(lValue, value);
            return out.copyFrom(tmp);
        }
        return out.copyFrom(in);

    }

    /**
     * @return true if the given variable can hold integer value, otherwise false.
     */
    public static boolean canHoldInt(Var var) {
        Type type = var.getType();
        if (type instanceof PrimitiveType) {
            switch ((PrimitiveType) type) {
                case BYTE:
                case SHORT:
                case INT:
                case CHAR:
                case BOOLEAN:
                    return true;
            }
        }
        return false;
    }

    /**
     * Evaluates the {@link Value} of given expression.
     *
     * @param exp the expression to be evaluated
     * @param in  IN fact of the statement
     * @return the resulting {@link Value}
     */
    public static Value evaluate(Exp exp, CPFact in) {
        if(exp instanceof IntLiteral intLiteral){               //  x = c
            return Value.makeConstant(intLiteral.getValue());
        }else if(exp instanceof Var var){                       // x = y
            return in.get(var);
        }

        //x = y op z
        //x = val(y) op val(z)  val(y) and val(z) is constant
        //x = NAC               val(y) or val(z) is NAC
        //x = UNDEF             op = %/ and val(z) == 0
        if(! (exp instanceof BinaryExp binaryExp))
            return Value.getNAC();

        Var op1 = binaryExp.getOperand1();
        Var op2 = binaryExp.getOperand2();

        Value value1 = in.get(op1);
        Value value2 = in.get(op2); //value2 = NAC/UNDEF  ->  res = NAC/UNDEF
        if(!value2.isConstant())
            return value2;

        if(!value1.isConstant() && value2.getConstant() == 0 && binaryExp instanceof ArithmeticExp){// value1 == NAC/UNDEF value2 == 0 && op == (%/)  -> undef
            return switch (((ArithmeticExp) exp).getOperator()){
                case DIV, REM -> Value.getUndef();
                default -> Value.getNAC();
            };
        }

        if(!value1.isConstant())
            return value1;

        // value1 is constant && value2 is constant(not zero)
        int constant1 = value1.getConstant();
        int constant2 = value2.getConstant();
        if(binaryExp instanceof ArithmeticExp arithmeticExp){
            return Value.makeConstant(
                    switch (arithmeticExp.getOperator()){
                        case ADD -> constant1 + constant2;
                        case SUB -> constant1 - constant2;
                        case MUL -> constant1 * constant2;
                        case DIV -> constant1 / constant2;
                        case REM -> constant1 % constant2;
                    });
        }else if(binaryExp instanceof BitwiseExp bitwiseExp){
            return Value.makeConstant(
                    switch (bitwiseExp.getOperator()){
                        case OR -> constant1 | constant2;
                        case AND -> constant1 & constant2;
                        case XOR -> constant1 ^ constant2;
                    }
            );
        }else if(binaryExp instanceof ConditionExp conditionExp){
            return Value.makeConstant(
                    switch (conditionExp.getOperator()){
                        case EQ -> constant1 == constant2;
                        case NE -> constant1 != constant2;
                        case LT -> constant1 < constant2;
                        case GT -> constant1 > constant2;
                        case LE -> constant1 <= constant2;
                        case GE -> constant1 >= constant2;
                    } ? 1 : 0
            );
        }else if(binaryExp instanceof ShiftExp shiftExp){
            return Value.makeConstant(
                    switch (shiftExp.getOperator()){
                        case SHL -> constant1 << constant2;
                        case SHR -> constant1 >> constant2;
                        case USHR -> constant1 >>> constant2;
                    }
            );
        } else {
            return Value.getNAC();
        }


    }
}
  1. WorkList算法实现:
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 WorkListSolver<>(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) {
        result.setInFact(cfg.getEntry(), analysis.newBoundaryFact(cfg));
        result.setOutFact(cfg.getEntry(), analysis.newBoundaryFact(cfg));

        for(Node node : cfg){
            if(!cfg.isEntry(node)){
                result.setInFact(node, analysis.newInitialFact());
                result.setOutFact(node, analysis.newInitialFact());
            }

        }
    }

    protected void initializeBackward(CFG<Node> cfg, DataflowResult<Node, Fact> result) {
        throw new UnsupportedOperationException();
    }

    /**
     * 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 WorkListSolver<Node, Fact> extends Solver<Node, Fact> {

    WorkListSolver(DataflowAnalysis<Node, Fact> analysis) {
        super(analysis);
    }

    @Override
    protected void doSolveForward(CFG<Node> cfg, DataflowResult<Node, Fact> result) {
        Queue<Node> workList = new ArrayDeque<>();
        for(Node node : cfg){
            workList.add(node);
        }
        while(!workList.isEmpty()){
            Node node = workList.poll();
            Fact inFact = result.getInFact(node);
            Fact outFact = result.getOutFact(node);
            for(Node pre : cfg.getPredsOf(node))
                analysis.meetInto(result.getOutFact(pre), inFact);
            if(analysis.transferNode(node, inFact, outFact)){
                for(Node succ : cfg.getSuccsOf(node)){
                    if(!workList.contains(succ)){
                        workList.add(succ);
                    }
                }
            }

        }
    }

    @Override
    protected void doSolveBackward(CFG<Node> cfg, DataflowResult<Node, Fact> result) {
        throw new UnsupportedOperationException();
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值