Search in sources :

Example 31 with RegisterSpec

use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.

the class SCCP method simulateBranch.

/**
     * Simulates branch insns, if possible. Adds reachable successor blocks
     * to the CFG worklists.
     * @param insn branch to simulate
     */
private void simulateBranch(SsaInsn insn) {
    Rop opcode = insn.getOpcode();
    RegisterSpecList sources = insn.getSources();
    boolean constantBranch = false;
    boolean constantSuccessor = false;
    // Check if the insn is a branch with a constant condition
    if (opcode.getBranchingness() == Rop.BRANCH_IF) {
        Constant cA = null;
        Constant cB = null;
        RegisterSpec specA = sources.get(0);
        int regA = specA.getReg();
        if (!ssaMeth.isRegALocal(specA) && latticeValues[regA] == CONSTANT) {
            cA = latticeConstants[regA];
        }
        if (sources.size() == 2) {
            RegisterSpec specB = sources.get(1);
            int regB = specB.getReg();
            if (!ssaMeth.isRegALocal(specB) && latticeValues[regB] == CONSTANT) {
                cB = latticeConstants[regB];
            }
        }
        // Calculate the result of the condition
        if (cA != null && sources.size() == 1) {
            switch(((TypedConstant) cA).getBasicType()) {
                case Type.BT_INT:
                    constantBranch = true;
                    int vA = ((CstInteger) cA).getValue();
                    switch(opcode.getOpcode()) {
                        case RegOps.IF_EQ:
                            constantSuccessor = (vA == 0);
                            break;
                        case RegOps.IF_NE:
                            constantSuccessor = (vA != 0);
                            break;
                        case RegOps.IF_LT:
                            constantSuccessor = (vA < 0);
                            break;
                        case RegOps.IF_GE:
                            constantSuccessor = (vA >= 0);
                            break;
                        case RegOps.IF_LE:
                            constantSuccessor = (vA <= 0);
                            break;
                        case RegOps.IF_GT:
                            constantSuccessor = (vA > 0);
                            break;
                        default:
                            throw new RuntimeException("Unexpected op");
                    }
                    break;
                default:
            }
        } else if (cA != null && cB != null) {
            switch(((TypedConstant) cA).getBasicType()) {
                case Type.BT_INT:
                    constantBranch = true;
                    int vA = ((CstInteger) cA).getValue();
                    int vB = ((CstInteger) cB).getValue();
                    switch(opcode.getOpcode()) {
                        case RegOps.IF_EQ:
                            constantSuccessor = (vA == vB);
                            break;
                        case RegOps.IF_NE:
                            constantSuccessor = (vA != vB);
                            break;
                        case RegOps.IF_LT:
                            constantSuccessor = (vA < vB);
                            break;
                        case RegOps.IF_GE:
                            constantSuccessor = (vA >= vB);
                            break;
                        case RegOps.IF_LE:
                            constantSuccessor = (vA <= vB);
                            break;
                        case RegOps.IF_GT:
                            constantSuccessor = (vA > vB);
                            break;
                        default:
                            throw new RuntimeException("Unexpected op");
                    }
                    break;
                default:
            }
        }
    }
    /*
         * If condition is constant, add only the target block to the
         * worklist. Otherwise, add all successors to the worklist.
         */
    SsaBasicBlock block = insn.getBlock();
    if (constantBranch) {
        int successorBlock;
        if (constantSuccessor) {
            successorBlock = block.getSuccessorList().get(1);
        } else {
            successorBlock = block.getSuccessorList().get(0);
        }
        addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
        branchWorklist.add(insn);
    } else {
        for (int i = 0; i < block.getSuccessorList().size(); i++) {
            int successorBlock = block.getSuccessorList().get(i);
            addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
        }
    }
}
Also used : Rop(com.android.dx.rop.code.Rop) TypedConstant(com.android.dx.rop.cst.TypedConstant) Constant(com.android.dx.rop.cst.Constant) TypedConstant(com.android.dx.rop.cst.TypedConstant) CstInteger(com.android.dx.rop.cst.CstInteger) RegisterSpecList(com.android.dx.rop.code.RegisterSpecList) RegisterSpec(com.android.dx.rop.code.RegisterSpec)

Example 32 with RegisterSpec

use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.

the class SCCP method simulateStmt.

/**
     * Simulates a statement and set the result lattice value.
     * @param insn instruction to simulate
     */
private void simulateStmt(SsaInsn insn) {
    Insn ropInsn = insn.getOriginalRopInsn();
    if (ropInsn.getOpcode().getBranchingness() != Rop.BRANCH_NONE || ropInsn.getOpcode().isCallLike()) {
        simulateBranch(insn);
    }
    int opcode = insn.getOpcode().getOpcode();
    RegisterSpec result = insn.getResult();
    if (result == null) {
        // Find move-result-pseudo result for int div and int rem
        if (opcode == RegOps.DIV || opcode == RegOps.REM) {
            SsaBasicBlock succ = insn.getBlock().getPrimarySuccessor();
            result = succ.getInsns().get(0).getResult();
        } else {
            return;
        }
    }
    int resultReg = result.getReg();
    int resultValue = VARYING;
    Constant resultConstant = null;
    switch(opcode) {
        case RegOps.CONST:
            {
                CstInsn cstInsn = (CstInsn) ropInsn;
                resultValue = CONSTANT;
                resultConstant = cstInsn.getConstant();
                break;
            }
        case RegOps.MOVE:
            {
                if (insn.getSources().size() == 1) {
                    int sourceReg = insn.getSources().get(0).getReg();
                    resultValue = latticeValues[sourceReg];
                    resultConstant = latticeConstants[sourceReg];
                }
                break;
            }
        case RegOps.ADD:
        case RegOps.SUB:
        case RegOps.MUL:
        case RegOps.DIV:
        case RegOps.AND:
        case RegOps.OR:
        case RegOps.XOR:
        case RegOps.SHL:
        case RegOps.SHR:
        case RegOps.USHR:
        case RegOps.REM:
            {
                resultConstant = simulateMath(insn, result.getBasicType());
                if (resultConstant != null) {
                    resultValue = CONSTANT;
                }
                break;
            }
        case RegOps.MOVE_RESULT_PSEUDO:
            {
                if (latticeValues[resultReg] == CONSTANT) {
                    resultValue = latticeValues[resultReg];
                    resultConstant = latticeConstants[resultReg];
                }
                break;
            }
        // TODO: Eliminate check casts that we can prove the type of.
        default:
            {
            }
    }
    if (setLatticeValueTo(resultReg, resultValue, resultConstant)) {
        addUsersToWorklist(resultReg, resultValue);
    }
}
Also used : CstInsn(com.android.dx.rop.code.CstInsn) Insn(com.android.dx.rop.code.Insn) PlainInsn(com.android.dx.rop.code.PlainInsn) CstInsn(com.android.dx.rop.code.CstInsn) Constant(com.android.dx.rop.cst.Constant) TypedConstant(com.android.dx.rop.cst.TypedConstant) RegisterSpec(com.android.dx.rop.code.RegisterSpec)

Example 33 with RegisterSpec

use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.

the class SsaBasicBlock method scheduleMovesFromPhis.

/**
     * Sorts move instructions added via {@code addMoveToEnd} during
     * phi removal so that results don't overwrite sources that are used.
     * For use after all phis have been removed and all calls to
     * addMoveToEnd() have been made.<p>
     *
     * This is necessary because copy-propogation may have left us in a state
     * where the same basic block has the same register as a phi operand
     * and a result. In this case, the register in the phi operand always
     * refers value before any other phis have executed.
     */
public void scheduleMovesFromPhis() {
    if (movesFromPhisAtBeginning > 1) {
        List<SsaInsn> toSchedule;
        toSchedule = insns.subList(0, movesFromPhisAtBeginning);
        scheduleUseBeforeAssigned(toSchedule);
        SsaInsn firstNonPhiMoveInsn = insns.get(movesFromPhisAtBeginning);
        /*
             * TODO: It's actually possible that this case never happens,
             * because a move-exception block, having only one predecessor
             * in SSA form, perhaps is never on a dominance frontier.
             */
        if (firstNonPhiMoveInsn.isMoveException()) {
            if (true) {
                /*
                     * We've yet to observe this case, and if it can
                     * occur the code written to handle it probably
                     * does not work.
                     */
                throw new RuntimeException("Unexpected: moves from " + "phis before move-exception");
            } else {
                /*
                     * A move-exception insn must be placed first in this block
                     * We need to move it there, and deal with possible
                     * interference.
                     */
                boolean moveExceptionInterferes = false;
                int moveExceptionResult = firstNonPhiMoveInsn.getResult().getReg();
                /*
                     * Does the move-exception result reg interfere with the
                     * phi moves?
                     */
                for (SsaInsn insn : toSchedule) {
                    if (insn.isResultReg(moveExceptionResult) || insn.isRegASource(moveExceptionResult)) {
                        moveExceptionInterferes = true;
                        break;
                    }
                }
                if (!moveExceptionInterferes) {
                    // This is the easy case.
                    insns.remove(movesFromPhisAtBeginning);
                    insns.add(0, firstNonPhiMoveInsn);
                } else {
                    /*
                         * We need to move the result to a spare reg
                         * and move it back.
                         */
                    RegisterSpec originalResultSpec = firstNonPhiMoveInsn.getResult();
                    int spareRegister = parent.borrowSpareRegister(originalResultSpec.getCategory());
                    // We now move it to a spare register.
                    firstNonPhiMoveInsn.changeResultReg(spareRegister);
                    RegisterSpec tempSpec = firstNonPhiMoveInsn.getResult();
                    insns.add(0, firstNonPhiMoveInsn);
                    // And here we move it back.
                    NormalSsaInsn toAdd = new NormalSsaInsn(new PlainInsn(Rops.opMove(tempSpec.getType()), SourcePosition.NO_INFO, originalResultSpec, RegisterSpecList.make(tempSpec)), this);
                    /*
                         * Place it immediately after the phi-moves,
                         * overwriting the move-exception that was there.
                         */
                    insns.set(movesFromPhisAtBeginning + 1, toAdd);
                }
            }
        }
    }
    if (movesFromPhisAtEnd > 1) {
        scheduleUseBeforeAssigned(insns.subList(insns.size() - movesFromPhisAtEnd - 1, insns.size() - 1));
    }
    // Return registers borrowed here and in scheduleUseBeforeAssigned().
    parent.returnSpareRegisters();
}
Also used : PlainInsn(com.android.dx.rop.code.PlainInsn) RegisterSpec(com.android.dx.rop.code.RegisterSpec)

Example 34 with RegisterSpec

use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.

the class ConstCollector method getConstsSortedByCountUse.

/**
     * Gets all of the collectable constant values used in this method,
     * sorted by most used first. Skips non-collectable consts, such as
     * non-string object constants
     *
     * @return {@code non-null;} list of constants in most-to-least used order
     */
private ArrayList<TypedConstant> getConstsSortedByCountUse() {
    int regSz = ssaMeth.getRegCount();
    final HashMap<TypedConstant, Integer> countUses = new HashMap<TypedConstant, Integer>();
    /*
         * Each collected constant can be used by just one local
         * (used only if COLLECT_ONE_LOCAL is true).
         */
    final HashSet<TypedConstant> usedByLocal = new HashSet<TypedConstant>();
    // Count how many times each const value is used.
    for (int i = 0; i < regSz; i++) {
        SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
        if (insn == null || insn.getOpcode() == null)
            continue;
        RegisterSpec result = insn.getResult();
        TypeBearer typeBearer = result.getTypeBearer();
        if (!typeBearer.isConstant())
            continue;
        TypedConstant cst = (TypedConstant) typeBearer;
        // Find defining instruction for move-result-pseudo instructions
        if (insn.getOpcode().getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
            int pred = insn.getBlock().getPredecessors().nextSetBit(0);
            ArrayList<SsaInsn> predInsns;
            predInsns = ssaMeth.getBlocks().get(pred).getInsns();
            insn = predInsns.get(predInsns.size() - 1);
        }
        if (insn.canThrow()) {
            /*
                 * Don't move anything other than strings -- the risk
                 * of changing where an exception is thrown is too high.
                 */
            if (!(cst instanceof CstString) || !COLLECT_STRINGS) {
                continue;
            }
            /*
                 * We can't move any throwable const whose throw will be
                 * caught, so don't count them.
                 */
            if (insn.getBlock().getSuccessors().cardinality() > 1) {
                continue;
            }
        }
        /*
             * TODO: Might be nice to try and figure out which local
             * wins most when collected.
             */
        if (ssaMeth.isRegALocal(result)) {
            if (!COLLECT_ONE_LOCAL) {
                continue;
            } else {
                if (usedByLocal.contains(cst)) {
                    // Count one local usage only.
                    continue;
                } else {
                    usedByLocal.add(cst);
                }
            }
        }
        Integer has = countUses.get(cst);
        if (has == null) {
            countUses.put(cst, 1);
        } else {
            countUses.put(cst, has + 1);
        }
    }
    // Collect constants that have been reused.
    ArrayList<TypedConstant> constantList = new ArrayList<TypedConstant>();
    for (Map.Entry<TypedConstant, Integer> entry : countUses.entrySet()) {
        if (entry.getValue() > 1) {
            constantList.add(entry.getKey());
        }
    }
    // Sort by use, with most used at the beginning of the list.
    Collections.sort(constantList, new Comparator<Constant>() {

        public int compare(Constant a, Constant b) {
            int ret;
            ret = countUses.get(b) - countUses.get(a);
            if (ret == 0) {
                /*
                     * Provide sorting determinisim for constants with same
                     * usage count.
                     */
                ret = a.compareTo(b);
            }
            return ret;
        }

        @Override
        public boolean equals(Object obj) {
            return obj == this;
        }
    });
    return constantList;
}
Also used : HashMap(java.util.HashMap) Constant(com.android.dx.rop.cst.Constant) TypedConstant(com.android.dx.rop.cst.TypedConstant) CstString(com.android.dx.rop.cst.CstString) ArrayList(java.util.ArrayList) TypedConstant(com.android.dx.rop.cst.TypedConstant) TypeBearer(com.android.dx.rop.type.TypeBearer) HashMap(java.util.HashMap) Map(java.util.Map) RegisterSpec(com.android.dx.rop.code.RegisterSpec) HashSet(java.util.HashSet)

Example 35 with RegisterSpec

use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.

the class ConstCollector method updateConstUses.

/**
     * Updates all uses of various consts to use the values in the newly
     * assigned registers.
     *
     * @param newRegs {@code non-null;} mapping between constant and new reg
     * @param origRegCount {@code >=0;} original SSA reg count, not including
     * newly added constant regs
     */
private void updateConstUses(HashMap<TypedConstant, RegisterSpec> newRegs, int origRegCount) {
    /*
         * set of constants associated with a local variable; used
         * only if COLLECT_ONE_LOCAL is true.
         */
    final HashSet<TypedConstant> usedByLocal = new HashSet<TypedConstant>();
    final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
    for (int i = 0; i < origRegCount; i++) {
        SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
        if (insn == null) {
            continue;
        }
        final RegisterSpec origReg = insn.getResult();
        TypeBearer typeBearer = insn.getResult().getTypeBearer();
        if (!typeBearer.isConstant())
            continue;
        TypedConstant cst = (TypedConstant) typeBearer;
        final RegisterSpec newReg = newRegs.get(cst);
        if (newReg == null) {
            continue;
        }
        if (ssaMeth.isRegALocal(origReg)) {
            if (!COLLECT_ONE_LOCAL) {
                continue;
            } else {
                /*
                     * TODO: If the same local gets the same cst
                     * multiple times, it would be nice to reuse the
                     * register.
                     */
                if (usedByLocal.contains(cst)) {
                    continue;
                } else {
                    usedByLocal.add(cst);
                    fixLocalAssignment(origReg, newRegs.get(cst));
                }
            }
        }
        // maps an original const register to the new collected register
        RegisterMapper mapper = new RegisterMapper() {

            @Override
            public int getNewRegisterCount() {
                return ssaMeth.getRegCount();
            }

            @Override
            public RegisterSpec map(RegisterSpec registerSpec) {
                if (registerSpec.getReg() == origReg.getReg()) {
                    return newReg.withLocalItem(registerSpec.getLocalItem());
                }
                return registerSpec;
            }
        };
        for (SsaInsn use : useList[origReg.getReg()]) {
            if (use.canThrow() && use.getBlock().getSuccessors().cardinality() > 1) {
                continue;
            }
            use.mapSourceRegisters(mapper);
        }
    }
}
Also used : TypedConstant(com.android.dx.rop.cst.TypedConstant) ArrayList(java.util.ArrayList) TypeBearer(com.android.dx.rop.type.TypeBearer) RegisterSpec(com.android.dx.rop.code.RegisterSpec) HashSet(java.util.HashSet)

Aggregations

RegisterSpec (com.android.dx.rop.code.RegisterSpec)135 RegisterSpecList (com.android.dx.rop.code.RegisterSpecList)50 PlainInsn (com.android.dx.rop.code.PlainInsn)24 Constant (com.android.dx.rop.cst.Constant)20 TypedConstant (com.android.dx.rop.cst.TypedConstant)16 TypeBearer (com.android.dx.rop.type.TypeBearer)16 ArrayList (java.util.ArrayList)16 Insn (com.android.dx.rop.code.Insn)14 PlainCstInsn (com.android.dx.rop.code.PlainCstInsn)14 Rop (com.android.dx.rop.code.Rop)14 ThrowingCstInsn (com.android.dx.rop.code.ThrowingCstInsn)14 CstType (com.android.dx.rop.cst.CstType)14 BitSet (java.util.BitSet)11 LocalItem (com.android.dx.rop.code.LocalItem)10 RegisterSpecSet (com.android.dx.rop.code.RegisterSpecSet)10 ThrowingInsn (com.android.dx.rop.code.ThrowingInsn)10 CstString (com.android.dx.rop.cst.CstString)10 HashSet (java.util.HashSet)10 SourcePosition (com.android.dx.rop.code.SourcePosition)8 CstFieldRef (com.android.dx.rop.cst.CstFieldRef)8