/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.ir.ppc; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.CONDITION_REG; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.CR; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.CTR; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.DOUBLE_REG; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.FIRST_CONDITION; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.FIRST_DOUBLE; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.FIRST_DOUBLE_PARAM; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.FIRST_INT; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.FIRST_INT_PARAM; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.FIRST_INT_RETURN; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.FIRST_SPECIAL; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.INT_REG; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.LR; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.NUMBER_DOUBLE_PARAM; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.NUMBER_INT_PARAM; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.SPECIAL_REG; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.TL; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.TU; import static org.jikesrvm.compilers.opt.regalloc.ppc.PhysicalRegisterConstants.XER; import static org.jikesrvm.ppc.RegisterConstants.FIRST_NONVOLATILE_FPR; import static org.jikesrvm.ppc.RegisterConstants.FIRST_NONVOLATILE_GPR; import static org.jikesrvm.ppc.RegisterConstants.FIRST_SCRATCH_FPR; import static org.jikesrvm.ppc.RegisterConstants.FIRST_SCRATCH_GPR; import static org.jikesrvm.ppc.RegisterConstants.FIRST_VOLATILE_FPR; import static org.jikesrvm.ppc.RegisterConstants.FIRST_VOLATILE_GPR; import static org.jikesrvm.ppc.RegisterConstants.FRAME_POINTER; import static org.jikesrvm.ppc.RegisterConstants.JTOC_POINTER; import static org.jikesrvm.ppc.RegisterConstants.LAST_NONVOLATILE_FPR; import static org.jikesrvm.ppc.RegisterConstants.LAST_NONVOLATILE_GPR; import static org.jikesrvm.ppc.RegisterConstants.LAST_SCRATCH_FPR; import static org.jikesrvm.ppc.RegisterConstants.LAST_SCRATCH_GPR; import static org.jikesrvm.ppc.RegisterConstants.LAST_VOLATILE_FPR; import static org.jikesrvm.ppc.RegisterConstants.LAST_VOLATILE_GPR; import static org.jikesrvm.ppc.RegisterConstants.NUM_CRS; import static org.jikesrvm.ppc.RegisterConstants.NUM_FPRS; import static org.jikesrvm.ppc.RegisterConstants.NUM_GPRS; import static org.jikesrvm.ppc.RegisterConstants.NUM_NONVOLATILE_FPRS; import static org.jikesrvm.ppc.RegisterConstants.NUM_NONVOLATILE_GPRS; import static org.jikesrvm.ppc.RegisterConstants.NUM_SPECIALS; import static org.jikesrvm.ppc.RegisterConstants.THREAD_REGISTER; import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_DOUBLE; import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS; import java.util.Enumeration; import org.jikesrvm.VM; import org.jikesrvm.architecture.MachineRegister; import org.jikesrvm.compilers.opt.OptimizingCompilerException; import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet; import org.jikesrvm.compilers.opt.ir.Register; import org.jikesrvm.compilers.opt.util.BitSet; import org.jikesrvm.compilers.opt.util.CompoundEnumerator; import org.jikesrvm.compilers.opt.util.ReverseEnumerator; import org.jikesrvm.util.EmptyEnumeration; /** * This class represents a set of Registers corresponding to the * PowerPC register set. * * <P> Implementation Notes: * <P> The register allocator allocates registers according to the order * in these lists. For volatile registers, it traverses the lists in * order, starting with getFirstVolatile() and traversing with getNext(). * For non-volatiles, it traverses the lists * <STRONG> Backwards </STRONG>, starting with getLastNonvolatile() and * using getPrev(). * <P> TODO; clean up all this and provide appropriate enumerators */ public final class PhysicalRegisterSet extends GenericPhysicalRegisterSet { /** * This array holds a pool of objects representing physical registers */ private final Register[] reg = new Register[getSize()]; /** * The set of volatile registers; cached for efficiency */ private final BitSet volatileSet; /** * The condition registers that we allocate * To avoid expensive save/restores when * making a JNI transition Jikes RVM only uses the * CR that the 64 bit PowerPC ELF ABI defines to be volatile. * * We reserve one of the volatiles, CR7 for use only in yieldpoints. * This ensures that a yieldpoint won't bash an allocated CR. */ private static final int[] CR_NUMS = new int[]{0, 1, 5, 6}; private static final int TSR_REG = 7; /** * @return the total number of physical registers. */ public static int getSize() { return NUM_GPRS + NUM_FPRS + NUM_CRS + NUM_SPECIALS; } @Override public int getNumberOfPhysicalRegisters() { return getSize(); } /** * @return the total number of nonvolatile GPRs. */ public static int getNumberOfNonvolatileGPRs() { return NUM_NONVOLATILE_GPRS; } /** * @return the total number of nonvolatile FPRs. */ public static int getNumberOfNonvolatileFPRs() { return NUM_NONVOLATILE_FPRS; } /** * Constructor: set up a pool of physical registers. */ 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' or 'long' attribute on each GPR for (int i = FIRST_INT; i < FIRST_DOUBLE; i++) { if (VM.BuildFor32Addr) { reg[i].setInteger(); } else { reg[i].setLong(); } } // 3. Set the 'double' attribute on each FPR for (int i = FIRST_DOUBLE; i < FIRST_CONDITION; i++) { reg[i].setDouble(); } // 4. Set the 'condition' attribute on each CR for (int i = FIRST_CONDITION; i < FIRST_SPECIAL; i++) { reg[i].setCondition(); } // 5. set up the volatile GPRs for (int i = FIRST_VOLATILE_GPR.value(); i < LAST_VOLATILE_GPR.value(); i++) { Register r = reg[i]; r.setVolatile(); } reg[LAST_VOLATILE_GPR.value()].setVolatile(); for (int i = FIRST_SCRATCH_GPR.value(); i < LAST_SCRATCH_GPR.value(); i++) { Register r = reg[i]; r.setVolatile(); } reg[LAST_SCRATCH_GPR.value()].setVolatile(); // 6. set up the non-volatile GPRs for (int i = FIRST_NONVOLATILE_GPR.value(); i < LAST_NONVOLATILE_GPR.value(); i++) { Register r = reg[i]; r.setNonVolatile(); } // 7. set properties on some special registers reg[THREAD_REGISTER.value()].setSpansBasicBlock(); reg[FRAME_POINTER.value()].setSpansBasicBlock(); reg[JTOC_POINTER.value()].setSpansBasicBlock(); // 8. set up the volatile FPRs for (int i = FIRST_DOUBLE + FIRST_VOLATILE_FPR.value(); i < FIRST_DOUBLE + LAST_VOLATILE_FPR.value(); i++) { Register r = reg[i]; r.setVolatile(); } reg[FIRST_DOUBLE + LAST_VOLATILE_FPR.value()].setVolatile(); if (FIRST_SCRATCH_FPR != LAST_SCRATCH_FPR) { for (int i = FIRST_DOUBLE + FIRST_SCRATCH_FPR.value(); i < FIRST_DOUBLE + LAST_SCRATCH_FPR.value(); i++) { Register r = reg[i]; r.setVolatile(); } } reg[FIRST_DOUBLE + LAST_SCRATCH_FPR.value()].setVolatile(); // 9. set up the non-volatile FPRs for (int i = FIRST_DOUBLE + FIRST_NONVOLATILE_FPR.value(); i < FIRST_DOUBLE + LAST_NONVOLATILE_FPR.value(); i++) { Register r = reg[i]; r.setNonVolatile(); } // 10. set up the condition registers for (int i : CR_NUMS) { reg[FIRST_CONDITION + i].setVolatile(); } // 11. cache the volatiles for efficiency volatileSet = new BitSet(this); for (Enumeration<Register> e = enumerateVolatiles(); e.hasMoreElements();) { Register r = e.nextElement(); volatileSet.add(r); } // 12. Show which registers should be excluded from live analysis reg[CTR].setExcludedLiveA(); reg[CR].setExcludedLiveA(); reg[TU].setExcludedLiveA(); reg[TL].setExcludedLiveA(); reg[XER].setExcludedLiveA(); reg[FRAME_POINTER.value()].setExcludedLiveA(); reg[JTOC_POINTER.value()].setExcludedLiveA(); reg[LR].setExcludedLiveA(); } /** * Is a certain physical register allocatable? */ @Override public boolean isAllocatable(Register r) { if (r.number == THREAD_REGISTER.value() || r.number == FRAME_POINTER.value() || r.number == JTOC_POINTER.value()) { return false; } else { return (r.number < FIRST_SPECIAL); } } /** * @return the XER register. */ public Register getXER() { return reg[XER]; } /** * @return the LR register;. */ public Register getLR() { return reg[LR]; } /** * @return the CTR register */ public Register getCTR() { return reg[CTR]; } /** * @return the TU register */ public Register getTU() { return reg[TU]; } /** * @return the TL register */ public Register getTL() { return reg[TL]; } /** * @return the CR register */ public Register getCR() { return reg[CR]; } /** * @return the JTOC register */ public Register getJTOC() { return reg[JTOC_POINTER.value()]; } @Override public Register getFP() { return reg[FRAME_POINTER.value()]; } @Override public Register getTR() { return reg[THREAD_REGISTER.value()]; } /** * @return the thread-switch register */ public Register getTSR() { return reg[FIRST_CONDITION + TSR_REG]; } @Override public Register getGPR(int n) { return reg[FIRST_INT + n]; } /** * @return the nth physical GPR */ @Override public Register getGPR(MachineRegister n) { return reg[FIRST_INT + n.value()]; } /** * @return the first scratch GPR */ public Register getFirstScratchGPR() { return reg[FIRST_SCRATCH_GPR.value()]; } /** * @return the last scratch GPR */ public Register getLastScratchGPR() { return reg[LAST_SCRATCH_GPR.value()]; } /** * @return the first volatile GPR */ public Register getFirstVolatileGPR() { return reg[FIRST_INT + FIRST_VOLATILE_GPR.value()]; } /** * @return the first nonvolatile GPR */ public Register getFirstNonvolatileGPR() { return reg[FIRST_INT + FIRST_NONVOLATILE_GPR.value()]; } /** * @return the last nonvolatile GPR */ public Register getLastNonvolatileGPR() { return reg[FIRST_INT + LAST_NONVOLATILE_GPR.value()]; } @Override public Register getFirstReturnGPR() { return reg[FIRST_INT_RETURN]; } @Override public Register getFPR(int n) { return reg[FIRST_DOUBLE + n]; } /** * @return the first scratch FPR */ public Register getFirstScratchFPR() { return reg[FIRST_DOUBLE + FIRST_SCRATCH_FPR.value()]; } /** * @return the first volatile FPR */ public Register getFirstVolatileFPR() { return reg[FIRST_DOUBLE + FIRST_VOLATILE_FPR.value()]; } /** * @return the last scratch FPR */ public Register getLastScratchFPR() { return reg[FIRST_DOUBLE + LAST_SCRATCH_FPR.value()]; } /** * @return the first nonvolatile FPR */ public Register getFirstNonvolatileFPR() { return reg[FIRST_DOUBLE + FIRST_NONVOLATILE_FPR.value()]; } /** * @return the last nonvolatile FPR */ public Register getLastNonvolatileFPR() { return reg[FIRST_DOUBLE + LAST_NONVOLATILE_FPR.value()]; } /** * @param n number of the condition register * @return the nth physical condition register */ public Register getConditionRegister(int n) { return reg[FIRST_CONDITION + n]; } /** * @return the first condition */ public Register getFirstConditionRegister() { return reg[FIRST_CONDITION]; } /** * @return the first volatile CR */ public Register getFirstVolatileConditionRegister() { if (VM.VerifyAssertions) { VM._assert(getFirstConditionRegister() != getTSR()); } return getFirstConditionRegister(); } @Override public Register get(int n) { return reg[n]; } /** * @return the first volatile physical register of a given class * @param regClass one of INT_REG, DOUBLE_REG, CONDITION_REG, or * SPECIAL_REG */ public Register getFirstVolatile(int regClass) { switch (regClass) { case INT_REG: return getFirstVolatileGPR(); case DOUBLE_REG: return getFirstVolatileFPR(); case CONDITION_REG: return getFirstVolatileConditionRegister(); case SPECIAL_REG: return null; default: throw new OptimizingCompilerException("Unknown register class"); } } /** * @return the first nonvolatile physical register of a given class * @param regClass one of INT_REG, DOUBLE_REG, CONDITION_REG, or * SPECIAL_REG */ public Register getLastNonvolatile(int regClass) { switch (regClass) { case INT_REG: return getLastNonvolatileGPR(); case DOUBLE_REG: return getLastNonvolatileFPR(); case CONDITION_REG: return null; case SPECIAL_REG: return null; default: throw new OptimizingCompilerException("Unknown register class"); } } /** * Given a symbolic register, return a cdoe 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, or CONDITION_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 if (r.isCondition()) { return CONDITION_REG; } else { throw new OptimizingCompilerException("getPhysicalRegisterType " + " unexpected " + r); } } /** * Given a physical register (XER, LR, or CTR), return the integer that * denotes the PowerPC Special Purpose Register (SPR) in the PPC * instruction set. See p.129 of PPC ISA book * * @param r a physical register (XER, LR or CTR) * @return the integer that denotes the PowerPC Special Purpose Register (SPR) * in the PPC instruction set. */ public byte getSPR(Register r) { if (VM.VerifyAssertions) { VM._assert((r == getXER()) || (r == getLR()) || (r == getCTR())); } if (r == getXER()) { return 1; } else if (r == getLR()) { return 8; } else if (r == getCTR()) { return 9; } else { throw new OptimizingCompilerException("Invalid SPR"); } } /** * register names for each class. used in printing the IR * The indices for "FP" and "JTOC" should always match the * final static values of int FP and int JTOC defined below. */ private static final String[] registerName = new String[getSize()]; static { String[] regName = registerName; for (int i = 0; i < NUM_GPRS; i++) { regName[i + FIRST_INT] = "R" + i; } for (int i = 0; i < NUM_FPRS; i++) { regName[i + FIRST_DOUBLE] = "F" + i; } for (int i = 0; i < NUM_CRS; i++) { regName[i + FIRST_CONDITION] = "C" + i; } regName[JTOC_POINTER.value()] = "JTOC"; regName[FRAME_POINTER.value()] = "FP"; regName[THREAD_REGISTER.value()] = "TR"; regName[XER] = "XER"; regName[LR] = "LR"; regName[CTR] = "CTR"; regName[TU] = "TU"; regName[TL] = "TL"; regName[CR] = "CR"; } static final int TEMP = FIRST_INT; // temporary register (currently r0) /** * @return R0, a temporary register */ public Register getTemp() { return reg[TEMP]; } /** * @param number a register number * @return the register name for a register with a particular number in the * pool */ public static String getName(int number) { return registerName[number]; } /** * Gets the required spill alignment for a register with a particular type * @param type one of INT_REG, DOUBLE_REG, CONDITION_REG, SPECIAL_REG * @return the alignment in bytes */ public static int getSpillAlignment(int type) { if (VM.VerifyAssertions) { VM._assert((type == INT_REG) || (type == DOUBLE_REG) || (type == CONDITION_REG) || (type == SPECIAL_REG)); } if (type == DOUBLE_REG) { return BYTES_IN_DOUBLE; } else { return BYTES_IN_ADDRESS; } } @Override public Enumeration<Register> enumerateAll() { return new PhysicalRegisterEnumeration(0, getSize() - 1); } @Override public Enumeration<Register> enumerateGPRs() { return new PhysicalRegisterEnumeration(FIRST_INT, FIRST_DOUBLE - 1); } @Override public Enumeration<Register> enumerateVolatileGPRs() { return new PhysicalRegisterEnumeration(FIRST_INT + FIRST_VOLATILE_GPR.value(), FIRST_INT + LAST_SCRATCH_GPR.value()); } static { // enumerateVolatileGPRs relies on volatiles & scratches being // contiguous; so let's make sure that is the case! if (VM.VerifyAssertions) { VM._assert(LAST_VOLATILE_GPR.value() + 1 == FIRST_SCRATCH_GPR.value()); } } /** * Enumerate the first n GPR parameters. * @param n count of GPR parameters to enumerate * @return enumeration of the first n GPR parameters */ public Enumeration<Register> enumerateGPRParameters(int n) { if (VM.VerifyAssertions) { VM._assert(n <= NUMBER_INT_PARAM); } return new PhysicalRegisterEnumeration(FIRST_INT_PARAM, FIRST_INT_PARAM + n - 1); } @Override public Enumeration<Register> enumerateNonvolatileGPRs() { return new PhysicalRegisterEnumeration(FIRST_INT + FIRST_NONVOLATILE_GPR.value(), FIRST_INT + LAST_NONVOLATILE_GPR.value()); } @Override public Enumeration<Register> enumerateNonvolatileGPRsBackwards() { return new ReverseEnumerator<Register>(enumerateNonvolatileGPRs()); } /** * Enumerates all the volatile FPRs in this set. * NOTE: This assumes the scratch FPRs are numbered immediately * <em> before</em> the volatile FPRs. * @return an enumeration containing all volatile FPRs in this set */ @Override public Enumeration<Register> enumerateVolatileFPRs() { return new PhysicalRegisterEnumeration(FIRST_DOUBLE + FIRST_SCRATCH_FPR.value(), FIRST_DOUBLE + LAST_VOLATILE_FPR.value()); } /** * Enumerates the first n FPR parameters. * @param n count of FPR parameters * @return an enumeration containing the firs n FPRs */ public Enumeration<Register> enumerateFPRParameters(int n) { if (VM.VerifyAssertions) { VM._assert(n <= NUMBER_DOUBLE_PARAM); } return new PhysicalRegisterEnumeration(FIRST_DOUBLE_PARAM, FIRST_DOUBLE_PARAM + n - 1); } @Override public Enumeration<Register> enumerateNonvolatileFPRs() { return new PhysicalRegisterEnumeration(FIRST_DOUBLE + FIRST_NONVOLATILE_FPR.value(), FIRST_DOUBLE + LAST_NONVOLATILE_FPR.value()); } /** * Enumerates the volatile physical condition registers. * Note that the TSR is non-volatile. * @return an enumeration of the volatile condition registers */ public Enumeration<Register> enumerateVolatileConditionRegisters() { return new Enumeration<Register>() { private int idx = 0; @Override public Register nextElement() { return reg[FIRST_CONDITION + CR_NUMS[idx++]]; } @Override public boolean hasMoreElements() { return idx < CR_NUMS.length; } }; } /** * Enumerates the non-volatile physical condition registers. * Note that only the TSR is non-volatile. * * @return an enumeration containing only TSR */ public Enumeration<Register> enumerateNonvolatileConditionRegisters() { return new PhysicalRegisterEnumeration(0, -1); } /** * Enumerate the volatile physical registers of a given class. * @param regClass one of INT_REG, DOUBLE_REG, CONDITION_REG * @return enumeration containing the physical registers of the * desired class */ @Override public Enumeration<Register> enumerateVolatiles(int regClass) { switch (regClass) { case INT_REG: return enumerateVolatileGPRs(); case DOUBLE_REG: return enumerateVolatileFPRs(); case CONDITION_REG: return enumerateVolatileConditionRegisters(); case SPECIAL_REG: return EmptyEnumeration.emptyEnumeration(); default: throw new OptimizingCompilerException("Unsupported volatile type"); } } @Override public Enumeration<Register> enumerateVolatiles() { Enumeration<Register> e1 = enumerateVolatileGPRs(); Enumeration<Register> e2 = enumerateVolatileFPRs(); Enumeration<Register> e3 = enumerateVolatileConditionRegisters(); return new CompoundEnumerator<Register>(e1, new CompoundEnumerator<Register>(e2, e3)); } /** * @return a set of all the volatile registers. */ public BitSet getVolatiles() { return volatileSet; } /** * Enumerate the nonvolatile physical registers of a given class. * @param regClass one of INT_REG, DOUBLE_REG, CONDITION_REG * @return the non-volatile physical registers of the given class */ public Enumeration<Register> enumerateNonvolatiles(int regClass) { switch (regClass) { case INT_REG: return enumerateNonvolatileGPRs(); case DOUBLE_REG: return enumerateNonvolatileFPRs(); case CONDITION_REG: return enumerateNonvolatileConditionRegisters(); case SPECIAL_REG: return EmptyEnumeration.emptyEnumeration(); default: throw new OptimizingCompilerException("Unsupported non-volatile type"); } } @Override public Enumeration<Register> enumerateNonvolatilesBackwards(int regClass) { return new ReverseEnumerator<Register>(enumerateNonvolatiles(regClass)); } /** * @param r a physical register * @return If the passed in physical register r is used as a GPR parameter register, * return the index into the GPR parameters for r. Otherwise, return -1; */ public int getGPRParamIndex(Register r) { if ((r.number < FIRST_INT_PARAM) || (r.number > LAST_VOLATILE_GPR.value())) { return -1; } else { return r.number - FIRST_INT_PARAM; } } /** * @param r a physical register * @return If the passed in physical register r is used as an FPR parameter register, * return the index into the FPR parameters for r. Otherwise, return -1; */ public int getFPRParamIndex(Register r) { if ((r.number < FIRST_DOUBLE_PARAM) || (r.number > LAST_VOLATILE_FPR.value())) { return -1; } else { return r.number - FIRST_DOUBLE_PARAM; } } /** * @param r a register * @return If r is used as the first half of a (long) register pair, return * the second half of the pair. */ public Register getSecondHalf(Register r) { int n = r.number; return get(n + 1); } /** * An enumerator for use by the physical register utilities. */ final class PhysicalRegisterEnumeration implements Enumeration<Register> { private final int end; private int index; PhysicalRegisterEnumeration(int start, int end) { this.end = end; this.index = start; } @Override public Register nextElement() { return reg[index++]; } @Override public boolean hasMoreElements() { return (index <= end); } } }