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
{
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)
{
}
};

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

View File

@ -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;
}
}

View File

@ -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:

View File

@ -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_); }