/** Evaluate the cost of a basic block, in number of real instructions. */ private int evaluateCost(BasicBlock bb) { int result = 0; for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements(); ) { Instruction s = e.nextElement(); if (!s.isBranch()) result++; } return result; }
/** * For each real non-branch instruction s in bb, * * <ul> * <li>Copy s to s', and store s' in the returned array * <li>Insert the function s->s' in the map * </ul> */ private Instruction[] copyAndMapInstructions( BasicBlock bb, HashMap<Instruction, Instruction> map) { if (bb == null) return new Instruction[0]; int count = 0; // first count the number of instructions for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements(); ) { Instruction s = e.nextElement(); if (s.isBranch()) continue; count++; } // now copy. Instruction[] result = new Instruction[count]; int i = 0; for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements(); ) { Instruction s = e.nextElement(); if (s.isBranch()) continue; Instruction sprime = s.copyWithoutLinks(); result[i++] = sprime; map.put(s, sprime); } return result; }
/** * Walks through the IR. For each StackLocationOperand, replace the operand with the appropriate * MemoryOperand. */ private void rewriteStackLocations() { // ESP is initially WORDSIZE above where the framepointer is going to be. ESPOffset = getFrameFixedSize() + WORDSIZE; Register ESP = ((PhysicalRegisterSet) ir.regpool.getPhysicalRegisterSet()).getESP(); boolean seenReturn = false; for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements(); ) { Instruction s = e.nextElement(); if (s.isReturn()) { seenReturn = true; continue; } if (s.isBranch()) { // restore ESP to home location at end of basic block. moveESPBefore(s, 0); continue; } if (s.operator() == BBEND) { if (seenReturn) { // at a return ESP will be at FrameFixedSize, seenReturn = false; ESPOffset = 0; } else { moveESPBefore(s, 0); } continue; } if (s.operator() == ADVISE_ESP) { ESPOffset = MIR_UnaryNoRes.getVal(s).asIntConstant().value; continue; } if (s.operator() == REQUIRE_ESP) { // ESP is required to be at the given offset from the bottom of the frame moveESPBefore(s, MIR_UnaryNoRes.getVal(s).asIntConstant().value); continue; } if (s.operator() == YIELDPOINT_PROLOGUE || s.operator() == YIELDPOINT_BACKEDGE || s.operator() == YIELDPOINT_EPILOGUE) { moveESPBefore(s, 0); continue; } if (s.operator() == IA32_MOV) { rewriteMoveInstruction(s); } // pop computes the effective address of its operand after ESP // is incremented. Therefore update ESPOffset before rewriting // stacklocation and memory operands. if (s.operator() == IA32_POP) { ESPOffset += WORDSIZE; } for (Enumeration<Operand> ops = s.getOperands(); ops.hasMoreElements(); ) { Operand op = ops.nextElement(); if (op instanceof StackLocationOperand) { StackLocationOperand sop = (StackLocationOperand) op; int offset = sop.getOffset(); if (sop.isFromTop()) { offset = FPOffset2SPOffset(offset); } offset -= ESPOffset; byte size = sop.getSize(); MemoryOperand M = MemoryOperand.BD( new RegisterOperand(ESP, PRIMITIVE_TYPE_FOR_WORD), Offset.fromIntSignExtend(offset), size, null, null); s.replaceOperand(op, M); } else if (op instanceof MemoryOperand) { MemoryOperand M = op.asMemory(); if ((M.base != null && M.base.getRegister() == ESP) || (M.index != null && M.index.getRegister() == ESP)) { M.disp = M.disp.minus(ESPOffset); } } } // push computes the effective address of its operand after ESP // is decremented. Therefore update ESPOffset after rewriting // stacklocation and memory operands. if (s.operator() == IA32_PUSH) { ESPOffset -= WORDSIZE; } } }
/** * Do any of the instructions in a basic block preclude eliminating the basic block with * conditional moves? */ private boolean hasCMTaboo(BasicBlock bb) { if (bb == null) return false; // Note: it is taboo to assign more than once to any register in the // block. HashSet<Register> defined = new HashSet<Register>(); for (Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); e.hasMoreElements(); ) { Instruction s = e.nextElement(); if (s.isBranch()) continue; // for now, only the following opcodes are legal. switch (s.operator.opcode) { case INT_MOVE_opcode: case REF_MOVE_opcode: case DOUBLE_MOVE_opcode: case FLOAT_MOVE_opcode: case INT_ADD_opcode: case REF_ADD_opcode: case FLOAT_ADD_opcode: case DOUBLE_ADD_opcode: case INT_SUB_opcode: case REF_SUB_opcode: case FLOAT_SUB_opcode: case DOUBLE_SUB_opcode: case INT_MUL_opcode: case FLOAT_MUL_opcode: case DOUBLE_MUL_opcode: case INT_NEG_opcode: case FLOAT_NEG_opcode: case DOUBLE_NEG_opcode: case REF_SHL_opcode: case INT_SHL_opcode: case REF_SHR_opcode: case INT_SHR_opcode: case REF_USHR_opcode: case INT_USHR_opcode: case REF_AND_opcode: case INT_AND_opcode: case REF_OR_opcode: case INT_OR_opcode: case REF_XOR_opcode: case INT_XOR_opcode: case REF_NOT_opcode: case INT_NOT_opcode: case INT_2BYTE_opcode: case INT_2USHORT_opcode: case INT_2SHORT_opcode: case FLOAT_2DOUBLE_opcode: case DOUBLE_2FLOAT_opcode: // these are OK. break; default: return true; } // make sure no register is defined more than once in this block. for (Enumeration<Operand> defs = s.getDefs(); defs.hasMoreElements(); ) { Operand def = defs.nextElement(); if (VM.VerifyAssertions) VM._assert(def.isRegister()); Register r = def.asRegister().getRegister(); if (defined.contains(r)) return true; defined.add(r); } } return false; }
/** * Perform the transformation to replace conditional branch with a sequence using conditional * moves. * * @param ir governing IR * @param diamond the IR diamond structure to replace * @param cb conditional branch instruction at the head of the diamond */ private void doCondMove(IR ir, Diamond diamond, Instruction cb) { BasicBlock taken = diamond.getTaken(); BasicBlock notTaken = diamond.getNotTaken(); // for each non-branch instruction s in the diamond, // copy s to a new instruction s' // and store a mapping from s to s' HashMap<Instruction, Instruction> takenInstructions = new HashMap<Instruction, Instruction>(); Instruction[] takenInstructionList = copyAndMapInstructions(taken, takenInstructions); HashMap<Instruction, Instruction> notTakenInstructions = new HashMap<Instruction, Instruction>(); Instruction[] notTakenInstructionList = copyAndMapInstructions(notTaken, notTakenInstructions); // Extract the values and condition from the conditional branch. Operand val1 = IfCmp.getVal1(cb); Operand val2 = IfCmp.getVal2(cb); ConditionOperand cond = IfCmp.getCond(cb); // Copy val1 and val2 to temporaries, just in case they're defined in // the diamond. If they're not defined in the diamond, copy prop // should clean these moves up. RegisterOperand tempVal1 = ir.regpool.makeTemp(val1); Operator op = IRTools.getMoveOp(tempVal1.getType()); cb.insertBefore(Move.create(op, tempVal1.copyRO(), val1.copy())); RegisterOperand tempVal2 = ir.regpool.makeTemp(val2); op = IRTools.getMoveOp(tempVal2.getType()); cb.insertBefore(Move.create(op, tempVal2.copyRO(), val2.copy())); // For each instruction in each temporary set, rewrite it to def a new // temporary, and insert it before the branch. rewriteWithTemporaries(takenInstructionList, ir); rewriteWithTemporaries(notTakenInstructionList, ir); insertBefore(takenInstructionList, cb); insertBefore(notTakenInstructionList, cb); // For each register defined in the TAKEN branch, save a mapping to // the corresponding conditional move. HashMap<Register, Instruction> takenMap = new HashMap<Register, Instruction>(); // Now insert conditional moves to replace each instruction in the diamond. // First handle the taken branch. if (taken != null) { for (Enumeration<Instruction> e = taken.forwardRealInstrEnumerator(); e.hasMoreElements(); ) { Instruction s = e.nextElement(); if (s.isBranch()) continue; Operand def = s.getDefs().nextElement(); // if the register does not span a basic block, it is a temporary // that will now be dead if (def.asRegister().getRegister().spansBasicBlock()) { Instruction tempS = takenInstructions.get(s); RegisterOperand temp = (RegisterOperand) tempS.getDefs().nextElement(); op = IRTools.getCondMoveOp(def.asRegister().getType()); Instruction cmov = CondMove.create( op, def.asRegister(), tempVal1.copy(), tempVal2.copy(), cond.copy().asCondition(), temp.copy(), def.copy()); takenMap.put(def.asRegister().getRegister(), cmov); cb.insertBefore(cmov); } s.remove(); } } // For each register defined in the NOT-TAKEN branch, save a mapping to // the corresponding conditional move. HashMap<Register, Instruction> notTakenMap = new HashMap<Register, Instruction>(); // Next handle the not taken branch. if (notTaken != null) { for (Enumeration<Instruction> e = notTaken.forwardRealInstrEnumerator(); e.hasMoreElements(); ) { Instruction s = e.nextElement(); if (s.isBranch()) continue; Operand def = s.getDefs().nextElement(); // if the register does not span a basic block, it is a temporary // that will now be dead if (def.asRegister().getRegister().spansBasicBlock()) { Instruction tempS = notTakenInstructions.get(s); RegisterOperand temp = (RegisterOperand) tempS.getDefs().nextElement(); Instruction prevCmov = takenMap.get(def.asRegister().getRegister()); if (prevCmov != null) { // if this register was also defined in the taken branch, change // the previous cmov with a different 'False' Value CondMove.setFalseValue(prevCmov, temp.copy()); notTakenMap.put(def.asRegister().getRegister(), prevCmov); } else { // create a new cmov instruction op = IRTools.getCondMoveOp(def.asRegister().getType()); Instruction cmov = CondMove.create( op, def.asRegister(), tempVal1.copy(), tempVal2.copy(), cond.copy().asCondition(), def.copy(), temp.copy()); cb.insertBefore(cmov); notTakenMap.put(def.asRegister().getRegister(), cmov); } } s.remove(); } } // Mutate the conditional branch into a GOTO. BranchOperand target = diamond.getBottom().makeJumpTarget(); Goto.mutate(cb, GOTO, target); // Delete a potential GOTO after cb. Instruction next = cb.nextInstructionInCodeOrder(); if (next.operator != BBEND) { next.remove(); } // Recompute the CFG. diamond.getTop().recomputeNormalOut(ir); // fix the CFG }