x86emitter: Remove virtual methods from register types

Allows methods to generate variable-sized registers
This commit is contained in:
Tellow Krinkle 2020-07-16 03:20:47 -05:00 committed by tellowkrinkle
parent f33a6076dc
commit 096bb8bf74
5 changed files with 111 additions and 143 deletions

View File

@ -201,8 +201,18 @@ class xAddressVoid;
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
class OperandSizedObject class OperandSizedObject
{ {
protected:
uint _operandSize = 0;
OperandSizedObject() = default;
OperandSizedObject(uint operandSize)
: _operandSize(operandSize)
{
}
public: 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; } bool Is8BitOp() const { return GetOperandSize() == 1; }
u8 GetPrefix16() const { return GetOperandSize() == 2 ? 0x66 : 0; } u8 GetPrefix16() const { return GetOperandSize() == 2 ? 0x66 : 0; }
@ -258,20 +268,20 @@ static const int xRegId_Invalid = -2;
// //
class xRegisterBase : public OperandSizedObject 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: public:
int Id; int Id;
xRegisterBase() 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; } bool IsEmpty() const { return Id < 0; }
@ -301,9 +311,6 @@ public:
// return true if the register is a valid YMM register // return true if the register is a valid YMM register
bool IsWideSIMD() const { return GetOperandSize() == 32; } 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 // 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. // is a valid non-null string for any Id, valid or invalid. No assertions are generated.
const char *GetName(); const char *GetName();
@ -314,19 +321,35 @@ class xRegisterInt : public xRegisterBase
{ {
typedef xRegisterBase _parent; typedef xRegisterBase _parent;
public: protected:
xRegisterInt() {} explicit xRegisterInt(uint operandSize, int regId)
explicit xRegisterInt(const xRegisterBase &src) : _parent(operandSize, regId)
: _parent(src)
{ {
} }
explicit xRegisterInt(int regId) public:
: _parent(regId) 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) /// 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 Id == src.Id && (GetOperandSize() == src.GetOperandSize()); }
bool operator!=(const xRegisterInt &src) const { return !operator==(src); } bool operator!=(const xRegisterInt &src) const { return !operator==(src); }
@ -340,17 +363,16 @@ class xRegister8 : public xRegisterInt
typedef xRegisterInt _parent; typedef xRegisterInt _parent;
public: public:
xRegister8() xRegister8() = default;
: _parent()
{
}
explicit xRegister8(int regId) explicit xRegister8(int regId)
: _parent(regId) : _parent(1, regId)
{ {
} }
explicit xRegister8(const xRegisterInt& other)
virtual uint GetOperandSize() const override { return 1; } : _parent(1, other.Id)
virtual const xRegisterInt& GetNonWide() const override { return *this; } {
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; }
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; typedef xRegisterInt _parent;
public: public:
xRegister16() xRegister16() = default;
: _parent()
{
}
explicit xRegister16(int regId) explicit xRegister16(int regId)
: _parent(regId) : _parent(2, regId)
{ {
} }
explicit xRegister16(const xRegisterInt& other)
virtual uint GetOperandSize() const override { return 2; } : _parent(2, other.Id)
virtual const xRegisterInt& GetNonWide() const override { return *this; } {
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; }
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; typedef xRegisterInt _parent;
public: public:
xRegister32() xRegister32() = default;
: _parent()
{
}
explicit xRegister32(int regId) explicit xRegister32(int regId)
: _parent(regId) : _parent(4, regId)
{ {
} }
explicit xRegister32(const xRegisterInt& other)
virtual uint GetOperandSize() const override { return 4; } : _parent(4, other.Id)
virtual const xRegisterInt& GetNonWide() const override { return *this; } {
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; }
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; typedef xRegisterInt _parent;
xRegister32 m_nonWide;
public: public:
xRegister64() xRegister64() = default;
: _parent()
, m_nonWide()
{
}
explicit xRegister64(int regId) explicit xRegister64(int regId)
: _parent(regId) : _parent(8, regId)
, m_nonWide(regId)
{ {
} }
explicit xRegister64(const xRegisterInt& other)
virtual uint GetOperandSize() const override { return 8; } : _parent(8, other.Id)
virtual const xRegisterInt& GetNonWide() const override { return m_nonWide; } {
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; }
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; typedef xRegisterBase _parent;
public: public:
xRegisterSSE() xRegisterSSE() = default;
: _parent()
{
}
explicit xRegisterSSE(int regId) 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; }
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); static const inline xRegisterSSE &GetInstance(uint id);
}; };
@ -494,20 +491,9 @@ static const int wordsize = sizeof(sptr);
class xAddressReg : public xRegisterLong class xAddressReg : public xRegisterLong
{ {
public: public:
xAddressReg() xAddressReg() = default;
: xRegisterLong() explicit xAddressReg(xRegisterInt other)
{ : xRegisterLong(other)
}
xAddressReg(const xAddressReg &src)
: xRegisterLong(src.Id)
{
}
xAddressReg(const xRegister32 &src)
: xRegisterLong(src.Id)
{
}
xAddressReg(const xRegister64 &src)
: xRegisterLong(src.Id)
{ {
} }
explicit xAddressReg(int regId) explicit xAddressReg(int regId)
@ -885,8 +871,6 @@ public:
explicit xIndirectVoid(sptr disp); explicit xIndirectVoid(sptr disp);
explicit xIndirectVoid(const xAddressVoid &src); explicit xIndirectVoid(const xAddressVoid &src);
xIndirectVoid(xAddressReg base, xAddressReg index, int scale = 0, sptr displacement = 0); xIndirectVoid(xAddressReg base, xAddressReg index, int scale = 0, sptr displacement = 0);
virtual uint GetOperandSize() const;
xIndirectVoid &Add(sptr imm); xIndirectVoid &Add(sptr imm);
bool IsByteSizeDisp() const { return is_s8(Displacement); } bool IsByteSizeDisp() const { return is_s8(Displacement); }
@ -916,17 +900,22 @@ public:
explicit xIndirect(sptr disp) explicit xIndirect(sptr disp)
: _parent(disp) : _parent(disp)
{ {
_operandSize = sizeof(OperandType);
} }
explicit xIndirect(const xAddressInfo<OperandType> &src) explicit xIndirect(const xAddressInfo<OperandType> &src)
: _parent(src) : _parent(src)
{ {
_operandSize = sizeof(OperandType);
} }
xIndirect(xAddressReg base, xAddressReg index, int scale = 0, sptr displacement = 0) xIndirect(xAddressReg base, xAddressReg index, int scale = 0, sptr displacement = 0)
: _parent(base, index, scale, displacement) : _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) xIndirect<OperandType> &Add(sptr imm)
{ {
@ -970,42 +959,21 @@ class xIndirect64orLess : public xIndirectVoid
{ {
typedef xIndirectVoid _parent; typedef xIndirectVoid _parent;
protected:
uint m_OpSize;
public: public:
xIndirect64orLess(const xIndirect8 &src) xIndirect64orLess(const xIndirect8 &src)
: _parent(src) : _parent(src)
{ {
m_OpSize = src.GetOperandSize();
} }
xIndirect64orLess(const xIndirect16 &src) xIndirect64orLess(const xIndirect16 &src)
: _parent(src) : _parent(src)
{ {
m_OpSize = src.GetOperandSize();
} }
xIndirect64orLess(const xIndirect32 &src) xIndirect64orLess(const xIndirect32 &src)
: _parent(src) : _parent(src)
{ {
m_OpSize = src.GetOperandSize();
} }
xIndirect64orLess(const xIndirect64 &src) xIndirect64orLess(const xIndirect64 &src)
: _parent(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)
{ {
} }
}; };

View File

@ -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 // 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) { if (a2.Id != arg1reg.Id) {
xMOV(Reg1(arg1reg.Id), a1); xMOV(Reg1(arg1reg), a1);
if (!a2.IsEmpty()) { if (!a2.IsEmpty()) {
xMOV(Reg2(arg2reg.Id), a2); xMOV(Reg2(arg2reg), a2);
} }
} else if (a1.Id != arg2reg.Id) { } else if (a1.Id != arg2reg.Id) {
xMOV(Reg2(arg2reg.Id), a2); xMOV(Reg2(arg2reg), a2);
xMOV(Reg1(arg1reg.Id), a1); xMOV(Reg1(arg1reg), a1);
} else { } else {
xPUSH(a1); xPUSH(a1);
xMOV(Reg2(arg2reg.Id), a2); xMOV(Reg2(arg2reg), a2);
xPOP(Reg1(arg1reg.Id)); xPOP(Reg1(arg1reg));
} }
} }

View File

@ -578,6 +578,16 @@ __emitinline void xAdvancePtr(uint bytes)
x86Ptr += 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) // 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) xIndirectVoid &xIndirectVoid::Add(sptr imm)
{ {
Displacement += imm; Displacement += imm;
@ -851,10 +855,6 @@ static void EmitLeaMagic(const xRegisterInt &to, const xIndirectVoid &src, bool
// See EmitSibMagic for commenting on SIB encoding. // 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) { if (!NeedsSibMagic(src) && src.Displacement == (s32)src.Displacement) {
// LEA Land: means we have either 1-register encoding or just an offset. // 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 // 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; return;
} }
else if (displacement_size == 0) { else if (displacement_size == 0) {
_xMovRtoR(to, sizeMatchedIndex); _xMovRtoR(to, src.Index.MatchSizeTo(to));
return; return;
} else if (!preserve_flags) { } else if (!preserve_flags) {
// encode as MOV and ADD combo. Make sure to use the immediate on the // 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. // 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); xADD(to, src.Displacement);
return; return;
} }
@ -894,20 +894,20 @@ static void EmitLeaMagic(const xRegisterInt &to, const xIndirectVoid &src, bool
if (!preserve_flags) { if (!preserve_flags) {
if (src.Index == rsp) { if (src.Index == rsp) {
// ESP is not encodable as an index (ix86 ignores it), thus: // 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) if (src.Displacement)
xADD(to, src.Displacement); xADD(to, src.Displacement);
return; return;
} else if (src.Displacement == 0) { } else if (src.Displacement == 0) {
_xMovRtoR(to, sizeMatchedBase); _xMovRtoR(to, src.Base.MatchSizeTo(to));
_g1_EmitOp(G1Type_ADD, to, sizeMatchedIndex); _g1_EmitOp(G1Type_ADD, to, src.Index.MatchSizeTo(to));
return; return;
} }
} else if ((src.Index == rsp) && (src.Displacement == 0)) { } else if ((src.Index == rsp) && (src.Displacement == 0)) {
// special case handling of ESP as Index, which is replaceable with // special case handling of ESP as Index, which is replaceable with
// a single MOV even when preserve_flags is set! :D // a single MOV even when preserve_flags is set! :D
_xMovRtoR(to, sizeMatchedBase); _xMovRtoR(to, src.Base.MatchSizeTo(to));
return; return;
} }
} }

View File

@ -206,7 +206,7 @@ namespace vtlb_private
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static void DynGen_DirectWrite( u32 bits ) 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) switch(bits)
{ {
//8 , 16, 32 : data on EDX //8 , 16, 32 : data on EDX
@ -216,7 +216,7 @@ namespace vtlb_private
break; break;
case 16: case 16:
xMOV( ptr[arg1reg], xRegister16(arg2reg.Id) ); xMOV( ptr[arg1reg], xRegister16(arg2reg) );
break; break;
case 32: case 32:
@ -543,7 +543,7 @@ void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const )
auto vmv = vtlbdata.vmap[addr_const>>VTLB_PAGE_BITS]; auto vmv = vtlbdata.vmap[addr_const>>VTLB_PAGE_BITS];
if( !vmv.isHandler(addr_const) ) 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); auto ppf = vmv.assumePtr(addr_const);
switch(bits) switch(bits)
{ {
@ -554,7 +554,7 @@ void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const )
break; break;
case 16: case 16:
xMOV( ptr[(void*)ppf], xRegister16(arg2reg.Id) ); xMOV( ptr[(void*)ppf], xRegister16(arg2reg) );
break; break;
case 32: case 32:

View File

@ -939,10 +939,10 @@ mVUop(mVU_ISW) {
if (!_Is_) if (!_Is_)
xXOR(gprT2, gprT2); xXOR(gprT2, gprT2);
xADD(gprT2, _Imm11_); xADD(gprT2, _Imm11_);
mVUaddrFix (mVU, gprT2); mVUaddrFix (mVU, gprT2q);
mVUallocVIa(mVU, gprT1, _It_); mVUallocVIa(mVU, gprT1, _It_);
writeBackISW(mVU, ptr, gprT2); writeBackISW(mVU, ptr, gprT2q);
mVU.profiler.EmitOp(opISW); mVU.profiler.EmitOp(opISW);
} }
pass3 { mVUlog("ISW.%s vi%02d, vi%02d + %d", _XYZW_String, _Ft_, _Fs_, _Imm11_); } pass3 { mVUlog("ISW.%s vi%02d, vi%02d + %d", _XYZW_String, _Ft_, _Fs_, _Imm11_); }