/*
* 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);
}
}
}