mirror of https://github.com/PCSX2/pcsx2.git
x86emitter: Remove virtual methods from register types
Allows methods to generate variable-sized registers
This commit is contained in:
parent
f33a6076dc
commit
096bb8bf74
|
@ -201,8 +201,18 @@ class xAddressVoid;
|
|||
// --------------------------------------------------------------------------------------
|
||||
class OperandSizedObject
|
||||
{
|
||||
protected:
|
||||
uint _operandSize = 0;
|
||||
OperandSizedObject() = default;
|
||||
OperandSizedObject(uint operandSize)
|
||||
: _operandSize(operandSize)
|
||||
{
|
||||
}
|
||||
public:
|
||||
virtual uint GetOperandSize() const = 0;
|
||||
uint GetOperandSize() const {
|
||||
pxAssertDev(_operandSize != 0, "Attempted to use operand size of uninitialized or void object");
|
||||
return _operandSize;
|
||||
}
|
||||
|
||||
bool Is8BitOp() const { return GetOperandSize() == 1; }
|
||||
u8 GetPrefix16() const { return GetOperandSize() == 2 ? 0x66 : 0; }
|
||||
|
@ -258,20 +268,20 @@ static const int xRegId_Invalid = -2;
|
|||
//
|
||||
class xRegisterBase : public OperandSizedObject
|
||||
{
|
||||
protected:
|
||||
xRegisterBase(uint operandSize, int regId)
|
||||
: OperandSizedObject(operandSize), Id(regId)
|
||||
{
|
||||
// Note: to avoid tons of ifdef, the 32 bits build will instantiate
|
||||
// all 16x64 bits registers.
|
||||
pxAssert((Id >= xRegId_Empty) && (Id < 16));
|
||||
}
|
||||
public:
|
||||
int Id;
|
||||
|
||||
xRegisterBase()
|
||||
: OperandSizedObject(0), Id(xRegId_Invalid)
|
||||
{
|
||||
Id = xRegId_Invalid;
|
||||
}
|
||||
|
||||
explicit xRegisterBase(int regId)
|
||||
{
|
||||
Id = regId;
|
||||
// Note: to avoid tons of ifdef, the 32 bits build will instantiate
|
||||
// all 16x64 bits registers.
|
||||
pxAssert((Id >= xRegId_Empty) && (Id < 16));
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return Id < 0; }
|
||||
|
@ -301,9 +311,6 @@ public:
|
|||
// return true if the register is a valid YMM register
|
||||
bool IsWideSIMD() const { return GetOperandSize() == 32; }
|
||||
|
||||
bool operator==(const xRegisterBase &src) const { return (Id == src.Id); }
|
||||
bool operator!=(const xRegisterBase &src) const { return (Id != src.Id); }
|
||||
|
||||
// Diagnostics -- returns a string representation of this register. Return string
|
||||
// is a valid non-null string for any Id, valid or invalid. No assertions are generated.
|
||||
const char *GetName();
|
||||
|
@ -314,19 +321,35 @@ class xRegisterInt : public xRegisterBase
|
|||
{
|
||||
typedef xRegisterBase _parent;
|
||||
|
||||
public:
|
||||
xRegisterInt() {}
|
||||
explicit xRegisterInt(const xRegisterBase &src)
|
||||
: _parent(src)
|
||||
protected:
|
||||
explicit xRegisterInt(uint operandSize, int regId)
|
||||
: _parent(operandSize, regId)
|
||||
{
|
||||
}
|
||||
explicit xRegisterInt(int regId)
|
||||
: _parent(regId)
|
||||
public:
|
||||
xRegisterInt() = default;
|
||||
|
||||
/// IDs in [4, 8) are h registers in 8-bit
|
||||
int isIDSameInAllSizes() const
|
||||
{
|
||||
return Id < 4 || Id >= 8;
|
||||
}
|
||||
|
||||
/// Checks if mapping the ID directly would be a good idea
|
||||
bool canMapIDTo(int otherSize) const
|
||||
{
|
||||
if ((otherSize == 1) == GetOperandSize() == 1)
|
||||
return true;
|
||||
return isIDSameInAllSizes();
|
||||
}
|
||||
|
||||
/// Get a non-wide version of the register (for use with e.g. mov, where `mov eax, 3` and `mov rax, 3` are functionally identical but `mov eax, 3` is shorter)
|
||||
virtual const xRegisterInt& GetNonWide() const = 0;
|
||||
xRegisterInt GetNonWide() const
|
||||
{
|
||||
return GetOperandSize() == 8 ? xRegisterInt(4, Id) : *this;
|
||||
}
|
||||
|
||||
xRegisterInt MatchSizeTo(xRegisterInt other) const;
|
||||
|
||||
bool operator==(const xRegisterInt &src) const { return Id == src.Id && (GetOperandSize() == src.GetOperandSize()); }
|
||||
bool operator!=(const xRegisterInt &src) const { return !operator==(src); }
|
||||
|
@ -340,17 +363,16 @@ class xRegister8 : public xRegisterInt
|
|||
typedef xRegisterInt _parent;
|
||||
|
||||
public:
|
||||
xRegister8()
|
||||
: _parent()
|
||||
{
|
||||
}
|
||||
xRegister8() = default;
|
||||
explicit xRegister8(int regId)
|
||||
: _parent(regId)
|
||||
: _parent(1, regId)
|
||||
{
|
||||
}
|
||||
|
||||
virtual uint GetOperandSize() const override { return 1; }
|
||||
virtual const xRegisterInt& GetNonWide() const override { return *this; }
|
||||
explicit xRegister8(const xRegisterInt& other)
|
||||
: _parent(1, other.Id)
|
||||
{
|
||||
pxAssertDev(other.canMapIDTo(1), "spl, bpl, sil, dil not yet supported");
|
||||
}
|
||||
|
||||
bool operator==(const xRegister8 &src) const { return Id == src.Id; }
|
||||
bool operator!=(const xRegister8 &src) const { return Id != src.Id; }
|
||||
|
@ -361,17 +383,16 @@ class xRegister16 : public xRegisterInt
|
|||
typedef xRegisterInt _parent;
|
||||
|
||||
public:
|
||||
xRegister16()
|
||||
: _parent()
|
||||
{
|
||||
}
|
||||
xRegister16() = default;
|
||||
explicit xRegister16(int regId)
|
||||
: _parent(regId)
|
||||
: _parent(2, regId)
|
||||
{
|
||||
}
|
||||
|
||||
virtual uint GetOperandSize() const override { return 2; }
|
||||
virtual const xRegisterInt& GetNonWide() const override { return *this; }
|
||||
explicit xRegister16(const xRegisterInt& other)
|
||||
: _parent(2, other.Id)
|
||||
{
|
||||
pxAssertDev(other.canMapIDTo(2), "Mapping h registers to higher registers can produce unexpected values");
|
||||
}
|
||||
|
||||
bool operator==(const xRegister16 &src) const { return this->Id == src.Id; }
|
||||
bool operator!=(const xRegister16 &src) const { return this->Id != src.Id; }
|
||||
|
@ -382,17 +403,16 @@ class xRegister32 : public xRegisterInt
|
|||
typedef xRegisterInt _parent;
|
||||
|
||||
public:
|
||||
xRegister32()
|
||||
: _parent()
|
||||
{
|
||||
}
|
||||
xRegister32() = default;
|
||||
explicit xRegister32(int regId)
|
||||
: _parent(regId)
|
||||
: _parent(4, regId)
|
||||
{
|
||||
}
|
||||
|
||||
virtual uint GetOperandSize() const override { return 4; }
|
||||
virtual const xRegisterInt& GetNonWide() const override { return *this; }
|
||||
explicit xRegister32(const xRegisterInt& other)
|
||||
: _parent(4, other.Id)
|
||||
{
|
||||
pxAssertDev(other.canMapIDTo(4), "Mapping h registers to higher registers can produce unexpected values");
|
||||
}
|
||||
|
||||
bool operator==(const xRegister32 &src) const { return this->Id == src.Id; }
|
||||
bool operator!=(const xRegister32 &src) const { return this->Id != src.Id; }
|
||||
|
@ -402,21 +422,17 @@ class xRegister64 : public xRegisterInt
|
|||
{
|
||||
typedef xRegisterInt _parent;
|
||||
|
||||
xRegister32 m_nonWide;
|
||||
public:
|
||||
xRegister64()
|
||||
: _parent()
|
||||
, m_nonWide()
|
||||
{
|
||||
}
|
||||
xRegister64() = default;
|
||||
explicit xRegister64(int regId)
|
||||
: _parent(regId)
|
||||
, m_nonWide(regId)
|
||||
: _parent(8, regId)
|
||||
{
|
||||
}
|
||||
|
||||
virtual uint GetOperandSize() const override { return 8; }
|
||||
virtual const xRegisterInt& GetNonWide() const override { return m_nonWide; }
|
||||
explicit xRegister64(const xRegisterInt& other)
|
||||
: _parent(8, other.Id)
|
||||
{
|
||||
pxAssertDev(other.canMapIDTo(8), "Mapping h registers to higher registers can produce unexpected values");
|
||||
}
|
||||
|
||||
bool operator==(const xRegister64 &src) const { return this->Id == src.Id; }
|
||||
bool operator!=(const xRegister64 &src) const { return this->Id != src.Id; }
|
||||
|
@ -433,34 +449,15 @@ class xRegisterSSE : public xRegisterBase
|
|||
typedef xRegisterBase _parent;
|
||||
|
||||
public:
|
||||
xRegisterSSE()
|
||||
: _parent()
|
||||
{
|
||||
}
|
||||
xRegisterSSE() = default;
|
||||
explicit xRegisterSSE(int regId)
|
||||
: _parent(regId)
|
||||
: _parent(16, regId)
|
||||
{
|
||||
}
|
||||
|
||||
virtual uint GetOperandSize() const { return 16; }
|
||||
|
||||
bool operator==(const xRegisterSSE &src) const { return this->Id == src.Id; }
|
||||
bool operator!=(const xRegisterSSE &src) const { return this->Id != src.Id; }
|
||||
|
||||
xRegisterSSE &operator++()
|
||||
{
|
||||
++Id;
|
||||
Id &= (iREGCNT_XMM - 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
xRegisterSSE &operator--()
|
||||
{
|
||||
--Id;
|
||||
Id &= (iREGCNT_XMM - 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static const inline xRegisterSSE &GetInstance(uint id);
|
||||
};
|
||||
|
||||
|
@ -494,20 +491,9 @@ static const int wordsize = sizeof(sptr);
|
|||
class xAddressReg : public xRegisterLong
|
||||
{
|
||||
public:
|
||||
xAddressReg()
|
||||
: xRegisterLong()
|
||||
{
|
||||
}
|
||||
xAddressReg(const xAddressReg &src)
|
||||
: xRegisterLong(src.Id)
|
||||
{
|
||||
}
|
||||
xAddressReg(const xRegister32 &src)
|
||||
: xRegisterLong(src.Id)
|
||||
{
|
||||
}
|
||||
xAddressReg(const xRegister64 &src)
|
||||
: xRegisterLong(src.Id)
|
||||
xAddressReg() = default;
|
||||
explicit xAddressReg(xRegisterInt other)
|
||||
: xRegisterLong(other)
|
||||
{
|
||||
}
|
||||
explicit xAddressReg(int regId)
|
||||
|
@ -885,8 +871,6 @@ public:
|
|||
explicit xIndirectVoid(sptr disp);
|
||||
explicit xIndirectVoid(const xAddressVoid &src);
|
||||
xIndirectVoid(xAddressReg base, xAddressReg index, int scale = 0, sptr displacement = 0);
|
||||
|
||||
virtual uint GetOperandSize() const;
|
||||
xIndirectVoid &Add(sptr imm);
|
||||
|
||||
bool IsByteSizeDisp() const { return is_s8(Displacement); }
|
||||
|
@ -916,17 +900,22 @@ public:
|
|||
explicit xIndirect(sptr disp)
|
||||
: _parent(disp)
|
||||
{
|
||||
_operandSize = sizeof(OperandType);
|
||||
}
|
||||
explicit xIndirect(const xAddressInfo<OperandType> &src)
|
||||
: _parent(src)
|
||||
{
|
||||
_operandSize = sizeof(OperandType);
|
||||
}
|
||||
xIndirect(xAddressReg base, xAddressReg index, int scale = 0, sptr displacement = 0)
|
||||
: _parent(base, index, scale, displacement)
|
||||
{
|
||||
_operandSize = sizeof(OperandType);
|
||||
}
|
||||
explicit xIndirect(const xIndirectVoid& other)
|
||||
: _parent(other)
|
||||
{
|
||||
}
|
||||
|
||||
virtual uint GetOperandSize() const { return sizeof(OperandType); }
|
||||
|
||||
xIndirect<OperandType> &Add(sptr imm)
|
||||
{
|
||||
|
@ -970,42 +959,21 @@ class xIndirect64orLess : public xIndirectVoid
|
|||
{
|
||||
typedef xIndirectVoid _parent;
|
||||
|
||||
protected:
|
||||
uint m_OpSize;
|
||||
|
||||
public:
|
||||
xIndirect64orLess(const xIndirect8 &src)
|
||||
: _parent(src)
|
||||
{
|
||||
m_OpSize = src.GetOperandSize();
|
||||
}
|
||||
xIndirect64orLess(const xIndirect16 &src)
|
||||
: _parent(src)
|
||||
{
|
||||
m_OpSize = src.GetOperandSize();
|
||||
}
|
||||
xIndirect64orLess(const xIndirect32 &src)
|
||||
: _parent(src)
|
||||
{
|
||||
m_OpSize = src.GetOperandSize();
|
||||
}
|
||||
xIndirect64orLess(const xIndirect64 &src)
|
||||
: _parent(src)
|
||||
{
|
||||
m_OpSize = src.GetOperandSize();
|
||||
}
|
||||
|
||||
uint GetOperandSize() const { return m_OpSize; }
|
||||
|
||||
protected:
|
||||
//xIndirect64orLess( const xAddressVoid& src ) : _parent( src ) {}
|
||||
|
||||
explicit xIndirect64orLess(sptr disp)
|
||||
: _parent(disp)
|
||||
{
|
||||
}
|
||||
xIndirect64orLess(xAddressReg base, xAddressReg index, int scale = 0, sptr displacement = 0)
|
||||
: _parent(base, index, scale, displacement)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
@ -55,17 +55,17 @@ void prepareRegsForFastcall(const Reg1 &a1, const Reg2 &a2) {
|
|||
|
||||
// Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg
|
||||
if (a2.Id != arg1reg.Id) {
|
||||
xMOV(Reg1(arg1reg.Id), a1);
|
||||
xMOV(Reg1(arg1reg), a1);
|
||||
if (!a2.IsEmpty()) {
|
||||
xMOV(Reg2(arg2reg.Id), a2);
|
||||
xMOV(Reg2(arg2reg), a2);
|
||||
}
|
||||
} else if (a1.Id != arg2reg.Id) {
|
||||
xMOV(Reg2(arg2reg.Id), a2);
|
||||
xMOV(Reg1(arg1reg.Id), a1);
|
||||
xMOV(Reg2(arg2reg), a2);
|
||||
xMOV(Reg1(arg1reg), a1);
|
||||
} else {
|
||||
xPUSH(a1);
|
||||
xMOV(Reg2(arg2reg.Id), a2);
|
||||
xPOP(Reg1(arg1reg.Id));
|
||||
xMOV(Reg2(arg2reg), a2);
|
||||
xPOP(Reg1(arg1reg));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -578,6 +578,16 @@ __emitinline void xAdvancePtr(uint bytes)
|
|||
x86Ptr += bytes;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xRegisterInt (method implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
xRegisterInt xRegisterInt::MatchSizeTo(xRegisterInt other) const
|
||||
{
|
||||
return other.GetOperandSize() == 1
|
||||
? xRegisterInt(xRegister8(*this))
|
||||
: xRegisterInt(other.GetOperandSize(), Id);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xAddressReg (operator overloads)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -824,12 +834,6 @@ void xIndirectVoid::Reduce()
|
|||
}
|
||||
}
|
||||
|
||||
uint xIndirectVoid::GetOperandSize() const
|
||||
{
|
||||
pxFailDev("Invalid operation on xIndirectVoid");
|
||||
return 0;
|
||||
}
|
||||
|
||||
xIndirectVoid &xIndirectVoid::Add(sptr imm)
|
||||
{
|
||||
Displacement += imm;
|
||||
|
@ -851,10 +855,6 @@ static void EmitLeaMagic(const xRegisterInt &to, const xIndirectVoid &src, bool
|
|||
|
||||
// See EmitSibMagic for commenting on SIB encoding.
|
||||
|
||||
// We should allow native-sized addressing regs (e.g. lea eax, [rax])
|
||||
const xRegisterInt& sizeMatchedIndex = to.IsWide() ? src.Index : src.Index.GetNonWide();
|
||||
const xRegisterInt& sizeMatchedBase = to.IsWide() ? src.Base : src.Base.GetNonWide();
|
||||
|
||||
if (!NeedsSibMagic(src) && src.Displacement == (s32)src.Displacement) {
|
||||
// LEA Land: means we have either 1-register encoding or just an offset.
|
||||
// offset is encodable as an immediate MOV, and a register is encodable
|
||||
|
@ -865,13 +865,13 @@ static void EmitLeaMagic(const xRegisterInt &to, const xIndirectVoid &src, bool
|
|||
return;
|
||||
}
|
||||
else if (displacement_size == 0) {
|
||||
_xMovRtoR(to, sizeMatchedIndex);
|
||||
_xMovRtoR(to, src.Index.MatchSizeTo(to));
|
||||
return;
|
||||
} else if (!preserve_flags) {
|
||||
// encode as MOV and ADD combo. Make sure to use the immediate on the
|
||||
// ADD since it can encode as an 8-bit sign-extended value.
|
||||
|
||||
_xMovRtoR(to, sizeMatchedIndex);
|
||||
_xMovRtoR(to, src.Index.MatchSizeTo(to));
|
||||
xADD(to, src.Displacement);
|
||||
return;
|
||||
}
|
||||
|
@ -894,20 +894,20 @@ static void EmitLeaMagic(const xRegisterInt &to, const xIndirectVoid &src, bool
|
|||
if (!preserve_flags) {
|
||||
if (src.Index == rsp) {
|
||||
// ESP is not encodable as an index (ix86 ignores it), thus:
|
||||
_xMovRtoR(to, sizeMatchedBase); // will do the trick!
|
||||
_xMovRtoR(to, src.Base.MatchSizeTo(to)); // will do the trick!
|
||||
if (src.Displacement)
|
||||
xADD(to, src.Displacement);
|
||||
return;
|
||||
} else if (src.Displacement == 0) {
|
||||
_xMovRtoR(to, sizeMatchedBase);
|
||||
_g1_EmitOp(G1Type_ADD, to, sizeMatchedIndex);
|
||||
_xMovRtoR(to, src.Base.MatchSizeTo(to));
|
||||
_g1_EmitOp(G1Type_ADD, to, src.Index.MatchSizeTo(to));
|
||||
return;
|
||||
}
|
||||
} else if ((src.Index == rsp) && (src.Displacement == 0)) {
|
||||
// special case handling of ESP as Index, which is replaceable with
|
||||
// a single MOV even when preserve_flags is set! :D
|
||||
|
||||
_xMovRtoR(to, sizeMatchedBase);
|
||||
_xMovRtoR(to, src.Base.MatchSizeTo(to));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ namespace vtlb_private
|
|||
// ------------------------------------------------------------------------
|
||||
static void DynGen_DirectWrite( u32 bits )
|
||||
{
|
||||
// TODO: x86Emitter can't use dil (and xRegister8(rdi.Id) is not dil)
|
||||
// TODO: x86Emitter can't use dil
|
||||
switch(bits)
|
||||
{
|
||||
//8 , 16, 32 : data on EDX
|
||||
|
@ -216,7 +216,7 @@ namespace vtlb_private
|
|||
break;
|
||||
|
||||
case 16:
|
||||
xMOV( ptr[arg1reg], xRegister16(arg2reg.Id) );
|
||||
xMOV( ptr[arg1reg], xRegister16(arg2reg) );
|
||||
break;
|
||||
|
||||
case 32:
|
||||
|
@ -543,7 +543,7 @@ void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const )
|
|||
auto vmv = vtlbdata.vmap[addr_const>>VTLB_PAGE_BITS];
|
||||
if( !vmv.isHandler(addr_const) )
|
||||
{
|
||||
// TODO: x86Emitter can't use dil (and xRegister8(rdi.Id) is not dil)
|
||||
// TODO: x86Emitter can't use dil
|
||||
auto ppf = vmv.assumePtr(addr_const);
|
||||
switch(bits)
|
||||
{
|
||||
|
@ -554,7 +554,7 @@ void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const )
|
|||
break;
|
||||
|
||||
case 16:
|
||||
xMOV( ptr[(void*)ppf], xRegister16(arg2reg.Id) );
|
||||
xMOV( ptr[(void*)ppf], xRegister16(arg2reg) );
|
||||
break;
|
||||
|
||||
case 32:
|
||||
|
|
|
@ -939,10 +939,10 @@ mVUop(mVU_ISW) {
|
|||
if (!_Is_)
|
||||
xXOR(gprT2, gprT2);
|
||||
xADD(gprT2, _Imm11_);
|
||||
mVUaddrFix (mVU, gprT2);
|
||||
mVUaddrFix (mVU, gprT2q);
|
||||
|
||||
mVUallocVIa(mVU, gprT1, _It_);
|
||||
writeBackISW(mVU, ptr, gprT2);
|
||||
writeBackISW(mVU, ptr, gprT2q);
|
||||
mVU.profiler.EmitOp(opISW);
|
||||
}
|
||||
pass3 { mVUlog("ISW.%s vi%02d, vi%02d + %d", _XYZW_String, _Ft_, _Fs_, _Imm11_); }
|
||||
|
|
Loading…
Reference in New Issue