/** * Given a symbolic register, return a code that gives the physical register type to hold the * value of the symbolic register. * * @param r a symbolic register * @return one of INT_REG, DOUBLE_REG */ public static int getPhysicalRegisterType(Register r) { if (r.isInteger() || r.isLong() || r.isAddress()) { return INT_REG; } else if (r.isFloatingPoint()) { return DOUBLE_REG; } else { throw new OptimizingCompilerException("getPhysicalRegisterType " + " unexpected " + r); } }
/** * @param type one of INT_VALUE, FLOAT_VALUE, or DOUBLE_VALUE * @return the move operator for a type of value. */ private static Operator getMoveOperator(Register type) { if (type.isNatural()) { return IA32_MOV; } else if (type.isDouble()) { return SSE2_FULL ? IA32_MOVSD : IA32_FMOV; } else if (type.isFloat()) { return SSE2_FULL ? IA32_MOVSS : IA32_FMOV; } else { OptimizingCompilerException.TODO("getMoveOperator: unsupported: " + type); return null; } }
/** * @param type one of INT_VALUE, FLOAT_VALUE, or DOUBLE_VALUE * @return the size of a type of value, in bytes. NOTE: For the purpose of register allocation, an * x87 FLOAT_VALUE is 64 bits! */ private static byte getSizeOfType(Register type) { if (type.isNatural()) { if (VM.BuildFor64Addr && type.isInteger()) { return (byte) BYTES_IN_INT; } else { return (byte) WORDSIZE; } } else if (type.isFloat()) { if (SSE2_FULL) return (byte) BYTES_IN_FLOAT; return (byte) BYTES_IN_DOUBLE; } else if (type.isDouble()) { return (byte) BYTES_IN_DOUBLE; } else { OptimizingCompilerException.TODO("getSizeOfValue: unsupported: " + type); return (byte) -1; } }
/** * Bypass MOVE instructions that def an operand: return the first def in the chain that is not the * result of a MOVE instruction. * * <p>Note: treat PI instructions like MOVES * * @param op the RegisterOperand */ private Operand bypassMoves(Operand op) { if (!op.isRegister()) return op; Register r = op.asRegister().getRegister(); Instruction def = r.getFirstDef(); if (def == null) { return op; } if (r.isPhysical()) { return op; } if (Move.conforms(def)) { // In a perfect world, this shouldn't happen. Copy propagation // in SSA form should remove all 'normal' moves. // We can't simply bypass this move, since it may lead to // infinite mutual recursion. return op; } else if (def.operator == PI) { return bypassMoves(GuardedUnary.getVal(def)); } else { return op; } }
@Override public void insertUnspillBefore(Instruction s, Register r, Register type, int location) { Operator move = getMoveOperator(type); byte size = getSizeOfType(type); RegisterOperand rOp; if (type.isFloat()) { rOp = F(r); } else if (type.isDouble()) { rOp = D(r); } else { if (VM.BuildFor64Addr && type.isInteger()) { rOp = new RegisterOperand(r, TypeReference.Int); } else { rOp = new RegisterOperand(r, PRIMITIVE_TYPE_FOR_WORD); } } StackLocationOperand spillLoc = new StackLocationOperand(true, -location, size); Instruction unspillOp = MIR_Move.create(move, rOp, spillLoc); if (VERBOSE_DEBUG) { System.out.println("INSERT_UNSPILL_BEFORE: " + "Inserting " + unspillOp + " before " + s); } s.insertBefore(unspillOp); }
@Test public void assignCausesAssignmentOfTheIntervalsRegisterToTheGivenRegister() { Register r = new Register(0); CompoundInterval ci = new CompoundInterval(DEFAULT_BEGIN, DEFAULT_END, r); Register s = new Register(1); RegisterAllocatorState regAllocState = new RegisterAllocatorState(0); assertThat(ci.isAssigned(regAllocState), is(false)); assertNull(ci.getAssignment(regAllocState)); ci.assign(s); assertThat(s.mapsToRegister, is(r)); assertThat(!s.isSpilled() && s.isTouched() && s.isAllocated(), is(true)); assertThat(r.mapsToRegister, is(s)); assertThat(!r.isSpilled() && r.isTouched() && r.isAllocated(), is(true)); assertThat(ci.isAssigned(regAllocState), is(true)); assertThat(ci.getAssignment(regAllocState), is(s)); }
@Override public boolean needScratch(Register r, Instruction s) { // We never need a scratch register for a floating point value in an // FMOV instruction. if (r.isFloatingPoint() && s.operator() == IA32_FMOV) return false; // never need a scratch register for a YIELDPOINT_OSR if (s.operator() == YIELDPOINT_OSR) return false; // Some MOVEs never need scratch registers if (isScratchFreeMove(s)) return false; // If s already has a memory operand, it is illegal to introduce // another. if (s.hasMemoryOperand()) return true; // If r appears more than once in the instruction, we can't // use a memory operand for all occurrences, so we will need a scratch int count = 0; for (Enumeration<Operand> ops = s.getOperands(); ops.hasMoreElements(); ) { Operand op = ops.nextElement(); if (op.isRegister()) { RegisterOperand rop = op.asRegister(); if (rop.getRegister() == r) { count++; } } } if (count > 1) return true; // Check the architecture restrictions. if (RegisterRestrictions.mustBeInRegister(r, s)) return true; // Otherwise, everything is OK. return false; }
@Override public void computeNonVolatileArea() { GenericPhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); if (ir.compiledMethod.isSaveVolatile()) { // Record that we use every nonvolatile GPR int numGprNv = PhysicalRegisterSet.getNumberOfNonvolatileGPRs(); ir.compiledMethod.setNumberOfNonvolatileGPRs((short) numGprNv); // set the frame size frameSize += numGprNv * WORDSIZE; frameSize = align(frameSize, STACKFRAME_ALIGNMENT); // TODO!! ir.compiledMethod.setNumberOfNonvolatileFPRs((short) 0); // Record that we need a stack frame. setFrameRequired(); int fpuStateSaveAreaBegin = spillPointer; // Calculate FPU state save area for restoreFloatingPointState(..) // and saveFloatingPointState(..) if (SSE2_FULL) { for (int i = 0; i < 8; i++) { fsaveLocation = allocateNewSpillLocation(DOUBLE_REG); } } else { // Grab 108 bytes (same as 27 4-byte spills) in the stack // frame, as a place to store the floating-point state with FSAVE for (int i = 0; i < 27; i++) { fsaveLocation = allocateNewSpillLocation(INT_REG); } } int fpuStateSaveAreaEnd = spillPointer; int fpuStateSize = fpuStateSaveAreaEnd - fpuStateSaveAreaBegin; if (VM.VerifyAssertions) { VM._assert(fpuStateSize == OPT_SAVE_VOLATILE_SPACE_FOR_FPU_STATE); } int volatileGPRSaveAreaBegin = spillPointer; // Map each volatile register to a spill location. int i = 0; for (Enumeration<Register> e = phys.enumerateVolatileGPRs(); e.hasMoreElements(); i++) { e.nextElement(); // Note that as a side effect, the following call bumps up the // frame size. saveVolatileGPRLocation[i] = allocateNewSpillLocation(INT_REG); } int volatileGPRSaveAreaEnd = spillPointer; int volatileGPRSaveAreaSize = volatileGPRSaveAreaEnd - volatileGPRSaveAreaBegin; if (VM.VerifyAssertions) { VM._assert(volatileGPRSaveAreaSize == OPT_SAVE_VOLATILE_SPACE_FOR_VOLATILE_GPRS); VM._assert((volatileGPRSaveAreaSize + fpuStateSize) == OPT_SAVE_VOLATILE_TOTAL_SIZE); } // Map each non-volatile register to a spill location. i = 0; for (Enumeration<Register> e = phys.enumerateNonvolatileGPRs(); e.hasMoreElements(); i++) { e.nextElement(); // Note that as a side effect, the following call bumps up the // frame size. nonVolatileGPRLocation[i] = allocateNewSpillLocation(INT_REG); } // Set the offset to find non-volatiles. int gprOffset = getNonvolatileGPROffset(0); ir.compiledMethod.setUnsignedNonVolatileOffset(gprOffset); } else { // Count the number of nonvolatiles used. int numGprNv = 0; int i = 0; for (Enumeration<Register> e = phys.enumerateNonvolatileGPRs(); e.hasMoreElements(); ) { Register r = e.nextElement(); if (r.isTouched()) { // Note that as a side effect, the following call bumps up the // frame size. nonVolatileGPRLocation[i++] = allocateNewSpillLocation(INT_REG); numGprNv++; } } // Update the OptCompiledMethod object. ir.compiledMethod.setNumberOfNonvolatileGPRs((short) numGprNv); if (numGprNv > 0) { int gprOffset = getNonvolatileGPROffset(0); ir.compiledMethod.setUnsignedNonVolatileOffset(gprOffset); // record that we need a stack frame setFrameRequired(); } else { ir.compiledMethod.setUnsignedNonVolatileOffset(0); } ir.compiledMethod.setNumberOfNonvolatileFPRs((short) 0); } }
/** * Add a node to the value graph for every symbolic register. * * <p><b>PRECONDITION:</b> register lists are computed and valid * * @param ir the governing IR */ private void addRegisterNodes(IR ir) { for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) { findOrCreateVertex(reg); } }
public PhysicalRegisterSet() { // 1. Create all the physical registers in the pool. for (int i = 0; i < reg.length; i++) { Register r = new Register(i); r.setPhysical(); reg[i] = r; } // 2. Set the 'integer' attribute on each GPR for (int i = FIRST_INT; i < FIRST_DOUBLE; i++) { reg[i].setInteger(); } // 3. Set the 'double' attribute on each FPR for (int i = FIRST_DOUBLE; i < FIRST_SPECIAL; i++) { reg[i].setDouble(); } // 4. set up the volatile GPRs for (Enumeration<Register> e = enumerateVolatileGPRs(); e.hasMoreElements(); ) { Register r = e.nextElement(); r.setVolatile(); } // 5. set up the non-volatile GPRs for (Enumeration<Register> e = enumerateNonvolatileGPRs(); e.hasMoreElements(); ) { Register r = e.nextElement(); r.setNonVolatile(); } // 6. set properties on some special registers reg[AF].setSpansBasicBlock(); reg[CF].setSpansBasicBlock(); reg[OF].setSpansBasicBlock(); reg[PF].setSpansBasicBlock(); reg[SF].setSpansBasicBlock(); reg[ZF].setSpansBasicBlock(); reg[C0].setSpansBasicBlock(); reg[C1].setSpansBasicBlock(); reg[C2].setSpansBasicBlock(); reg[C3].setSpansBasicBlock(); reg[THREAD_REGISTER.value()].setSpansBasicBlock(); // For SSE2 reg[ST0].setDouble(); reg[ST1].setDouble(); // 7. set up the volatile FPRs for (Enumeration<Register> e = enumerateVolatileFPRs(); e.hasMoreElements(); ) { Register r = e.nextElement(); r.setVolatile(); } // 8. set up the non-volatile FPRs for (Enumeration<Register> e = enumerateNonvolatileFPRs(); e.hasMoreElements(); ) { Register r = e.nextElement(); r.setNonVolatile(); } // 9. Cache the volatile registers for efficiency volatileSet = new BitSet(this); for (Enumeration<Register> e = enumerateVolatiles(); e.hasMoreElements(); ) { Register r = e.nextElement(); volatileSet.add(r); } // 10. Cache the FPRs for efficiency fpSet = new BitSet(this); for (Enumeration<Register> e = enumerateFPRs(); e.hasMoreElements(); ) { Register r = e.nextElement(); fpSet.add(r); } // Note no registers are excluded from live analysis (as is done for PPC) }