All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.teavm.model.optimization.ConstantConditionElimination Maven / Gradle / Ivy

There is a newer version: 0.2.8
Show newest version
/*
 *  Copyright 2016 Alexey Andreev.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.teavm.model.optimization;

import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.analysis.NullnessInformation;
import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.util.TransitionExtractor;

public class ConstantConditionElimination implements MethodOptimization {
    private int[] constants;
    private boolean[] constantDefined;
    private NullnessInformation nullness;

    @Override
    public boolean optimize(MethodOptimizationContext context, Program program) {
        return optimize(context.getMethod().getDescriptor(), program);
    }

    public boolean optimize(MethodDescriptor descriptor, Program program) {
        constants = new int[program.variableCount()];
        constantDefined = new boolean[program.variableCount()];
        nullness = NullnessInformation.build(program, descriptor);

        for (int i = 0; i < program.basicBlockCount(); ++i) {
            BasicBlock block = program.basicBlockAt(i);
            for (Instruction insn : block) {
                if (insn instanceof IntegerConstantInstruction) {
                    IntegerConstantInstruction constInsn = (IntegerConstantInstruction) insn;
                    int receiver = constInsn.getReceiver().getIndex();
                    constants[receiver] = constInsn.getConstant();
                    constantDefined[receiver] = true;
                }
            }
        }

        boolean changed = false;
        TransitionExtractor transitionExtractor = new TransitionExtractor();
        for (int i = 0; i < program.basicBlockCount(); ++i) {
            BasicBlock block = program.basicBlockAt(i);
            Instruction insn = block.getLastInstruction();
            BasicBlock target = constantTarget(insn);
            if (target != null) {
                block.getLastInstruction().acceptVisitor(transitionExtractor);

                for (BasicBlock successor : transitionExtractor.getTargets()) {
                    if (successor != target) {
                        for (Phi phi : successor.getPhis()) {
                            for (int j = 0; j < phi.getIncomings().size(); ++j) {
                                if (phi.getIncomings().get(j).getSource() == block) {
                                    phi.getIncomings().remove(j--);
                                }
                            }
                        }
                    }
                }

                JumpInstruction jump = new JumpInstruction();
                jump.setTarget(target);
                jump.setLocation(insn.getLocation());
                block.getLastInstruction().replace(jump);

                changed = true;
            }
        }

        nullness.dispose();
        nullness = null;
        constantDefined = null;
        constants = null;

        if (changed) {
            new UnreachableBasicBlockEliminator().optimize(program);
        }

        return changed;
    }

    private BasicBlock constantTarget(Instruction instruction) {
        if (instruction instanceof BranchingInstruction) {
            BranchingInstruction branching = (BranchingInstruction) instruction;
            switch (branching.getCondition()) {
                case NULL:
                    if (nullness.isNull(branching.getOperand())) {
                        return branching.getConsequent();
                    } else if (nullness.isNotNull(branching.getOperand())) {
                        return branching.getAlternative();
                    }
                    break;
                case NOT_NULL:
                    if (nullness.isNull(branching.getOperand())) {
                        return branching.getAlternative();
                    } else if (nullness.isNotNull(branching.getOperand())) {
                        return branching.getConsequent();
                    }
                    break;
                default: {
                    int operand = branching.getOperand().getIndex();
                    if (constantDefined[operand]) {
                        return checkCondition(branching.getCondition(), constants[operand])
                                ? branching.getConsequent() : branching.getAlternative();
                    }
                    break;
                }
            }
        } else if (instruction instanceof BinaryBranchingInstruction) {
            BinaryBranchingInstruction branching = (BinaryBranchingInstruction) instruction;
            int first = branching.getFirstOperand().getIndex();
            int second = branching.getSecondOperand().getIndex();
            switch (branching.getCondition()) {
                case EQUAL:
                case NOT_EQUAL:
                    if (constantDefined[first] && constantDefined[second]) {
                        boolean result = constants[first] == constants[second];
                        if (branching.getCondition() == BinaryBranchingCondition.NOT_EQUAL) {
                            result = !result;
                        }
                        return result ? branching.getConsequent() : branching.getAlternative();
                    }
                    break;
                default:
                    break;
            }
        }

        return null;
    }

    private boolean checkCondition(BranchingCondition condition, int constant) {
        switch (condition) {
            case EQUAL:
                return constant == 0;
            case NOT_EQUAL:
                return constant != 0;
            case GREATER:
                return constant > 0;
            case GREATER_OR_EQUAL:
                return constant >= 0;
            case LESS:
                return constant < 0;
            case LESS_OR_EQUAL:
                return constant <= 0;
            case NOT_NULL:
            case NULL:
                break;
        }
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy