/** * Adds {@code regV} to the live-in list for this block. This is called by the liveness analyzer. * * @param regV register that is live-in for this block. */ public void addLiveIn(int regV) { if (liveIn == null) { liveIn = SetFactory.makeLivenessSet(parent.getRegCount()); } liveIn.add(regV); }
/** Applies the optimization. */ private void run() { int regSz = ssaMeth.getRegCount(); ArrayList<TypedConstant> constantList = getConstsSortedByCountUse(); int toCollect = Math.min(constantList.size(), MAX_COLLECTED_CONSTANTS); SsaBasicBlock start = ssaMeth.getEntryBlock(); // Constant to new register containing the constant HashMap<TypedConstant, RegisterSpec> newRegs = new HashMap<TypedConstant, RegisterSpec>(toCollect); for (int i = 0; i < toCollect; i++) { TypedConstant cst = constantList.get(i); RegisterSpec result = RegisterSpec.make(ssaMeth.makeNewSsaReg(), cst); Rop constRop = Rops.opConst(cst); if (constRop.getBranchingness() == Rop.BRANCH_NONE) { start.addInsnToHead( new PlainCstInsn( Rops.opConst(cst), SourcePosition.NO_INFO, result, RegisterSpecList.EMPTY, cst)); } else { // We need two new basic blocks along with the new insn SsaBasicBlock entryBlock = ssaMeth.getEntryBlock(); SsaBasicBlock successorBlock = entryBlock.getPrimarySuccessor(); // Insert a block containing the const insn. SsaBasicBlock constBlock = entryBlock.insertNewSuccessor(successorBlock); constBlock.replaceLastInsn( new ThrowingCstInsn( constRop, SourcePosition.NO_INFO, RegisterSpecList.EMPTY, StdTypeList.EMPTY, cst)); // Insert a block containing the move-result-pseudo insn. SsaBasicBlock resultBlock = constBlock.insertNewSuccessor(successorBlock); PlainInsn insn = new PlainInsn( Rops.opMoveResultPseudo(result.getTypeBearer()), SourcePosition.NO_INFO, result, RegisterSpecList.EMPTY); resultBlock.addInsnToHead(insn); } newRegs.put(cst, result); } updateConstUses(newRegs, regSz); }
/** * Does the extraction. * * @return {@code non-null;} the extracted information */ private LocalVariableInfo doit() { // FIXME why is this needed here? if (method.getRegCount() > 0) { for (int bi = method.getEntryBlockIndex(); bi >= 0; bi = workSet.nextSetBit(0)) { workSet.clear(bi); processBlock(bi); } } resultInfo.setImmutable(); return resultInfo; }
/** * Returns the set of live-out registers. Valid after register interference graph has been * generated, otherwise empty. * * @return {@code non-null;} live-out register set */ public IntSet getLiveOutRegs() { if (liveOut == null) { liveOut = SetFactory.makeLivenessSet(parent.getRegCount()); } return liveOut; }
/** * Ensures that all move operations in this block occur such that reads of any register happen * before writes to that register. NOTE: caller is expected to returnSpareRegisters()! TODO: See * Briggs, et al "Practical Improvements to the Construction and Destruction of Static Single * Assignment Form" section 5. a) This can be done in three passes. * * @param toSchedule List of instructions. Must consist only of moves. */ private void scheduleUseBeforeAssigned(List<SsaInsn> toSchedule) { BitSet regsUsedAsSources = new BitSet(parent.getRegCount()); // TODO: Get rid of this. BitSet regsUsedAsResults = new BitSet(parent.getRegCount()); int sz = toSchedule.size(); int insertPlace = 0; while (insertPlace < sz) { int oldInsertPlace = insertPlace; // Record all registers used as sources in this block. for (int i = insertPlace; i < sz; i++) { setRegsUsed(regsUsedAsSources, toSchedule.get(i).getSources().get(0)); setRegsUsed(regsUsedAsResults, toSchedule.get(i).getResult()); } /* * If there are no circular dependencies, then there exists n * instructions where n > 1 whose result is not used as a source. */ for (int i = insertPlace; i < sz; i++) { SsaInsn insn = toSchedule.get(i); /* * Move these n registers to the front, since they overwrite * nothing. */ if (!checkRegUsed(regsUsedAsSources, insn.getResult())) { Collections.swap(toSchedule, i, insertPlace++); } } /* * If we've made no progress in this iteration, there's a circular * dependency. Split it using the temp reg. */ if (oldInsertPlace == insertPlace) { SsaInsn insnToSplit = null; // Find an insn whose result is used as a source. for (int i = insertPlace; i < sz; i++) { SsaInsn insn = toSchedule.get(i); if (checkRegUsed(regsUsedAsSources, insn.getResult()) && checkRegUsed(regsUsedAsResults, insn.getSources().get(0))) { insnToSplit = insn; /* * We're going to split this insn; move it to the front. */ Collections.swap(toSchedule, insertPlace, i); break; } } // At least one insn will be set above. RegisterSpec result = insnToSplit.getResult(); RegisterSpec tempSpec = result.withReg(parent.borrowSpareRegister(result.getCategory())); NormalSsaInsn toAdd = new NormalSsaInsn( new PlainInsn( Rops.opMove(result.getType()), SourcePosition.NO_INFO, tempSpec, insnToSplit.getSources()), this); toSchedule.add(insertPlace++, toAdd); RegisterSpecList newSources = RegisterSpecList.make(tempSpec); NormalSsaInsn toReplace = new NormalSsaInsn( new PlainInsn( Rops.opMove(result.getType()), SourcePosition.NO_INFO, result, newSources), this); toSchedule.set(insertPlace, toReplace); // The size changed. sz = toSchedule.size(); } regsUsedAsSources.clear(); regsUsedAsResults.clear(); } }
/** * 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; }