From ac2f5713fc2d241cd1f144f03e7ab08c9f141257 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Thu, 16 Apr 2009 14:45:13 +0000 Subject: [PATCH] Emitter: fixed a bug in MOVSX/ZX's reg->reg form [resolves Issue 159 - missing geometry in DQ8], and moved some files around. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@988 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 40 ++++++++----- .../dwshift.h} | 6 +- .../group1.h} | 17 ++---- .../group2.h} | 7 +-- pcsx2/x86/ix86/implement/incdec.h | 22 +++++++ .../{ix86_impl_movs.h => implement/movs.h} | 5 +- pcsx2/x86/ix86/ix86.cpp | 31 ++++++---- pcsx2/x86/ix86/ix86_legacy.cpp | 49 +++++++-------- pcsx2/x86/ix86/ix86_types.h | 59 +++++-------------- 9 files changed, 120 insertions(+), 116 deletions(-) rename pcsx2/x86/ix86/{ix86_impl_dwshift.h => implement/dwshift.h} (97%) rename pcsx2/x86/ix86/{ix86_impl_group1.h => implement/group1.h} (92%) rename pcsx2/x86/ix86/{ix86_impl_group2.h => implement/group2.h} (97%) create mode 100644 pcsx2/x86/ix86/implement/incdec.h rename pcsx2/x86/ix86/{ix86_impl_movs.h => implement/movs.h} (98%) diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index d81664fa89..7f961b7061 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -2925,22 +2925,6 @@ RelativePath="..\..\x86\ix86\ix86_fpu.cpp" > - - - - - - - - @@ -2993,6 +2977,30 @@ RelativePath="..\..\x86\ix86\ix86_types.h" > + + + + + + + + + + + + & to, const iRegister& from, u8 imm ) @@ -57,7 +57,7 @@ public: if( imm == 0 ) return; prefix16(); write16( 0xa40f | (isShiftRight ? 0x800 : 0) ); - ModRM( 3, from.Id, to.Id ); + ModRM_Direct( from.Id, to.Id ); write8( imm ); } diff --git a/pcsx2/x86/ix86/ix86_impl_group1.h b/pcsx2/x86/ix86/implement/group1.h similarity index 92% rename from pcsx2/x86/ix86/ix86_impl_group1.h rename to pcsx2/x86/ix86/implement/group1.h index b948700b9b..c9b313cb85 100644 --- a/pcsx2/x86/ix86/ix86_impl_group1.h +++ b/pcsx2/x86/ix86/implement/group1.h @@ -19,7 +19,6 @@ #pragma once // Note: This header is meant to be included from within the x86Emitter::Internal namespace. - // Instructions implemented in this header are as follows -->> enum G1Type @@ -52,7 +51,7 @@ public: { prefix16(); iWrite( (Is8BitOperand() ? 0 : 1) | (InstType<<3) ); - ModRM( 3, from.Id, to.Id ); + ModRM_Direct( from.Id, to.Id ); } static __emitinline void Emit( const ModSibBase& sibdest, const iRegister& from ) @@ -89,7 +88,7 @@ public: if( !Is8BitOperand() && is_s8( imm ) ) { iWrite( 0x83 ); - ModRM( 3, InstType, to.Id ); + ModRM_Direct( InstType, to.Id ); iWrite( imm ); } else @@ -99,7 +98,7 @@ public: else { iWrite( Is8BitOperand() ? 0x80 : 0x81 ); - ModRM( 3, InstType, to.Id ); + ModRM_Direct( InstType, to.Id ); } iWrite( imm ); } @@ -148,11 +147,7 @@ public: __noinline void operator()( const iRegister32& to, const ModSibBase& sibsrc ) const{ m_32::Emit( to, sibsrc ); } __noinline void operator()( const ModSibStrict<4>& sibdest, u32 imm ) const { m_32::Emit( sibdest, imm ); } - void operator()( const iRegister32& to, u32 imm, bool needs_flags=false ) const - { - //if( needs_flags || (imm != 0) || !_optimize_imm0() ) - m_32::Emit( to, imm ); - } + void operator()( const iRegister32& to, u32 imm ) const { m_32::Emit( to, imm ); } // ---------- 16 Bit Interface ----------- __forceinline void operator()( const iRegister16& to, const iRegister16& from ) const { m_16::Emit( to, from ); } @@ -162,7 +157,7 @@ public: __noinline void operator()( const iRegister16& to, const ModSibBase& sibsrc ) const{ m_16::Emit( to, sibsrc ); } __noinline void operator()( const ModSibStrict<2>& sibdest, u16 imm ) const { m_16::Emit( sibdest, imm ); } - void operator()( const iRegister16& to, u16 imm, bool needs_flags=false ) const { m_16::Emit( to, imm ); } + void operator()( const iRegister16& to, u16 imm ) const { m_16::Emit( to, imm ); } // ---------- 8 Bit Interface ----------- __forceinline void operator()( const iRegister8& to, const iRegister8& from ) const { m_8::Emit( to, from ); } @@ -172,7 +167,7 @@ public: __noinline void operator()( const iRegister8& to, const ModSibBase& sibsrc ) const{ m_8::Emit( to, sibsrc ); } __noinline void operator()( const ModSibStrict<1>& sibdest, u8 imm ) const { m_8::Emit( sibdest, imm ); } - void operator()( const iRegister8& to, u8 imm, bool needs_flags=false ) const { m_8::Emit( to, imm ); } + void operator()( const iRegister8& to, u8 imm ) const { m_8::Emit( to, imm ); } Group1ImplAll() {} // Why does GCC need these? }; diff --git a/pcsx2/x86/ix86/ix86_impl_group2.h b/pcsx2/x86/ix86/implement/group2.h similarity index 97% rename from pcsx2/x86/ix86/ix86_impl_group2.h rename to pcsx2/x86/ix86/implement/group2.h index dd551713d1..481e3b37d8 100644 --- a/pcsx2/x86/ix86/ix86_impl_group2.h +++ b/pcsx2/x86/ix86/implement/group2.h @@ -19,7 +19,6 @@ #pragma once // Note: This header is meant to be included from within the x86Emitter::Internal namespace. - // Instructions implemented in this header are as follows -->> enum G2Type @@ -56,7 +55,7 @@ public: { prefix16(); iWrite( Is8BitOperand() ? 0xd2 : 0xd3 ); - ModRM( 3, InstType, to.Id ); + ModRM_Direct( InstType, to.Id ); } static __emitinline void Emit( const iRegister& to, u8 imm ) @@ -68,12 +67,12 @@ public: { // special encoding of 1's iWrite( Is8BitOperand() ? 0xd0 : 0xd1 ); - ModRM( 3, InstType, to.Id ); + ModRM_Direct( InstType, to.Id ); } else { iWrite( Is8BitOperand() ? 0xc0 : 0xc1 ); - ModRM( 3, InstType, to.Id ); + ModRM_Direct( InstType, to.Id ); iWrite( imm ); } } diff --git a/pcsx2/x86/ix86/implement/incdec.h b/pcsx2/x86/ix86/implement/incdec.h new file mode 100644 index 0000000000..3a3f9690eb --- /dev/null +++ b/pcsx2/x86/ix86/implement/incdec.h @@ -0,0 +1,22 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2009 Pcsx2 Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +// Implementations found here: Increment and Decrement Instructions! +// Note: This header is meant to be included from within the x86Emitter::Internal namespace. diff --git a/pcsx2/x86/ix86/ix86_impl_movs.h b/pcsx2/x86/ix86/implement/movs.h similarity index 98% rename from pcsx2/x86/ix86/ix86_impl_movs.h rename to pcsx2/x86/ix86/implement/movs.h index b9b67460b9..2ba18be506 100644 --- a/pcsx2/x86/ix86/ix86_impl_movs.h +++ b/pcsx2/x86/ix86/implement/movs.h @@ -44,8 +44,9 @@ public: static __emitinline void Emit( JccComparisonType cc, const iRegister& to, const iRegister& from ) { + if( to == from ) return; emit_base( cc ); - ModRM( 3, to.Id, from.Id ); + ModRM( ModRm_Direct, to.Id, from.Id ); } static __emitinline void Emit( JccComparisonType cc, const iRegister& to, const void* src ) @@ -123,7 +124,7 @@ public: static __emitinline void Emit( const iRegister& to, const iRegister& from, bool SignExtend ) { emit_base( SignExtend ); - ModRM( 3, from.Id, to.Id ); + ModRM_Direct( to.Id, from.Id ); } static __emitinline void Emit( const iRegister& to, const ModSibStrict& sibsrc, bool SignExtend ) diff --git a/pcsx2/x86/ix86/ix86.cpp b/pcsx2/x86/ix86/ix86.cpp index ec41c81e50..7a1d4ec89a 100644 --- a/pcsx2/x86/ix86/ix86.cpp +++ b/pcsx2/x86/ix86/ix86.cpp @@ -128,6 +128,11 @@ namespace Internal //x86Ptr++; } + __forceinline void ModRM_Direct( uint reg, uint rm ) + { + ModRM( Mod_Direct, reg, rm ); + } + __forceinline void SibSB( u32 ss, u32 index, u32 base ) { iWrite( (ss << 6) | (index << 3) | base ); @@ -679,7 +684,7 @@ static __forceinline void EmitMulDiv_OneRegForm( MulDivType InstType, const ModS } ////////////////////////////////////////////////////////////////////////////////////////// -// All ioMul forms are valid for 16 and 32 bit register operands only! +// All iMul forms are valid for 16 and 32 bit register operands only! template< typename ImmType > class iMulImpl @@ -752,12 +757,6 @@ public: } }; -namespace Internal -{ - typedef iMulImpl iMUL32; - typedef iMulImpl iMUL16; -} - __forceinline void iUMUL( const iRegister32& from ) { EmitMulDiv_OneRegForm( MDT_Mul, from ); } __forceinline void iUMUL( const iRegister16& from ) { EmitMulDiv_OneRegForm( MDT_Mul, from ); } __forceinline void iUMUL( const iRegister8& from ) { EmitMulDiv_OneRegForm( MDT_Mul, from ); } @@ -773,22 +772,32 @@ __forceinline void iSDIV( const iRegister16& from ) { EmitMulDiv_OneRegForm( MD __forceinline void iSDIV( const iRegister8& from ) { EmitMulDiv_OneRegForm( MDT_iDiv, from ); } __noinline void iSDIV( const ModSibSized& from ) { EmitMulDiv_OneRegForm( MDT_iDiv, from ); } -__forceinline void iSMUL( const iRegister32& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } +__forceinline void iSMUL( const iRegister32& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } +__forceinline void iSMUL( const iRegister16& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } +__forceinline void iSMUL( const iRegister8& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } +__noinline void iSMUL( const ModSibSized& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } + +// ------------------------------------------------------------------------ +// iMUL's special forms (unique to iMUL alone) + +namespace Internal +{ + typedef iMulImpl iMUL32; + typedef iMulImpl iMUL16; +} + __forceinline void iSMUL( const iRegister32& to, const iRegister32& from ) { iMUL32::Emit( to, from ); } __forceinline void iSMUL( const iRegister32& to, const void* src ) { iMUL32::Emit( to, src ); } __forceinline void iSMUL( const iRegister32& to, const iRegister32& from, s32 imm ) { iMUL32::Emit( to, from, imm ); } __noinline void iSMUL( const iRegister32& to, const ModSibBase& src ) { iMUL32::Emit( to, src ); } __noinline void iSMUL( const iRegister32& to, const ModSibBase& from, s32 imm ) { iMUL32::Emit( to, from, imm ); } -__forceinline void iSMUL( const iRegister16& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } __forceinline void iSMUL( const iRegister16& to, const iRegister16& from ) { iMUL16::Emit( to, from ); } __forceinline void iSMUL( const iRegister16& to, const void* src ) { iMUL16::Emit( to, src ); } __forceinline void iSMUL( const iRegister16& to, const iRegister16& from, s16 imm ) { iMUL16::Emit( to, from, imm ); } __noinline void iSMUL( const iRegister16& to, const ModSibBase& src ) { iMUL16::Emit( to, src ); } __noinline void iSMUL( const iRegister16& to, const ModSibBase& from, s16 imm ) { iMUL16::Emit( to, from, imm ); } -__forceinline void iSMUL( const iRegister8& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } -__noinline void iSMUL( const ModSibSized& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/pcsx2/x86/ix86/ix86_legacy.cpp b/pcsx2/x86/ix86/ix86_legacy.cpp index 3f12a7f818..2fc12afd89 100644 --- a/pcsx2/x86/ix86/ix86_legacy.cpp +++ b/pcsx2/x86/ix86/ix86_legacy.cpp @@ -176,6 +176,31 @@ emitterT void SHRD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift ) iSHRD( iRegister32(to), iRegister32(from), shift ); } +/* mul eax by r32 to edx:eax */ +emitterT void MUL32R( x86IntRegType from ) { iUMUL( iRegister32(from) ); } +/* imul eax by r32 to edx:eax */ +emitterT void IMUL32R( x86IntRegType from ) { iSMUL( iRegister32(from) ); } +/* mul eax by m32 to edx:eax */ +emitterT void MUL32M( u32 from ) { iUMUL( ptr32[from] ); } +/* imul eax by m32 to edx:eax */ +emitterT void IMUL32M( u32 from ) { iSMUL( ptr32[from] ); } + +/* imul r32 by r32 to r32 */ +emitterT void IMUL32RtoR( x86IntRegType to, x86IntRegType from ) +{ + iSMUL( iRegister32(to), iRegister32(from) ); +} + +/* div eax by r32 to edx:eax */ +emitterT void DIV32R( x86IntRegType from ) { iUDIV( iRegister32(from) ); } +/* idiv eax by r32 to edx:eax */ +emitterT void IDIV32R( x86IntRegType from ) { iSDIV( iRegister32(from) ); } +/* div eax by m32 to edx:eax */ +emitterT void DIV32M( u32 from ) { iUDIV( ptr32[from] ); } +/* idiv eax by m32 to edx:eax */ +emitterT void IDIV32M( u32 from ) { iSDIV( ptr32[from] ); } + + emitterT void LEA32RtoR(x86IntRegType to, x86IntRegType from, s32 offset) { iLEA( iRegister32( to ), ptr[x86IndexReg(from)+offset] ); @@ -413,30 +438,6 @@ emitterT void DEC16M( u32 to ) write32( MEMADDR(to, 4) ); } -/* mul eax by r32 to edx:eax */ -emitterT void MUL32R( x86IntRegType from ) { iUMUL( iRegister32(from) ); } -/* imul eax by r32 to edx:eax */ -emitterT void IMUL32R( x86IntRegType from ) { iSMUL( iRegister32(from) ); } -/* mul eax by m32 to edx:eax */ -emitterT void MUL32M( u32 from ) { iUMUL( ptr32[from] ); } -/* imul eax by m32 to edx:eax */ -emitterT void IMUL32M( u32 from ) { iSMUL( ptr32[from] ); } - -/* imul r32 by r32 to r32 */ -emitterT void IMUL32RtoR( x86IntRegType to, x86IntRegType from ) -{ - iSMUL( iRegister32(to), iRegister32(from) ); -} - -/* div eax by r32 to edx:eax */ -emitterT void DIV32R( x86IntRegType from ) { iUDIV( iRegister32(from) ); } -/* idiv eax by r32 to edx:eax */ -emitterT void IDIV32R( x86IntRegType from ) { iSDIV( iRegister32(from) ); } -/* div eax by m32 to edx:eax */ -emitterT void DIV32M( u32 from ) { iUDIV( ptr32[from] ); } -/* idiv eax by m32 to edx:eax */ -emitterT void IDIV32M( u32 from ) { iSDIV( ptr32[from] ); } - //////////////////////////////////// // logical instructions / //////////////////////////////////// diff --git a/pcsx2/x86/ix86/ix86_types.h b/pcsx2/x86/ix86/ix86_types.h index e2f3c16a1e..af473c5c8a 100644 --- a/pcsx2/x86/ix86/ix86_types.h +++ b/pcsx2/x86/ix86/ix86_types.h @@ -147,6 +147,15 @@ namespace x86Emitter # define __noinline #endif + // ModRM 'mod' field enumeration. Provided mostly for reference: + enum ModRm_ModField + { + Mod_NoDisp = 0, // effective address operation with no displacement, in the form of [reg] (or uses special Disp32-only encoding in the case of [ebp] form) + Mod_Disp8, // effective address operation with 8 bit displacement, in the form of [reg+disp8] + Mod_Disp32, // effective address operation with 32 bit displacement, in the form of [reg+disp32], + Mod_Direct, // direct reg/reg operation + }; + static const int ModRm_Direct = 3; // when used as the first parameter, specifies direct register operation (no mem) static const int ModRm_UseSib = 4; // same index value as ESP (used in RM field) static const int ModRm_UseDisp32 = 5; // same index value as EBP (used in Mod field) @@ -636,57 +645,17 @@ namespace x86Emitter namespace Internal { extern void ModRM( uint mod, uint reg, uint rm ); + extern void ModRM_Direct( uint reg, uint rm ); extern void SibSB( u32 ss, u32 index, u32 base ); extern void iWriteDisp( int regfield, s32 displacement ); extern void iWriteDisp( int regfield, const void* address ); extern void EmitSibMagic( uint regfield, const ModSibBase& info ); - #include "ix86_impl_group1.h" - #include "ix86_impl_group2.h" - #include "ix86_impl_movs.h" // cmov and movsx/zx - #include "ix86_impl_dwshift.h" // dowubleword shifts! - - // if the immediate is zero, we can replace the instruction, or ignore it - // entirely, depending on the instruction being issued. That's what we do here. - // (returns FALSE if no optimization is performed) - // [TODO] : Work-in-progress! - //template< G1Type InstType, typename RegType > - //static __forceinline void _optimize_imm0( RegType to ); - - /*template< G1Type InstType, typename RegType > - static __forceinline void _optimize_imm0( const RegType& to ) - { - switch( InstType ) - { - // ADD, SUB, and OR can be ignored if the imm is zero.. - case G1Type_ADD: - case G1Type_SUB: - case G1Type_OR: - return true; - - // ADC and SBB can never be ignored (could have carry bits) - // XOR behavior is distinct as well [or is it the same as NEG or NOT?] - case G1Type_ADC: - case G1Type_SBB: - case G1Type_XOR: - return false; - - // replace AND with XOR (or SUB works too.. whatever!) - case G1Type_AND: - iXOR( to, to ); - return true; - - // replace CMP with OR reg,reg: - case G1Type_CMP: - iOR( to, to ); - return true; - - jNO_DEFAULT - } - return false; - }*/ - + #include "implement/group1.h" + #include "implement/group2.h" + #include "implement/movs.h" // cmov and movsx/zx + #include "implement/dwshift.h" // dowubleword shifts! } // ------------------------------------------------------------------------