From 096bb8bf7494d06b41bddd601ef25314deada56f Mon Sep 17 00:00:00 2001 From: Tellow Krinkle Date: Thu, 16 Jul 2020 03:20:47 -0500 Subject: [PATCH] x86emitter: Remove virtual methods from register types Allows methods to generate variable-sized registers --- common/include/x86emitter/x86types.h | 198 +++++++++++---------------- common/src/x86emitter/jmp.cpp | 12 +- common/src/x86emitter/x86emitter.cpp | 32 ++--- pcsx2/x86/ix86-32/recVTLB.cpp | 8 +- pcsx2/x86/microVU_Lower.inl | 4 +- 5 files changed, 111 insertions(+), 143 deletions(-) diff --git a/common/include/x86emitter/x86types.h b/common/include/x86emitter/x86types.h index 2c12c08cb9..9c3491e9ab 100644 --- a/common/include/x86emitter/x86types.h +++ b/common/include/x86emitter/x86types.h @@ -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 &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 &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) { } }; diff --git a/common/src/x86emitter/jmp.cpp b/common/src/x86emitter/jmp.cpp index b6e5961c1c..7bd44aa9fb 100644 --- a/common/src/x86emitter/jmp.cpp +++ b/common/src/x86emitter/jmp.cpp @@ -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)); } } diff --git a/common/src/x86emitter/x86emitter.cpp b/common/src/x86emitter/x86emitter.cpp index 55ac07da45..55a58bb27a 100644 --- a/common/src/x86emitter/x86emitter.cpp +++ b/common/src/x86emitter/x86emitter.cpp @@ -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; } } diff --git a/pcsx2/x86/ix86-32/recVTLB.cpp b/pcsx2/x86/ix86-32/recVTLB.cpp index 71fda7b427..7f9f0373f5 100644 --- a/pcsx2/x86/ix86-32/recVTLB.cpp +++ b/pcsx2/x86/ix86-32/recVTLB.cpp @@ -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: diff --git a/pcsx2/x86/microVU_Lower.inl b/pcsx2/x86/microVU_Lower.inl index 437148a2ad..3c0fa9c7e2 100644 --- a/pcsx2/x86/microVU_Lower.inl +++ b/pcsx2/x86/microVU_Lower.inl @@ -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_); }