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));
}
}
}
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);
}
}
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();
}
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;
}
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);
}
}
}
Aggregations