/* * 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 java.util.Enumeration; import org.jikesrvm.VM; 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.regalloc.ppc.PhysicalRegisterConstants; import org.jikesrvm.compilers.opt.util.BitSet; import org.jikesrvm.compilers.opt.util.CompoundEnumerator; import org.jikesrvm.compilers.opt.util.EmptyEnumerator; import org.jikesrvm.compilers.opt.util.ReverseEnumerator; import org.jikesrvm.ppc.RegisterConstants; /** * This class represents a set of Registers corresponding to the * PowerPC register set. * * <P> Implementation Notes: * <P> Due to some historical ugliness not yet cleaned up, the register * allocator depend on properties cached in the * <code>next</code> field of Register. The constructor sets the * following properties: * <ul> * <li> The volatile GPRs form a linked list, starting with * FIRST_VOLATILE_GPR and ending with LAST_SCRATCH_GPR * <li> The volatile FPRs form a linked list, starting with * FIRST_VOLATILE_FPR and ending with LAST_SCRATCH_FPR * <li> The non-volatile GPRs form a linked list, starting with * FIRST_NONVOLATILE_GPR and ending with LAST_NONVOLATILE_GPR * <li> The non-volatile FPRs form a linked list, starting with * FIRST_NONVOLATILE_FPR and ending with LAST_NONVOLATILE_FPR * <li> The condition registers from a linked list, starting with * FIRST_CONDITION and ending with LAST_CONDITION-1, which opt reserves for yieldpoints. * </ul> * <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 abstract class PhysicalRegisterSet extends GenericPhysicalRegisterSet implements RegisterConstants, PhysicalRegisterConstants { /** * This array holds a pool of objects representing physical registers */ private Register[] reg = new Register[getSize()]; /** * The set of volatile registers; cached for efficiency */ private 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 AIX 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; } /** * Return the total number of physical registers. */ public final 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' 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; i < LAST_VOLATILE_GPR; i++) { Register r = reg[i]; r.setVolatile(); r.linkWithNext(reg[i + 1]); } reg[LAST_VOLATILE_GPR].setVolatile(); reg[LAST_VOLATILE_GPR].linkWithNext(reg[FIRST_SCRATCH_GPR]); for (int i = FIRST_SCRATCH_GPR; i < LAST_SCRATCH_GPR; i++) { Register r = reg[i]; r.setVolatile(); r.linkWithNext(reg[i + 1]); } reg[LAST_SCRATCH_GPR].setVolatile(); // 6. set up the non-volatile GPRs for (int i = FIRST_NONVOLATILE_GPR; i < LAST_NONVOLATILE_GPR; i++) { Register r = reg[i]; r.setNonVolatile(); r.linkWithNext(reg[i + 1]); } // 7. set properties on some special registers reg[THREAD_REGISTER].setSpansBasicBlock(); reg[FRAME_POINTER].setSpansBasicBlock(); reg[JTOC_POINTER].setSpansBasicBlock(); // 8. set up the volatile FPRs for (int i = FIRST_DOUBLE + FIRST_VOLATILE_FPR; i < FIRST_DOUBLE + LAST_VOLATILE_FPR; i++) { Register r = reg[i]; r.setVolatile(); r.linkWithNext(reg[i + 1]); } reg[FIRST_DOUBLE + LAST_VOLATILE_FPR].linkWithNext(reg[FIRST_DOUBLE + FIRST_SCRATCH_FPR]); reg[FIRST_DOUBLE + LAST_VOLATILE_FPR].setVolatile(); if (FIRST_SCRATCH_FPR != LAST_SCRATCH_FPR) { for (int i = FIRST_DOUBLE + FIRST_SCRATCH_FPR; i < FIRST_DOUBLE + LAST_SCRATCH_FPR; i++) { Register r = reg[i]; r.setVolatile(); r.linkWithNext(reg[i + 1]); } } reg[FIRST_DOUBLE + LAST_SCRATCH_FPR].setVolatile(); // 9. set up the non-volatile FPRs for (int i = FIRST_DOUBLE + FIRST_NONVOLATILE_FPR; i < FIRST_DOUBLE + LAST_NONVOLATILE_FPR; i++) { Register r = reg[i]; r.setNonVolatile(); r.linkWithNext(reg[i + 1]); } // 10. set up the condition registers int firstCR = -1; int prevCR = -1; for (int i : CR_NUMS) { reg[FIRST_CONDITION + i].setVolatile(); if (prevCR != -1) { reg[FIRST_CONDITION + prevCR].linkWithNext(reg[FIRST_CONDITION + i]); } prevCR = i; if (firstCR == -1) { firstCR = i; } } // 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].setExcludedLiveA(); reg[JTOC_POINTER].setExcludedLiveA(); reg[LR].setExcludedLiveA(); } /** * Is a certain physical register allocatable? */ public boolean isAllocatable(Register r) { switch (r.number) { case THREAD_REGISTER: case FRAME_POINTER: case JTOC_POINTER: return false; default: 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]; } /** * @return the FP registers */ public Register getFP() { return reg[FRAME_POINTER]; } /** * @return the thread register */ public Register getTR() { return reg[THREAD_REGISTER]; } /** * @return the thread-switch register */ public Register getTSR() { return reg[FIRST_CONDITION + TSR_REG]; } /** * @return the nth physical GPR */ public Register getGPR(int n) { return reg[FIRST_INT + n]; } /** * @return the first scratch GPR */ public Register getFirstScratchGPR() { return reg[FIRST_SCRATCH_GPR]; } /** * @return the last scratch GPR */ public Register getLastScratchGPR() { return reg[LAST_SCRATCH_GPR]; } /** * @return the first volatile GPR */ public Register getFirstVolatileGPR() { return reg[FIRST_INT + FIRST_VOLATILE_GPR]; } /** * @return the first nonvolatile GPR */ public Register getFirstNonvolatileGPR() { return reg[FIRST_INT + FIRST_NONVOLATILE_GPR]; } /** * @return the last nonvolatile GPR */ public Register getLastNonvolatileGPR() { return reg[FIRST_INT + LAST_NONVOLATILE_GPR]; } /** * @return the first GPR return */ public Register getFirstReturnGPR() { return reg[FIRST_INT_RETURN]; } /** * @return the nth physical FPR */ 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]; } /** * @return the first volatile FPR */ public Register getFirstVolatileFPR() { return reg[FIRST_DOUBLE + FIRST_VOLATILE_FPR]; } /** * @return the last scratch FPR */ public Register getLastScratchFPR() { return reg[FIRST_DOUBLE + LAST_SCRATCH_FPR]; } /** * @return the first nonvolatile FPR */ public Register getFirstNonvolatileFPR() { return reg[FIRST_DOUBLE + FIRST_NONVOLATILE_FPR]; } /** * @return the last nonvolatile FPR */ public Register getLastNonvolatileFPR() { return reg[FIRST_DOUBLE + LAST_NONVOLATILE_FPR]; } /** * @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(); } /** * @return the nth physical register in the pool. */ 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 */ public final 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] = "JTOC"; regName[FRAME_POINTER] = "FP"; regName[THREAD_REGISTER] = "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]; } /** * Get the register name for a register with a particular number in the * pool */ public static String getName(int number) { return registerName[number]; } /** * Get the spill size for a register with a particular type * @param type one of INT_REG, DOUBLE_REG, CONDITION_REG, SPECIAL_REG */ public static int getSpillSize(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; } } /** * Get the required spill alignment for a register with a particular type * @param type one of INT_REG, DOUBLE_REG, CONDITION_REG, SPECIAL_REG */ 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; } } /** * Enumerate all the physical registers in this set. */ public Enumeration<Register> enumerateAll() { return new PhysicalRegisterEnumeration(0, getSize() - 1); } /** * Enumerate all the GPRs in this set. */ public Enumeration<Register> enumerateGPRs() { return new PhysicalRegisterEnumeration(FIRST_INT, FIRST_DOUBLE - 1); } /** * Enumerate all the volatile GPRs in this set. * NOTE: This assumes the scratch GPRs are numbered immediately * <em> after </em> the volatile GPRs */ public Enumeration<Register> enumerateVolatileGPRs() { return new PhysicalRegisterEnumeration(FIRST_INT + FIRST_VOLATILE_GPR, FIRST_INT + LAST_SCRATCH_GPR); } 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 + 1 == FIRST_SCRATCH_GPR); } } /** * Enumerate 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); } /** * Enumerate all the nonvolatile GPRs in this set. */ public Enumeration<Register> enumerateNonvolatileGPRs() { return new PhysicalRegisterEnumeration(FIRST_INT + FIRST_NONVOLATILE_GPR, FIRST_INT + LAST_NONVOLATILE_GPR); } /** * Enumerate the nonvolatile GPRs backwards. */ public Enumeration<Register> enumerateNonvolatileGPRsBackwards() { return new ReverseEnumerator<Register>(enumerateNonvolatileGPRs()); } /** * Enumerate all the volatile FPRs in this set. * NOTE: This assumes the scratch FPRs are numbered immediately * <em> before</em> the volatile FPRs */ public Enumeration<Register> enumerateVolatileFPRs() { return new PhysicalRegisterEnumeration(FIRST_DOUBLE + FIRST_SCRATCH_FPR, FIRST_DOUBLE + LAST_VOLATILE_FPR); } /** * Enumerate the first n FPR parameters. */ 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); } /** * Enumerate all the nonvolatile FPRs in this set. */ public Enumeration<Register> enumerateNonvolatileFPRs() { return new PhysicalRegisterEnumeration(FIRST_DOUBLE + FIRST_NONVOLATILE_FPR, FIRST_DOUBLE + LAST_NONVOLATILE_FPR); } /** * Enumerate the volatile physical condition registers. * Note that the TSR is non-volatile. */ public Enumeration<Register> enumerateVolatileConditionRegisters() { return new Enumeration<Register>() { private int idx = 0; public Register nextElement() { return reg[FIRST_CONDITION + CR_NUMS[idx++]]; } public boolean hasMoreElements() { return idx < CR_NUMS.length; } }; } /** * Enumerate the non-volatile physical condition registers. * Note that only the TSR is non-volatile. */ 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 */ 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 EmptyEnumerator.emptyEnumeration(); default: throw new OptimizingCompilerException("Unsupported volatile type"); } } /** * Enumerate all the volatile physical registers */ 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 */ 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 EmptyEnumerator.emptyEnumeration(); default: throw new OptimizingCompilerException("Unsupported non-volatile type"); } } /** * Enumerate the nonvolatile physical registers of a given class, * backwards. */ public Enumeration<Register> enumerateNonvolatilesBackwards(int regClass) { return new ReverseEnumerator<Register>(enumerateNonvolatiles(regClass)); } /** * 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)) { return -1; } else { return r.number - FIRST_INT_PARAM; } } /** * 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)) { return -1; } else { return r.number - FIRST_DOUBLE_PARAM; } } /** * 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 int end; private int index; PhysicalRegisterEnumeration(int start, int end) { this.end = end; this.index = start; } public Register nextElement() { return reg[index++]; } public boolean hasMoreElements() { return (index <= end); } } }