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