* Runs the dead code remover.
*/
private void run() {
- HashSet<SsaInsn> deletedInsns = (HashSet<SsaInsn>) new HashSet();
+ pruneDeadInstructions();
+
+ HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
ssaMeth.forEachInsn(new NoSideEffectVisitor(worklist));
}
/**
+ * Removes all instructions from every unreachable block.
+ */
+ private void pruneDeadInstructions() {
+ HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
+
+ ssaMeth.computeReachability();
+
+ for (SsaBasicBlock block : ssaMeth.getBlocks()) {
+ if (block.isReachable()) continue;
+
+ // Prune instructions from unreachable blocks
+ for (int i = 0; i < block.getInsns().size(); i++) {
+ SsaInsn insn = block.getInsns().get(i);
+ RegisterSpecList sources = insn.getSources();
+ int sourcesSize = sources.size();
+
+ // Delete this instruction completely if it has sources
+ if (sourcesSize != 0) {
+ deletedInsns.add(insn);
+ }
+
+ // Delete this instruction from all usage lists.
+ for (int j = 0; j < sourcesSize; j++) {
+ RegisterSpec source = sources.get(j);
+ useList[source.getReg()].remove(insn);
+ }
+
+ // Remove this instruction result from the sources of any phis
+ RegisterSpec result = insn.getResult();
+ if (result == null) continue;
+ for (SsaInsn use : useList[result.getReg()]) {
+ if (use instanceof PhiInsn) {
+ PhiInsn phiUse = (PhiInsn) use;
+ phiUse.removePhiRegister(result);
+ }
+ }
+ }
+ }
+
+ ssaMeth.deleteInsns(deletedInsns);
+ }
+
+ /**
* Returns true if the only uses of this register form a circle of
* operations with no side effects.
*
package com.android.dx.ssa;
+import com.android.dx.rop.code.PlainCstInsn;
import com.android.dx.rop.code.TranslationAdvice;
import com.android.dx.rop.code.RegisterSpecList;
import com.android.dx.rop.code.Insn;
import com.android.dx.rop.code.PlainInsn;
import com.android.dx.rop.code.Rops;
import com.android.dx.rop.code.RegOps;
+import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstLiteralBits;
+import com.android.dx.rop.type.Type;
import com.android.dx.rop.type.TypeBearer;
import java.util.List;
Rop opcode = originalRopInsn.getOpcode();
RegisterSpecList sources = insn.getSources();
+ // Replace insns with constant results with const insns
+ if (insn.getResult() != null &&
+ opcode.getOpcode() != RegOps.CONST) {
+ TypeBearer type = insn.getResult().getTypeBearer();
+ if (type.isConstant() &&
+ type.getBasicType() == Type.BT_INT) {
+ replacePlainInsn(insn, RegisterSpecList.EMPTY,
+ RegOps.CONST, (Constant) type);
+ return;
+ }
+ }
+
if (sources.size() != 2 ) {
// We're only dealing with two-source insns here.
return;
*/
if (isConstIntZeroOrKnownNull(sources.get(0))) {
replacePlainInsn(insn, sources.withoutFirst(),
- RegOps.flippedIfOpcode(opcode.getOpcode()));
+ RegOps.flippedIfOpcode(opcode.getOpcode()), null);
} else if (isConstIntZeroOrKnownNull(sources.get(1))) {
replacePlainInsn(insn, sources.withoutLast(),
- opcode.getOpcode());
+ opcode.getOpcode(), null);
}
} else if (advice.hasConstantOperation(
opcode, sources.get(0), sources.get(1))) {
/**
* Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The
- * new PlainInsn is contructed with a new RegOp and new sources.
+ * new PlainInsn is constructed with a new RegOp and new sources.
*
* TODO move this somewhere else.
*
* @param insn {@code non-null;} an SsaInsn containing a PlainInsn
* @param newSources {@code non-null;} new sources list for new insn
* @param newOpcode A RegOp from {@link RegOps}
+ * @param cst {@code null-ok;} constant for new instruction, if any
*/
private void replacePlainInsn(NormalSsaInsn insn,
- RegisterSpecList newSources, int newOpcode) {
+ RegisterSpecList newSources, int newOpcode, Constant cst) {
Insn originalRopInsn = insn.getOriginalRopInsn();
- Rop newRop = Rops.ropFor(newOpcode,
- insn.getResult(), newSources, null);
- Insn newRopInsn = new PlainInsn(newRop,
- originalRopInsn.getPosition(), insn.getResult(),
- newSources);
- NormalSsaInsn newInsn
- = new NormalSsaInsn(newRopInsn, insn.getBlock());
+ Rop newRop = Rops.ropFor(newOpcode, insn.getResult(), newSources, cst);
+ Insn newRopInsn;
+ if (cst == null) {
+ newRopInsn = new PlainInsn(newRop, originalRopInsn.getPosition(),
+ insn.getResult(), newSources);
+ } else {
+ newRopInsn = new PlainCstInsn(newRop, originalRopInsn.getPosition(),
+ insn.getResult(), newSources, cst);
+ }
+ NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
List<SsaInsn> insns = insn.getBlock().getInsns();
import com.android.dx.rop.code.CstInsn;
import com.android.dx.rop.code.Insn;
+import com.android.dx.rop.code.PlainInsn;
import com.android.dx.rop.code.RegOps;
import com.android.dx.rop.code.RegisterSpecList;
import com.android.dx.rop.code.Rop;
import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.Rops;
import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstInteger;
import com.android.dx.rop.cst.TypedConstant;
private Constant[] latticeConstants;
/** Worklist of basic blocks to be processed */
private ArrayList<SsaBasicBlock> cfgWorklist;
+ /** Worklist of executed basic blocks with phis to be processed */
+ private ArrayList<SsaBasicBlock> cfgPhiWorklist;
/** Bitset containing bits for each block that has been found executable */
private BitSet executableBlocks;
/** Worklist for SSA edges. This is a list of registers to process */
* possible.
*/
private ArrayList<SsaInsn> varyingWorklist;
+ /** Worklist of potential branches to convert to gotos */
+ private ArrayList<SsaInsn> branchWorklist;
private SCCP(SsaMethod ssaMeth) {
this.ssaMeth = ssaMeth;
this.latticeValues = new int[this.regCount];
this.latticeConstants = new Constant[this.regCount];
this.cfgWorklist = new ArrayList<SsaBasicBlock>();
+ this.cfgPhiWorklist = new ArrayList<SsaBasicBlock>();
this.executableBlocks = new BitSet(ssaMeth.getBlocks().size());
this.ssaWorklist = new ArrayList<SsaInsn>();
this.varyingWorklist = new ArrayList<SsaInsn>();
+ this.branchWorklist = new ArrayList<SsaInsn>();
for (int i = 0; i < this.regCount; i++) {
latticeValues[i] = TOP;
latticeConstants[i] = null;
}
/**
- * Add a new SSA basic block to the CFG worklist
+ * Adds a SSA basic block to the CFG worklist if it's unexecuted, or
+ * to the CFG phi worklist if it's already executed.
* @param ssaBlock Block to add
*/
private void addBlockToWorklist(SsaBasicBlock ssaBlock) {
if (!executableBlocks.get(ssaBlock.getIndex())) {
cfgWorklist.add(ssaBlock);
executableBlocks.set(ssaBlock.getIndex());
+ } else {
+ cfgPhiWorklist.add(ssaBlock);
}
}
/**
* Simulates a PHI node and set the lattice for the result
- * to the approriate value.
+ * to the appropriate value.
* Meet values:
* TOP x anything = anything
* VARYING x anything = VARYING
}
}
}
+
+ /**
+ * Simulate the phis in a block and note the results in the lattice.
+ * @param block Block to visit
+ */
+ private void simulatePhiBlock(SsaBasicBlock block) {
+ for (SsaInsn insn : block.getInsns()) {
+ if (insn instanceof PhiInsn) {
+ simulatePhi((PhiInsn) insn);
+ } else {
+ return;
+ }
+ }
+ }
+
private static String latticeValName(int latticeVal) {
switch (latticeVal) {
case TOP: return "TOP";
}
/**
- * Simplifies a jump statement.
- * @param insn jump to simplify
- * @return an instruction representing the simplified jump.
+ * Simulates branch insns, if possible. Adds reachable successor blocks
+ * to the CFG worklists.
+ * @param insn branch to simulate
*/
- private Insn simplifyJump (Insn insn) {
- return insn;
+ 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;
+
+ int regA = sources.get(0).getReg();
+ if (latticeValues[regA] == CONSTANT) {
+ cA = latticeConstants[regA];
+ }
+
+ if (sources.size() == 2) {
+ int regB = sources.get(1).getReg();
+ if (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:
+ // not yet supported
+ }
+ } 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:
+ // not yet supported
+ }
+ }
+ }
+
+ /*
+ * 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));
+ }
+ }
}
/**
Insn ropInsn = insn.getOriginalRopInsn();
if (ropInsn.getOpcode().getBranchingness() != Rop.BRANCH_NONE
|| ropInsn.getOpcode().isCallLike()) {
- ropInsn = simplifyJump (ropInsn);
- /* TODO: If jump becomes constant, only take true edge. */
- SsaBasicBlock block = insn.getBlock();
- int successorSize = block.getSuccessorList().size();
- for (int i = 0; i < successorSize; i++) {
- int successor = block.getSuccessorList().get(i);
- addBlockToWorklist(ssaMeth.getBlocks().get(successor));
- }
+ simulateBranch(insn);
}
if (insn.getResult() == null) {
/* Empty all the worklists by propagating our values */
while (!cfgWorklist.isEmpty()
+ || !cfgPhiWorklist.isEmpty()
|| !ssaWorklist.isEmpty()
|| !varyingWorklist.isEmpty()) {
while (!cfgWorklist.isEmpty()) {
SsaBasicBlock block = cfgWorklist.remove(listSize);
simulateBlock(block);
}
+
+ while (!cfgPhiWorklist.isEmpty()) {
+ int listSize = cfgPhiWorklist.size() - 1;
+ SsaBasicBlock block = cfgPhiWorklist.remove(listSize);
+ simulatePhiBlock(block);
+ }
+
while (!varyingWorklist.isEmpty()) {
int listSize = varyingWorklist.size() - 1;
SsaInsn insn = varyingWorklist.remove(listSize);
}
replaceConstants();
+ replaceBranches();
}
/**
continue;
}
+ // Update the destination RegisterSpec with the constant value
+ RegisterSpec dest = defn.getResult();
+ RegisterSpec newDest
+ = dest.withType((TypedConstant)latticeConstants[reg]);
+ defn.setResult(newDest);
+
/*
* Update the sources RegisterSpec's of all non-move uses.
* These will be used in later steps.
}
}
}
+
+ /**
+ * Replaces branches that have constant conditions with gotos
+ */
+ private void replaceBranches() {
+ for (SsaInsn insn : branchWorklist) {
+ // Find if a successor block is never executed
+ int oldSuccessor = -1;
+ SsaBasicBlock block = insn.getBlock();
+ int successorSize = block.getSuccessorList().size();
+ for (int i = 0; i < successorSize; i++) {
+ int successorBlock = block.getSuccessorList().get(i);
+ if (!executableBlocks.get(successorBlock)) {
+ oldSuccessor = successorBlock;
+ }
+ }
+
+ /*
+ * Prune branches that have already been handled and ones that no
+ * longer have constant conditions (no nonexecutable successors)
+ */
+ if (successorSize != 2 || oldSuccessor == -1) continue;
+
+ // Replace branch with goto
+ Insn originalRopInsn = insn.getOriginalRopInsn();
+ block.replaceLastInsn(new PlainInsn(Rops.GOTO,
+ originalRopInsn.getPosition(), null, RegisterSpecList.EMPTY));
+ block.removeSuccessor(oldSuccessor);
+ }
+ }
}