/* * 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.ia32; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.AF; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.C0; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.C1; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.C2; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.C3; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.CF; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.DOUBLE_REG; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.FIRST_DOUBLE; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.FIRST_INT; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.FIRST_SPECIAL; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.INT_REG; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.NUM_SPECIALS; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.OF; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.PF; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.SF; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.SPECIAL_REG; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.ST0; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.ST1; import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.ZF; import static org.jikesrvm.ia32.ArchConstants.SSE2_FULL; import static org.jikesrvm.ia32.RegisterConstants.EAX; import static org.jikesrvm.ia32.RegisterConstants.EBP; import static org.jikesrvm.ia32.RegisterConstants.EBX; import static org.jikesrvm.ia32.RegisterConstants.ECX; import static org.jikesrvm.ia32.RegisterConstants.EDI; import static org.jikesrvm.ia32.RegisterConstants.EDX; import static org.jikesrvm.ia32.RegisterConstants.ESI; import static org.jikesrvm.ia32.RegisterConstants.ESP; import static org.jikesrvm.ia32.RegisterConstants.JTOC_REGISTER; import static org.jikesrvm.ia32.RegisterConstants.NATIVE_PARAMETER_FPRS; import static org.jikesrvm.ia32.RegisterConstants.NATIVE_PARAMETER_GPRS; import static org.jikesrvm.ia32.RegisterConstants.NONVOLATILE_FPRS; import static org.jikesrvm.ia32.RegisterConstants.NONVOLATILE_GPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_FPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_GPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_NATIVE_PARAMETER_FPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_NATIVE_PARAMETER_GPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_NONVOLATILE_FPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_NONVOLATILE_GPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_PARAMETER_FPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_PARAMETER_GPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_RETURN_FPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_RETURN_GPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_VOLATILE_FPRS; import static org.jikesrvm.ia32.RegisterConstants.NUM_VOLATILE_GPRS; import static org.jikesrvm.ia32.RegisterConstants.THREAD_REGISTER; import static org.jikesrvm.ia32.RegisterConstants.VOLATILE_FPRS; import static org.jikesrvm.ia32.RegisterConstants.VOLATILE_GPRS; 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.ia32.RegisterConstants.FPR; import org.jikesrvm.ia32.RegisterConstants.FloatingPointMachineRegister; import org.jikesrvm.ia32.RegisterConstants.GPR; import org.jikesrvm.ia32.RegisterConstants.XMM; import org.jikesrvm.util.EmptyEnumeration; /** * This class represents a set of Registers corresponding to the * IA32 register set. */ public final class PhysicalRegisterSet extends GenericPhysicalRegisterSet { /** * This array holds a pool of objects representing physical registers */ private final Register[] reg = new Register[getSize()]; /** * Cache the set of volatile registers for efficiency */ private final BitSet volatileSet; /** * Cache the set of floating-point registers for efficiency */ private final BitSet fpSet; /** * @return the total number of physical registers. */ public static int getSize() { return NUM_GPRS + NUM_FPRS + 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 GPRs that may hold parameters. */ public static int getNumberOfGPRParams() { return NUM_PARAMETER_GPRS; } /** * @param n register index * @return the (zero-based indexed) nth native GPR that may hold a parameter. */ public Register getNativeGPRParam(int n) { return getGPR(NATIVE_PARAMETER_GPRS[n]); } /** * @return the total number of FPRs that may hold parameters. */ public static int getNumberOfFPRParams() { return NUM_PARAMETER_FPRS; } /** * @return the total number of native GPRs that may hold parameters. */ public static int getNumberOfNativeGPRParams() { return NUM_NATIVE_PARAMETER_GPRS; } /** * @return the total number of native FPRs that may hold parameters. */ public static int getNumberOfNativeFPRParams() { return NUM_NATIVE_PARAMETER_FPRS; } /** * @param n register index * @return the (zero-based indexed) nth GPR that may hold a parameter. */ public Register getGPRParam(int n) { if (VM.VerifyAssertions) VM._assert(n < 2); if (n == 0) { return getEAX(); } else { return getEDX(); } } /** * @param n register index * @return the (zero-based indexed) nth FPR that may hold a parameter. */ public Register getFPRParam(int n) { return getFPR(VOLATILE_FPRS[n]); } /** * @param n register index * @return the (zero-based indexed) nth native FPR that may hold a parameter. */ public Register getNativeFPRParam(int n) { return getFPR(NATIVE_PARAMETER_FPRS[n]); } /** * @param n register index * @return the (zero-based indexed) nth GPR that may hold a return value. */ public Register getReturnGPR(int n) { if (VM.VerifyAssertions) VM._assert(n < 2); if (n == 0) { return getEAX(); } else { return getEDX(); } } 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_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) } /** * @param r the register to check * @return {@code true} if and only if a particular register is subject to allocation */ @Override public boolean isAllocatable(Register r) { return (r.number < FIRST_SPECIAL && r != getTR() && r != getESP()); } /** * @return the processor register */ @Override public Register getTR() { return getGPR(THREAD_REGISTER); } /** * @return the frame pointer register */ @Override public Register getFP() { throw new OptimizingCompilerException("Framepointer is not a register on IA32"); } /** * @return the EAX register */ public Register getEAX() { return getGPR(EAX); } /** * @return the ECX register */ public Register getECX() { return getGPR(ECX); } /** * @return the EDX register */ public Register getEDX() { return getGPR(EDX); } /** * @return the EBX register */ public Register getEBX() { return getGPR(EBX); } /** * @return the ESP register */ public Register getESP() { return getGPR(ESP); } /** * @return the EBP register */ public Register getEBP() { return getGPR(EBP); } /** * @return the ESI register */ public Register getESI() { return getGPR(ESI); } /** * @return the EDI register */ public Register getEDI() { return getGPR(EDI); } /** * @return a register representing the AF bit of the EFLAGS register. */ public Register getAF() { return reg[AF]; } /** * @return a register representing the CF bit of the EFLAGS register. */ public Register getCF() { return reg[CF]; } /** * @return a register representing the OF bit of the EFLAGS register. */ public Register getOF() { return reg[OF]; } /** * @return a register representing the PF bit of the EFLAGS register. */ public Register getPF() { return reg[PF]; } /** * @return a register representing the SF bit of the EFLAGS register. */ public Register getSF() { return reg[SF]; } /** * @return a register representing the ZF bit of the EFLAGS register. */ public Register getZF() { return reg[ZF]; } /** * @return a register representing the C0 floating-point status bit */ public Register getC0() { return reg[C0]; } /** * @return a register representing the C1 floating-point status bit */ public Register getC1() { return reg[C1]; } /** * @return a register representing the C2 floating-point status bit */ public Register getC2() { return reg[C2]; } /** * @return a register representing the C3 floating-point status bit */ public Register getC3() { return reg[C3]; } public Register getJTOC() { if (JTOC_REGISTER == null) { final String JTOCwasntSet = "Attempt to get JTOC register when it wasn't defined!"; if (VM.VerifyAssertions) { VM._assert(VM.NOT_REACHED, JTOCwasntSet); } else { VM.sysFail(JTOCwasntSet); } } return getGPR(JTOC_REGISTER); } @Override public Register getGPR(MachineRegister n) { return reg[FIRST_INT + n.value()]; } @Override public Register getGPR(int n) { return reg[FIRST_INT + n]; } /** * @param r a physical GPR * @return the index into the GPR set corresponding to a given register. * * PRECONDITION: r is a physical GPR */ public static int getGPRIndex(Register r) { return r.number - FIRST_INT; } /** * @return the first GPR register used to hold a return value */ @Override public 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 Register getSecondReturnGPR() { if (VM.VerifyAssertions) VM._assert(NUM_RETURN_GPRS > 1); return getEDX(); } /** * @return the FPR register used to hold a return value */ public Register getST0() { if (VM.VerifyAssertions) VM._assert(NUM_RETURN_FPRS == 1); if (VM.VerifyAssertions) VM._assert(SSE2_FULL); return reg[ST0]; } /** * @return the special ST1 x87 register */ public Register getST1() { if (VM.VerifyAssertions) VM._assert(SSE2_FULL); return reg[ST1]; } /** * @return the FPR register used to hold a return value */ public Register getReturnFPR() { if (VM.VerifyAssertions) VM._assert(NUM_RETURN_FPRS == 1); return getFPR(0); } public Register getFPR(FloatingPointMachineRegister n) { return reg[FIRST_DOUBLE + n.value()]; } @Override public Register getFPR(int n) { return reg[FIRST_DOUBLE + n]; } /** * @param r a physical FPR * @return the index into the FPR set corresponding to a given register. * * PRECONDITION: r is a physical FPR */ public static int getFPRIndex(Register r) { return r.number - FIRST_DOUBLE; } @Override public 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(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); } } /** * Register names for each class. used in printing the IR */ private static final String[] registerName = new String[getSize()]; static { String[] regName = registerName; for (GPR r : GPR.values()) { regName[r.ordinal() + FIRST_INT] = r.toString(); } if (SSE2_FULL) { for (XMM r : XMM.values()) { regName[r.ordinal() + FIRST_DOUBLE] = r.toString(); } } else { for (FPR r : FPR.values()) { regName[r.ordinal() + FIRST_DOUBLE] = r.toString(); } } regName[THREAD_REGISTER.value()] = "TR"; regName[AF] = "AF"; regName[CF] = "CF"; regName[OF] = "OF"; regName[PF] = "PF"; regName[SF] = "SF"; regName[ZF] = "ZF"; regName[ST0] = "ST0"; regName[ST1] = "ST1"; } /** * Gets the register name for a register with a particular number in the * pool. * * @param number register number * @return register name */ public static String getName(int number) { return registerName[number]; } /** * @param type one of INT_REG, DOUBLE_REG, SPECIAL_REG * @return the required spill alignment for a register with the given type */ public static int getSpillAlignment(int type) { if (VM.VerifyAssertions) { VM._assert((type == INT_REG) || (type == DOUBLE_REG) || (type == SPECIAL_REG)); } if (VM.BuildFor32Addr) { if (type == DOUBLE_REG) { return 8; } else { return 4; } } else { return 8; } } @Override public Enumeration<Register> enumerateAll() { return new RangeEnumeration(0, getSize() - 1); } @Override public Enumeration<Register> enumerateGPRs() { return new RangeEnumeration(FIRST_INT, FIRST_DOUBLE - 1); } public Enumeration<Register> enumerateFPRs() { return new RangeEnumeration(FIRST_DOUBLE, FIRST_SPECIAL - 1); } @Override public PhysicalRegisterEnumeration enumerateVolatileGPRs() { Register[] r = new Register[NUM_VOLATILE_GPRS]; for (int i = 0; i < NUM_VOLATILE_GPRS; i++) { r[i] = getGPR(VOLATILE_GPRS[i]); } return new PhysicalRegisterEnumeration(r); } @Override public PhysicalRegisterEnumeration enumerateNonvolatileGPRs() { Register[] r = new Register[NUM_NONVOLATILE_GPRS]; for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) { r[i] = getGPR(NONVOLATILE_GPRS[i]); } return new PhysicalRegisterEnumeration(r); } @Override public Enumeration<Register> enumerateNonvolatileGPRsBackwards() { return new ReverseEnumerator<Register>(enumerateNonvolatileGPRs()); } @Override public PhysicalRegisterEnumeration enumerateVolatileFPRs() { Register[] r = new Register[NUM_VOLATILE_FPRS]; for (int i = 0; i < NUM_VOLATILE_FPRS; i++) { r[i] = getFPR(VOLATILE_FPRS[i]); } return new PhysicalRegisterEnumeration(r); } @Override public PhysicalRegisterEnumeration enumerateNonvolatileFPRs() { Register[] r = new Register[NUM_NONVOLATILE_FPRS]; for (int i = 0; i < NUM_NONVOLATILE_FPRS; i++) { r[i] = getFPR(NONVOLATILE_FPRS[i]); } return new PhysicalRegisterEnumeration(r); } @Override public Enumeration<Register> enumerateVolatiles(int regClass) { switch (regClass) { case INT_REG: return enumerateVolatileGPRs(); case DOUBLE_REG: return enumerateVolatileFPRs(); 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(); return new CompoundEnumerator<Register>(e1, e2); } /** * @return the set of volatile physical registers */ public BitSet getVolatiles() { return volatileSet; } /** * @return the set of FPR physical registers */ public BitSet getFPRs() { return fpSet; } public Enumeration<Register> enumerateNonvolatiles(int regClass) { switch (regClass) { case INT_REG: return enumerateNonvolatileGPRs(); case DOUBLE_REG: return enumerateNonvolatileFPRs(); 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)); } /** * An enumerator for use by the physical register utilities. */ static final class PhysicalRegisterEnumeration implements Enumeration<Register> { private int index; private final Register[] r; PhysicalRegisterEnumeration(Register[] r) { this.r = r; this.index = 0; } @Override public Register nextElement() { return r[index++]; } @Override public boolean hasMoreElements() { return (index < r.length); } } /** * An enumerator for use by the physical register utilities. */ final class RangeEnumeration implements Enumeration<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; } @Override public Register nextElement() { if (index == exclude) index++; return reg[index++]; } @Override public boolean hasMoreElements() { if (index == exclude) index++; return (index <= end); } } }