/*
* 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.ia32;
import static org.jikesrvm.util.Bits.*;
import org.vmmagic.pragma.Pure;
import org.vmmagic.pragma.UninterruptibleNoWarn;
import org.jikesrvm.VM;
import org.jikesrvm.architecture.MachineRegister;
import org.jikesrvm.runtime.Magic;
public final class RegisterConstants {
//---------------------------------------------------------------------------------------//
// RVM register usage conventions - Intel version. //
//---------------------------------------------------------------------------------------//
/** log2 of instruction width in bytes */
public static final byte LG_INSTRUCTION_WIDTH = 0;
public static final int INSTRUCTION_WIDTH = 1 << LG_INSTRUCTION_WIDTH;
/**
* Common interface implemented by all registers constants
*/
public interface IntelMachineRegister extends MachineRegister {
byte value();
/** @return does this register require a REX prefix byte? */
boolean needsREXprefix();
}
/**
* Super interface for floating point registers
*/
public interface FloatingPointMachineRegister extends IntelMachineRegister {
}
/**
* Representation of general purpose registers
*/
public enum GPR implements IntelMachineRegister {
EAX(0), ECX(1), EDX(2), EBX(3), ESP(4), EBP(5), ESI(6), EDI(7),
R8(8), R9(9), R10(10), R11(11), R12(12), R13(13), R14(14), R15(15),
EIP(16);
/** Local copy of the backing array. Copied here to avoid calls to clone */
private static final GPR[] vals = values();
GPR(int v) {
if (v != ordinal()) {
throw new Error("Invalid register ordinal");
}
}
@Override
@UninterruptibleNoWarn("Interruptible code only called during boot image creation")
@Pure
public byte value() {
byte result;
if (!org.jikesrvm.VM.runningVM) {
result = (byte)ordinal();
} else {
result = (byte)java.lang.JikesRVMSupport.getEnumOrdinal(this);
}
if (VM.VerifyAssertions) {
if (VM.buildFor32Addr()) {
VM._assert(result >= 0 && result <= 7);
} else {
VM._assert(result >= 0 && result <= 15);
}
}
return result;
}
/** @return encoded value of this register to be included in the opcode byte */
@Pure
public byte valueForOpcode() {
byte result;
if (!org.jikesrvm.VM.runningVM) {
result = (byte)ordinal();
} else {
result = (byte)java.lang.JikesRVMSupport.getEnumOrdinal(this);
}
if (!VM.buildFor32Addr()) {
result &= 0x7;
}
if (VM.VerifyAssertions) {
VM._assert(result >= 0 && result <= 7);
}
return result;
}
@Override
@Pure
public boolean needsREXprefix() {
if (VM.buildFor32Addr()) {
return false;
} else {
return (this != EIP) && (value() > 7);
}
}
/**
* Intel have two flavours of 8bit opcodes, ones that operate on 32bit
* registers and ones that operate on 8bit registers. As the high half of
* 8bit registers doesn't allow ESI, EDI, EBP, ESP to be encoded, this
* routine returns true if this register is one of those unencodable
* registers.
* @return can this register be encoded as an 8byte register?
*/
@Pure
public boolean isValidAs8bitRegister() {
byte v = value();
return (v < 4) || (!VM.buildFor32Addr() && v > 7);
}
/**
* Convert encoded value into the GPR it represents
* @param num encoded value
* @return represented GPR
*/
@Pure
public static GPR lookup(int num) {
return vals[num];
}
/**
* Convert encoded value representing an opcode into the GPR to represent it
* @param opcode encoded value
* @return represented GPR
*/
public static GPR getForOpcode(int opcode) {
if (VM.VerifyAssertions) VM._assert(opcode >= 0 && opcode <= 7);
return lookup(opcode);
}
}
/**
* Representation of x87 floating point registers
*/
public enum FPR implements FloatingPointMachineRegister {
FP0(0), FP1(1), FP2(2), FP3(3), FP4(4), FP5(5), FP6(6), FP7(7);
/** Local copy of the backing array. Copied here to avoid calls to clone */
private static final FPR[] vals = values();
FPR(int v) {
if (v != ordinal()) {
throw new Error("Invalid register ordinal");
}
}
@Override
@Pure
public byte value() {
return (byte)ordinal();
}
@Override
@Pure
public boolean needsREXprefix() {
return false; // do REX prefixes of floating point operands make sense?
}
/**
* Convert encoded value into the FPR it represents
* @param num encoded value
* @return represented FPR
*/
@Pure
public static FPR lookup(int num) {
return vals[num];
}
}
/**
* Representation of MMX MM registers
* N.B. MM and x87 FPR registers alias
*/
public enum MM implements IntelMachineRegister {
MM0(0), MM1(1), MM2(2), MM3(3), MM4(4), MM5(5), MM6(6), MM7(7),
MM8(8), MM9(9), MM10(10), MM11(11), MM12(12), MM13(13), MM14(14), MM15(15);
/** Local copy of the backing array. Copied here to avoid calls to clone */
private static final MM[] vals = values();
MM(int v) {
if (v != ordinal()) {
throw new Error("Invalid register ordinal");
}
}
@Override
@Pure
public byte value() {
return (byte)ordinal();
}
@Override
@Pure
public boolean needsREXprefix() {
if (VM.buildFor32Addr()) {
return false;
} else {
return value() > 7;
}
}
/**
* Convert encoded value into the MM it represents
* @param num encoded value
* @return represented MM
*/
@Pure
public static MM lookup(int num) {
return vals[num];
}
}
/**
* Representation of SSE XMM registers
*/
public enum XMM implements FloatingPointMachineRegister {
XMM0(0), XMM1(1), XMM2(2), XMM3(3), XMM4(4), XMM5(5), XMM6(6), XMM7(7),
XMM8(8), XMM9(9), XMM10(10), XMM11(11), XMM12(12), XMM13(13), XMM14(14), XMM15(15);
/** Local copy of the backing array. Copied here to avoid calls to clone */
private static final XMM[] vals = values();
XMM(int v) {
if (v != ordinal()) {
throw new Error("Invalid register ordinal");
}
}
@Override
@Pure
public byte value() {
return (byte)ordinal();
}
@Override
@Pure
public boolean needsREXprefix() {
if (VM.buildFor32Addr()) {
return false;
} else {
return value() > 7;
}
}
/**
* Convert encoded value into the XMM it represents
* @param num encoded value
* @return represented XMM
*/
@Pure
public static XMM lookup(int num) {
return vals[num];
}
}
/*
* Symbolic values for general purpose registers.
* These values are used to assemble instructions and as indices into:
* Registers.gprs[]
* Registers.fprs[]
* GCMapIterator.registerLocations[]
* RegisterConstants.GPR_NAMES[]
*/
public static final GPR EAX = GPR.EAX;
public static final GPR ECX = GPR.ECX;
public static final GPR EDX = GPR.EDX;
public static final GPR EBX = GPR.EBX;
public static final GPR ESP = GPR.ESP;
public static final GPR EBP = GPR.EBP;
public static final GPR ESI = GPR.ESI;
public static final GPR EDI = GPR.EDI;
public static final GPR R0 = GPR.EAX;
public static final GPR R1 = GPR.ECX;
public static final GPR R2 = GPR.EDX;
public static final GPR R3 = GPR.EBX;
public static final GPR R4 = GPR.ESP;
public static final GPR R5 = GPR.EBP;
public static final GPR R6 = GPR.ESI;
public static final GPR R7 = GPR.EDI;
public static final GPR R8 = GPR.R8;
public static final GPR R9 = GPR.R9;
public static final GPR R10 = GPR.R10;
public static final GPR R11 = GPR.R11;
public static final GPR R12 = GPR.R12;
public static final GPR R13 = GPR.R13;
public static final GPR R14 = GPR.R14;
public static final GPR R15 = GPR.R15;
public static final FPR FP0 = FPR.FP0;
public static final FPR FP1 = FPR.FP1;
public static final FPR FP2 = FPR.FP2;
public static final FPR FP3 = FPR.FP3;
public static final FPR FP4 = FPR.FP4;
public static final FPR FP5 = FPR.FP5;
public static final FPR FP6 = FPR.FP6;
public static final FPR FP7 = FPR.FP7;
public static final MM MM0 = MM.MM0;
public static final MM MM1 = MM.MM1;
public static final MM MM2 = MM.MM2;
public static final MM MM3 = MM.MM3;
public static final MM MM4 = MM.MM4;
public static final MM MM5 = MM.MM5;
public static final MM MM6 = MM.MM6;
public static final MM MM7 = MM.MM7;
public static final MM MM8 = MM.MM8;
public static final MM MM9 = MM.MM9;
public static final MM MM10 = MM.MM10;
public static final MM MM11 = MM.MM11;
public static final MM MM12 = MM.MM12;
public static final MM MM13 = MM.MM13;
public static final MM MM14 = MM.MM14;
public static final MM MM15 = MM.MM15;
public static final XMM XMM0 = XMM.XMM0;
public static final XMM XMM1 = XMM.XMM1;
public static final XMM XMM2 = XMM.XMM2;
public static final XMM XMM3 = XMM.XMM3;
public static final XMM XMM4 = XMM.XMM4;
public static final XMM XMM5 = XMM.XMM5;
public static final XMM XMM6 = XMM.XMM6;
public static final XMM XMM7 = XMM.XMM7;
public static final XMM XMM8 = XMM.XMM8;
public static final XMM XMM9 = XMM.XMM9;
public static final XMM XMM10 = XMM.XMM10;
public static final XMM XMM11 = XMM.XMM11;
public static final XMM XMM12 = XMM.XMM12;
public static final XMM XMM13 = XMM.XMM13;
public static final XMM XMM14 = XMM.XMM14;
public static final XMM XMM15 = XMM.XMM15;
/*
* Dedicated registers.
*/
/** Register current stack pointer. NB the frame pointer is maintained in the processor. */
public static final GPR STACK_POINTER = ESP;
/** Register holding a reference to thread local information */
public static final GPR THREAD_REGISTER = ESI;
/** Register holding the value of the JTOC, only necessary when we can't directly address the JTOC */
public static final GPR JTOC_REGISTER = (VM.buildFor32Addr() || VM.runningTool ||
fits(Magic.getTocPointer(), 32)) ? null : R15;
/*
* Register sets
* (``range'' is a misnomer for the alphabet soup of of intel registers)
*/
// CHECKSTYLE:OFF
/** All general purpose registers */
public static final GPR[] ALL_GPRS =
VM.buildFor32Addr() ? new GPR[]{EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI}
: new GPR[]{EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, R8, R9, R10, R11, R12, R13, R14, R15};
/** Number of general purpose registers */
public static final byte NUM_GPRS = (byte)ALL_GPRS.length;
/**
* All floating point purpose registers
* NB with SSE x87 registers must be explicitly managed
*/
public static final FloatingPointMachineRegister[] ALL_FPRS =
VM.buildFor32Addr() ? (VM.buildForSSE2() ? new FPR[]{FP0, FP1, FP2, FP3, FP4, FP5, FP6, FP7}
: new XMM[]{XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7})
: new XMM[]{XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15};
/** Number of floating point registers */
public static final byte NUM_FPRS = (byte)ALL_FPRS.length;
/**
* Volatile general purpose registers.
* NB: the order here is important. The opt-compiler allocates
* the volatile registers in the order they appear here.
*/
public static final GPR[] VOLATILE_GPRS = VM.buildFor32Addr() ? new GPR[]{R0 /*EAX*/, R2 /*EDX*/, R1 /*ECX*/} : new GPR[]{R0, R2, R1, R8, R9, R10, R11, R14};
public static final int NUM_VOLATILE_GPRS = VOLATILE_GPRS.length;
/**
* Volatile floating point registers within the RVM.
* TODO: this should include XMMs
*/
public static final FloatingPointMachineRegister[] VOLATILE_FPRS = {FP0, FP1, FP2, FP3, FP4, FP5, FP6, FP7};
/** Number of volatile FPRs */
public static final int NUM_VOLATILE_FPRS = VOLATILE_FPRS.length;
/**
* Non-volatile general purpose registers within the RVM.
* Note: the order here is very important. The opt-compiler allocates
* the nonvolatile registers in the reverse of order they appear here.
* R3 (EBX) must be last, because it is the only non-volatile that can
* be used in instructions that are using r8 and we must ensure that
* opt doesn't skip over another nonvol while looking for an r8 nonvol.
*/
public static final GPR[] NONVOLATILE_GPRS =
VM.buildFor32Addr() ? new GPR[]{R5 /*EBP*/, R7 /*EDI*/, R3 /*EBX*/}
: new GPR[]{R5, R7, R3};
/** Number of non-volatile GPRs */
public static final int NUM_NONVOLATILE_GPRS = NONVOLATILE_GPRS.length;
/** Non-volatile floating point registers within the RVM. */
public static final FloatingPointMachineRegister[] NONVOLATILE_FPRS = {};
/** Number of non-volatile FPRs */
public static final int NUM_NONVOLATILE_FPRS = NONVOLATILE_FPRS.length;
/** General purpose registers to pass arguments within the RVM */
public static final GPR[] PARAMETER_GPRS = new GPR[]{EAX, EDX};
/** Number of parameter GPRs */
public static final int NUM_PARAMETER_GPRS = PARAMETER_GPRS.length;
/** Floating point registers to pass arguments within the RVM */
public static final FloatingPointMachineRegister[] PARAMETER_FPRS =
VM.buildForSSE2() ? new XMM[]{XMM0, XMM1, XMM2, XMM3}
: new FPR[]{FP0, FP1, FP2, FP3};
/** Number of parameter FPRs */
public static final int NUM_PARAMETER_FPRS = PARAMETER_FPRS.length;
/** GPR registers used for returning values */
public static final GPR[] RETURN_GPRS = VM.buildFor32Addr() ? new GPR[]{EAX, EDX} : new GPR[]{EAX};
/** Number of return GPRs */
public static final int NUM_RETURN_GPRS = RETURN_GPRS.length;
/** FPR registers used for returning values */
public static final FloatingPointMachineRegister[] RETURN_FPRS =
VM.buildForSSE2() ? new XMM[]{XMM0} : new FPR[]{FP0};
/** Number of return FPRs */
public static final int NUM_RETURN_FPRS = RETURN_FPRS.length;
/** Native volatile GPRS */
public static final GPR[] NATIVE_VOLATILE_GPRS = VM.buildFor32Addr() ? new GPR[]{EAX, ECX, EDX} : new GPR[]{EAX, ECX, EDX, ESI, EDI, R8, R9, R10, R11};
/** Native non-volatile GPRS */
public static final GPR[] NATIVE_NONVOLATILE_GPRS = VM.buildFor32Addr() ? new GPR[]{EBX, EBP, EDI, ESI} : new GPR[]{EBX, EBP, R12, R13, R14, R15};
/** Native volatile FPRS */
public static final FloatingPointMachineRegister[] NATIVE_VOLATILE_FPRS = ALL_FPRS;
/** Native non-volatile FPRS */
public static final FloatingPointMachineRegister[] NATIVE_NONVOLATILE_FPRS = new FloatingPointMachineRegister[0];
/** General purpose registers to pass arguments to native code */
public static final GPR[] NATIVE_PARAMETER_GPRS =
VM.buildFor32Addr() ? new GPR[0]
: new GPR[]{EDI /*R7*/, ESI /*R6*/, EDX /*R2*/, ECX /*R1*/, R8, R9};
/** Floating point registers to pass arguments to native code */
public static final FloatingPointMachineRegister[] NATIVE_PARAMETER_FPRS =
VM.buildFor32Addr() ? new FloatingPointMachineRegister[0]
: new XMM[]{XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7};
/** Number of native,sys parameter FPRs */
public static final int NUM_NATIVE_PARAMETER_FPRS = NATIVE_PARAMETER_FPRS.length;
/** Number of native, sys parameter GPRs */
public static final int NUM_NATIVE_PARAMETER_GPRS = NATIVE_PARAMETER_GPRS.length;
// CHECKSTYLE:ON
private RegisterConstants() {
// prevent instantiation
}
}