use of com.android.dx.ssa.SsaInsn in project buck by facebook.
the class RegisterAllocator method insertMoveBefore.
/**
* Inserts a move instruction for a specified SSA register before a
* specified instruction, creating a new SSA register and adjusting the
* interference graph in the process. The insn currently must be the
* last insn in a block.
*
* @param insn {@code non-null;} insn to insert move before, must
* be last insn in block
* @param reg {@code non-null;} SSA register to duplicate
* @return {@code non-null;} spec of new SSA register created by move
*/
protected final RegisterSpec insertMoveBefore(SsaInsn insn, RegisterSpec reg) {
SsaBasicBlock block = insn.getBlock();
ArrayList<SsaInsn> insns = block.getInsns();
int insnIndex = insns.indexOf(insn);
if (insnIndex < 0) {
throw new IllegalArgumentException("specified insn is not in this block");
}
if (insnIndex != insns.size() - 1) {
/*
* Presently, the interference updater only works when
* adding before the last insn, and the last insn must have no
* result
*/
throw new IllegalArgumentException("Adding move here not supported:" + insn.toHuman());
}
/*
* Get new register and make new move instruction.
*/
// The new result must not have an associated local variable.
RegisterSpec newRegSpec = RegisterSpec.make(ssaMeth.makeNewSsaReg(), reg.getTypeBearer());
SsaInsn toAdd = SsaInsn.makeFromRop(new PlainInsn(Rops.opMove(newRegSpec.getType()), SourcePosition.NO_INFO, newRegSpec, RegisterSpecList.make(reg)), block);
insns.add(insnIndex, toAdd);
int newReg = newRegSpec.getReg();
/*
* Adjust interference graph based on what's live out of the current
* block and what's used by the final instruction.
*/
IntSet liveOut = block.getLiveOutRegs();
IntIterator liveOutIter = liveOut.iterator();
while (liveOutIter.hasNext()) {
interference.add(newReg, liveOutIter.next());
}
// Everything that's a source in the last insn interferes.
RegisterSpecList sources = insn.getSources();
int szSources = sources.size();
for (int i = 0; i < szSources; i++) {
interference.add(newReg, sources.get(i).getReg());
}
ssaMeth.onInsnsChanged();
return newRegSpec;
}
use of com.android.dx.ssa.SsaInsn in project buck by facebook.
the class FirstFitLocalCombiningAllocator method handleCheckCastResults.
/**
* Handles check cast results to reuse the same source register.
* Inserts a move if it can't map the same register to both and the
* check cast is not caught.
*/
private void handleCheckCastResults() {
for (NormalSsaInsn insn : moveResultPseudoInsns) {
RegisterSpec moveRegSpec = insn.getResult();
int moveReg = moveRegSpec.getReg();
BitSet predBlocks = insn.getBlock().getPredecessors();
// Expect one predecessor block only
if (predBlocks.cardinality() != 1) {
continue;
}
SsaBasicBlock predBlock = ssaMeth.getBlocks().get(predBlocks.nextSetBit(0));
ArrayList<SsaInsn> insnList = predBlock.getInsns();
/**
* If the predecessor block has a check-cast, it will be the last
* instruction
*/
SsaInsn checkCastInsn = insnList.get(insnList.size() - 1);
if (checkCastInsn.getOpcode().getOpcode() != RegOps.CHECK_CAST) {
continue;
}
RegisterSpec checkRegSpec = checkCastInsn.getSources().get(0);
int checkReg = checkRegSpec.getReg();
/**
* See if either register is already mapped. Most likely the move
* result will be mapped already since the cast result is stored
* in a local variable.
*/
int category = checkRegSpec.getCategory();
boolean moveMapped = ssaRegsMapped.get(moveReg);
boolean checkMapped = ssaRegsMapped.get(checkReg);
if (moveMapped & !checkMapped) {
int moveRopReg = mapper.oldToNew(moveReg);
checkMapped = tryMapReg(checkRegSpec, moveRopReg, category);
}
if (checkMapped & !moveMapped) {
int checkRopReg = mapper.oldToNew(checkReg);
moveMapped = tryMapReg(moveRegSpec, checkRopReg, category);
}
// Map any unmapped registers to anything available
if (!moveMapped || !checkMapped) {
int ropReg = findNextUnreservedRopReg(paramRangeEnd, category);
ArrayList<RegisterSpec> ssaRegs = new ArrayList<RegisterSpec>(2);
ssaRegs.add(moveRegSpec);
ssaRegs.add(checkRegSpec);
while (!tryMapRegs(ssaRegs, ropReg, category, false)) {
ropReg = findNextUnreservedRopReg(ropReg + 1, category);
}
}
/*
* If source and result have a different mapping, insert a move so
* they can have the same mapping. Don't do this if the check cast
* is caught, since it will overwrite a potentially live value.
*/
boolean hasExceptionHandlers = checkCastInsn.getOriginalRopInsn().getCatches().size() != 0;
int moveRopReg = mapper.oldToNew(moveReg);
int checkRopReg = mapper.oldToNew(checkReg);
if (moveRopReg != checkRopReg && !hasExceptionHandlers) {
((NormalSsaInsn) checkCastInsn).changeOneSource(0, insertMoveBefore(checkCastInsn, checkRegSpec));
addMapping(checkCastInsn.getSources().get(0), moveRopReg);
}
}
}
use of com.android.dx.ssa.SsaInsn in project buck by facebook.
the class FirstFitLocalCombiningAllocator method processPhiInsn.
/**
* Attempts to map the sources and result of a phi to a common register.
* Will try existing mappings first, from most to least common. If none
* of the registers have mappings yet, a new mapping is created.
*/
private void processPhiInsn(PhiInsn insn) {
RegisterSpec result = insn.getResult();
int resultReg = result.getReg();
int category = result.getCategory();
RegisterSpecList sources = insn.getSources();
int sourcesSize = sources.size();
// List of phi sources / result that need mapping
ArrayList<RegisterSpec> ssaRegs = new ArrayList<RegisterSpec>();
// Track how many times a particular mapping is found
Multiset mapSet = new Multiset(sourcesSize + 1);
/*
* If the result of the phi has an existing mapping, get it.
* Otherwise, add it to the list of regs that need mapping.
*/
if (ssaRegsMapped.get(resultReg)) {
mapSet.add(mapper.oldToNew(resultReg));
} else {
ssaRegs.add(result);
}
for (int i = 0; i < sourcesSize; i++) {
RegisterSpec source = sources.get(i);
SsaInsn def = ssaMeth.getDefinitionForRegister(source.getReg());
RegisterSpec sourceDef = def.getResult();
int sourceReg = sourceDef.getReg();
/*
* If a source of the phi has an existing mapping, get it.
* Otherwise, add it to the list of regs that need mapping.
*/
if (ssaRegsMapped.get(sourceReg)) {
mapSet.add(mapper.oldToNew(sourceReg));
} else {
ssaRegs.add(sourceDef);
}
}
// Try all existing mappings, with the most common ones first
for (int i = 0; i < mapSet.getSize(); i++) {
int maxReg = mapSet.getAndRemoveHighestCount();
tryMapRegs(ssaRegs, maxReg, category, false);
}
// Map any remaining unmapped regs with whatever fits
int mapReg = findNextUnreservedRopReg(paramRangeEnd, category);
while (!tryMapRegs(ssaRegs, mapReg, category, false)) {
mapReg = findNextUnreservedRopReg(mapReg + 1, category);
}
}
use of com.android.dx.ssa.SsaInsn in project buck by facebook.
the class FirstFitLocalCombiningAllocator method getParameterIndexForReg.
/**
* Gets the parameter index for SSA registers that are method parameters.
* {@code -1} is returned for non-parameter registers.
*
* @param ssaReg {@code >=0;} SSA register to look up
* @return parameter index or {@code -1} if not a parameter
*/
private int getParameterIndexForReg(int ssaReg) {
SsaInsn defInsn = ssaMeth.getDefinitionForRegister(ssaReg);
if (defInsn == null) {
return -1;
}
Rop opcode = defInsn.getOpcode();
// opcode == null for phi insns.
if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) {
CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn();
return ((CstInteger) origInsn.getConstant()).getValue();
}
return -1;
}
use of com.android.dx.ssa.SsaInsn in project buck by facebook.
the class LivenessAnalyzer method run.
/**
* From Appel algorithm 19.17.
*/
public void run() {
List<SsaInsn> useList = ssaMeth.getUseListForRegister(regV);
for (SsaInsn insn : useList) {
nextFunction = NextFunction.DONE;
if (insn instanceof PhiInsn) {
// If s is a phi-function with V as it's ith argument.
PhiInsn phi = (PhiInsn) insn;
for (SsaBasicBlock pred : phi.predBlocksForReg(regV, ssaMeth)) {
blockN = pred;
nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
handleTailRecursion();
}
} else {
blockN = insn.getBlock();
statementIndex = blockN.getInsns().indexOf(insn);
if (statementIndex < 0) {
throw new RuntimeException("insn not found in it's own block");
}
nextFunction = NextFunction.LIVE_IN_AT_STATEMENT;
handleTailRecursion();
}
}
int nextLiveOutBlock;
while ((nextLiveOutBlock = liveOutBlocks.nextSetBit(0)) >= 0) {
blockN = ssaMeth.getBlocks().get(nextLiveOutBlock);
liveOutBlocks.clear(nextLiveOutBlock);
nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
handleTailRecursion();
}
}
Aggregations