/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * 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/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.ir.ia32; import java.util.Enumeration; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.OPT_BitSet; import org.jikesrvm.compilers.opt.OPT_CompoundEnumerator; import org.jikesrvm.compilers.opt.OPT_EmptyEnumerator; import org.jikesrvm.compilers.opt.OPT_OptimizingCompilerException; import org.jikesrvm.compilers.opt.OPT_ReverseEnumerator; import org.jikesrvm.compilers.opt.ia32.OPT_PhysicalRegisterConstants; import org.jikesrvm.compilers.opt.ir.OPT_GenericPhysicalRegisterSet; import org.jikesrvm.compilers.opt.ir.OPT_Register; import org.jikesrvm.ia32.VM_ArchConstants; import org.jikesrvm.ia32.VM_RegisterConstants; /** * This class represents a set of OPT_Registers corresponding to the * IA32 register set. */ public abstract class OPT_PhysicalRegisterSet extends OPT_GenericPhysicalRegisterSet implements VM_RegisterConstants, OPT_PhysicalRegisterConstants { /** * This array holds a pool of objects representing physical registers */ private final OPT_Register[] reg = new OPT_Register[getSize()]; /** * Cache the set of volatile registers for efficiency */ private final OPT_BitSet volatileSet; /** * Cache the set of floating-point registers for efficiency */ private final OPT_BitSet fpSet; /** * Return the total number of physical registers. */ public static int getSize() { return NUM_GPRS + NUM_FPRS + 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 GPRs that may hold parameters. */ public static int getNumberOfGPRParams() { return NUM_PARAMETER_GPRS; } /** * Return the total number of FPRs that may hold parameters. */ public static int getNumberOfFPRParams() { return NUM_PARAMETER_FPRS; } /** * Return the (zero-based indexed) nth GPR that may hold a parameter. */ public final OPT_Register getGPRParam(int n) { if (VM.VerifyAssertions) VM._assert(n < 2); if (n == 0) { return getEAX(); } else { return getEDX(); } } /** * Return the (zero-based indexed) nth FPR that may hold a parameter. */ public final OPT_Register getFPRParam(int n) { return getFPR(VOLATILE_FPRS[n]); } /** * Return the (zero-based indexed) nth GPR that may hold a return value. */ public OPT_Register getReturnGPR(int n) { if (VM.VerifyAssertions) VM._assert(n < 2); if (n == 0) { return getEAX(); } else { return getEDX(); } } /** * Constructor: set up a pool of physical registers. */ protected OPT_PhysicalRegisterSet() { // 1. Create all the physical registers in the pool. for (int i = 0; i < reg.length; i++) { OPT_Register r = new OPT_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<OPT_Register> e = enumerateVolatileGPRs(); e.hasMoreElements();) { OPT_Register r = e.nextElement(); r.setVolatile(); } // 5. set up the non-volatile GPRs for (Enumeration<OPT_Register> e = enumerateNonvolatileGPRs(); e.hasMoreElements();) { OPT_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[PROCESSOR_REGISTER].setSpansBasicBlock(); // For SSE2 reg[ST0].setDouble(); reg[ST1].setDouble(); // 7. set up the volatile FPRs for (Enumeration<OPT_Register> e = enumerateVolatileFPRs(); e.hasMoreElements();) { OPT_Register r = e.nextElement(); r.setVolatile(); } // 8. set up the non-volatile FPRs for (Enumeration<OPT_Register> e = enumerateNonvolatileFPRs(); e.hasMoreElements();) { OPT_Register r = e.nextElement(); r.setNonVolatile(); } // 9. Cache the volatile registers for efficiency volatileSet = new OPT_BitSet(this); for (Enumeration<OPT_Register> e = enumerateVolatiles(); e.hasMoreElements();) { OPT_Register r = e.nextElement(); volatileSet.add(r); } // 10. Cache the FPRs for efficiency fpSet = new OPT_BitSet(this); for (Enumeration<OPT_Register> e = enumerateFPRs(); e.hasMoreElements();) { OPT_Register r = e.nextElement(); fpSet.add(r); } // Note no registers are excluded from live analysis (as is done for PPC) } /** * Is a particular register subject to allocation? */ public boolean isAllocatable(OPT_Register r) { return (r.number < FIRST_SPECIAL && r != getPR() && r != getESP()); } /** * @return the processor register */ public OPT_Register getPR() { return getGPR(PROCESSOR_REGISTER); } /** * @return the frame pointer register */ public OPT_Register getFP() { throw new OPT_OptimizingCompilerException("Framepointer is not a register on IA32"); } /** * @return the EAX register */ public OPT_Register getEAX() { return getGPR(EAX); } /** * @return the ECX register */ public OPT_Register getECX() { return getGPR(ECX); } /** * @return the EDX register */ public OPT_Register getEDX() { return getGPR(EDX); } /** * @return the EBX register */ public OPT_Register getEBX() { return getGPR(EBX); } /** * @return the ESP register */ public OPT_Register getESP() { return getGPR(ESP); } /** * @return the EBP register */ public OPT_Register getEBP() { return getGPR(EBP); } /** * @return the ESI register */ public OPT_Register getESI() { return getGPR(ESI); } /** * @return the EDI register */ public OPT_Register getEDI() { return getGPR(EDI); } /** * @return a register representing the AF bit of the EFLAGS register. */ public OPT_Register getAF() { return reg[AF]; } /** * @return a register representing the CF bit of the EFLAGS register. */ public OPT_Register getCF() { return reg[CF]; } /** * @return a register representing the OF bit of the EFLAGS register. */ public OPT_Register getOF() { return reg[OF]; } /** * @return a register representing the PF bit of the EFLAGS register. */ public OPT_Register getPF() { return reg[PF]; } /** * @return a register representing the SF bit of the EFLAGS register. */ public OPT_Register getSF() { return reg[SF]; } /** * @return a register representing the ZF bit of the EFLAGS register. */ public OPT_Register getZF() { return reg[ZF]; } /** * @return a register representing the C0 floating-point status bit */ public OPT_Register getC0() { return reg[C0]; } /** * @return a register representing the C1 floating-point status bit */ public OPT_Register getC1() { return reg[C1]; } /** * @return a register representing the C2 floating-point status bit */ public OPT_Register getC2() { return reg[C2]; } /** * @return a register representing the C3 floating-point status bit */ public OPT_Register getC3() { return reg[C3]; } /** * @return the nth physical GPR */ public OPT_Register getGPR(int n) { return reg[FIRST_INT + n]; } /** * @return the index into the GPR set corresponding to a given register. * * PRECONDITION: r is a physical GPR */ public static int getGPRIndex(OPT_Register r) { return r.number - FIRST_INT; } /** * @return the first GPR register used to hold a return value */ public OPT_Register getFirstReturnGPR() { if (VM.VerifyAssertions) VM._assert(NUM_RETURN_GPRS > 0); return getEAX(); } /** * @return the second GPR register used to hold a return value */ public OPT_Register getSecondReturnGPR() { if (VM.VerifyAssertions) VM._assert(NUM_RETURN_GPRS > 1); return getEDX(); } /** * @return the FPR register used to hold a return value */ public OPT_Register getST0() { if (VM.VerifyAssertions) VM._assert(NUM_RETURN_FPRS == 1); if (VM.VerifyAssertions) VM._assert(VM_ArchConstants.SSE2_FULL); return reg[ST0]; } /** * @return the special ST1 x87 register */ public OPT_Register getST1() { if (VM.VerifyAssertions) VM._assert(VM_ArchConstants.SSE2_FULL); return reg[ST1]; } /** * @return the FPR register used to hold a return value */ public OPT_Register getReturnFPR() { if (VM.VerifyAssertions) VM._assert(NUM_RETURN_FPRS == 1); return getFPR(0); } /** * @return the nth physical FPR */ public OPT_Register getFPR(int n) { return reg[FIRST_DOUBLE + n]; } /** * @return the index into the GPR set corresponding to a given register. * * PRECONDITION: r is a physical GPR */ public static int getFPRIndex(OPT_Register r) { return r.number - FIRST_DOUBLE; } /** * @return the nth physical register in the pool. */ public OPT_Register get(int n) { return reg[n]; } /** * 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(OPT_Register r) { if (r.isInteger() || r.isLong() || r.isAddress()) { return INT_REG; } else if (r.isFloatingPoint()) { return DOUBLE_REG; } else { throw new OPT_OptimizingCompilerException("getPhysicalRegisterType " + " unexpected " + r); } } /** * Register names for each class. used in printing the IR */ private static final String[] registerName = new String[getSize()]; static { String[] regName = registerName; for (int i = 0; i < NUM_GPRS; i++) { regName[i + FIRST_INT] = GPR_NAMES[i]; } for (int i = 0; i < NUM_FPRS; i++) { regName[i + FIRST_DOUBLE] = FPR_NAMES[i]; } regName[PROCESSOR_REGISTER] = "PR"; regName[AF] = "AF"; regName[CF] = "CF"; regName[OF] = "OF"; regName[PF] = "PF"; regName[SF] = "SF"; regName[ZF] = "ZF"; regName[ST0] = "ST0"; regName[ST1] = "ST1"; } /** * 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, SPECIAL_REG */ public static int getSpillSize(int type) { if (VM.VerifyAssertions) { VM._assert((type == INT_REG) || (type == DOUBLE_REG) || (type == SPECIAL_REG)); } if (type == DOUBLE_REG) { return 8; } else { return 4; } } /** * Get the required spill alignment for a register with a particular type * @param type one of INT_REG, DOUBLE_REG, SPECIAL_REG */ public static int getSpillAlignment(int type) { if (VM.VerifyAssertions) { VM._assert((type == INT_REG) || (type == DOUBLE_REG) || (type == SPECIAL_REG)); } if (type == DOUBLE_REG) { return 8; } else { return 4; } } /** * Enumerate all the physical registers in this set. */ public Enumeration<OPT_Register> enumerateAll() { return new RangeEnumeration(0, getSize() - 1); } /** * Enumerate all the GPRs in this set. */ public Enumeration<OPT_Register> enumerateGPRs() { return new RangeEnumeration(FIRST_INT, FIRST_DOUBLE - 1); } /** * Enumerate all the GPRs in this set. */ public Enumeration<OPT_Register> enumerateFPRs() { return new RangeEnumeration(FIRST_DOUBLE, FIRST_SPECIAL - 1); } /** * Enumerate all the volatile GPRs in this set. */ public PhysicalRegisterEnumeration enumerateVolatileGPRs() { OPT_Register[] r = new OPT_Register[NUM_VOLATILE_GPRS]; for (int i = 0; i < NUM_VOLATILE_GPRS; i++) { r[i] = getGPR(VOLATILE_GPRS[i]); } return new PhysicalRegisterEnumeration(r); } /** * Enumerate all the nonvolatile GPRs in this set. */ public PhysicalRegisterEnumeration enumerateNonvolatileGPRs() { OPT_Register[] r = new OPT_Register[NUM_NONVOLATILE_GPRS]; for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) { r[i] = getGPR(NONVOLATILE_GPRS[i]); } return new PhysicalRegisterEnumeration(r); } /** * Enumerate the nonvolatile GPRS backwards */ public Enumeration<OPT_Register> enumerateNonvolatileGPRsBackwards() { return new OPT_ReverseEnumerator<OPT_Register>(enumerateNonvolatileGPRs()); } /** * Enumerate all the volatile FPRs in this set. */ public PhysicalRegisterEnumeration enumerateVolatileFPRs() { OPT_Register[] r = new OPT_Register[NUM_VOLATILE_FPRS]; for (int i = 0; i < NUM_VOLATILE_FPRS; i++) { r[i] = getFPR(VOLATILE_FPRS[i]); } return new PhysicalRegisterEnumeration(r); } /** * Enumerate all the nonvolatile FPRs in this set. */ public PhysicalRegisterEnumeration enumerateNonvolatileFPRs() { OPT_Register[] r = new OPT_Register[NUM_NONVOLATILE_FPRS]; for (int i = 0; i < NUM_NONVOLATILE_FPRS; i++) { r[i] = getFPR(NONVOLATILE_FPRS[i]); } return new PhysicalRegisterEnumeration(r); } /** * Enumerate the volatile physical registers of a given class. * @param regClass one of INT_REG, DOUBLE_REG, SPECIAL_REG */ public Enumeration<OPT_Register> enumerateVolatiles(int regClass) { switch (regClass) { case INT_REG: return enumerateVolatileGPRs(); case DOUBLE_REG: return enumerateVolatileFPRs(); case SPECIAL_REG: return OPT_EmptyEnumerator.emptyEnumeration(); default: throw new OPT_OptimizingCompilerException("Unsupported volatile type"); } } /** * Enumerate all the volatile physical registers */ public Enumeration<OPT_Register> enumerateVolatiles() { Enumeration<OPT_Register> e1 = enumerateVolatileGPRs(); Enumeration<OPT_Register> e2 = enumerateVolatileFPRs(); return new OPT_CompoundEnumerator<OPT_Register>(e1, e2); } /** * @return the set of volatile physical registers */ public OPT_BitSet getVolatiles() { return volatileSet; } /** * @return the set of FPR physical registers */ public OPT_BitSet getFPRs() { return fpSet; } /** * Enumerate the nonvolatile physical registers of a given class. * @param regClass one of INT_REG, DOUBLE_REG, SPECIAL_REG */ public Enumeration<OPT_Register> enumerateNonvolatiles(int regClass) { switch (regClass) { case INT_REG: return enumerateNonvolatileGPRs(); case DOUBLE_REG: return enumerateNonvolatileFPRs(); case SPECIAL_REG: return OPT_EmptyEnumerator.emptyEnumeration(); default: throw new OPT_OptimizingCompilerException("Unsupported non-volatile type"); } } /** * Enumerate the nonvolatile physical registers of a given class, * backwards * @param regClass one of INT_REG, DOUBLE_REG, SPECIAL_REG */ public Enumeration<OPT_Register> enumerateNonvolatilesBackwards(int regClass) { return new OPT_ReverseEnumerator<OPT_Register>(enumerateNonvolatiles(regClass)); } /** * An enumerator for use by the physical register utilities. */ static final class PhysicalRegisterEnumeration implements Enumeration<OPT_Register> { private int index; private final OPT_Register[] r; PhysicalRegisterEnumeration(OPT_Register[] r) { this.r = r; this.index = 0; } public OPT_Register nextElement() { return r[index++]; } public boolean hasMoreElements() { return (index < r.length); } } /** * An enumerator for use by the physical register utilities. */ final class RangeEnumeration implements Enumeration<OPT_Register> { private final int end; private int index; private final int exclude; // an index in the register range to exclude RangeEnumeration(int start, int end) { this.end = end; this.exclude = -1; this.index = start; } RangeEnumeration(int start, int end, int exclude) { this.end = end; this.exclude = exclude; this.index = start; } public OPT_Register nextElement() { if (index == exclude) index++; return reg[index++]; } public boolean hasMoreElements() { if (index == exclude) index++; return (index <= end); } } }