* Added MUL/DIV/IMUL/IDIV to the emitter, renamed as UMUL/SMUL respectively (to remove ambiguity of the instruction behaviors).
 * Fixed a bug in the shift instruction emitter that would have caused it to emit the wrong instruction type (like a SHR instead of a SHL, for example).
 * Added type strictness to the shift instructions that take the CL register as a parameter.  Passing anything other than CL will generate compile time errors now.
 * Fixed a syntax error in one of the legacy defines.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@986 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-04-16 01:34:09 +00:00
parent f228a91c93
commit 4658529970
6 changed files with 340 additions and 168 deletions

View File

@ -2925,6 +2925,10 @@
RelativePath="..\..\x86\ix86\ix86_fpu.cpp"
>
</File>
<File
RelativePath="..\..\x86\ix86\ix86_impl_dwshift.h"
>
</File>
<File
RelativePath="..\..\x86\ix86\ix86_impl_group1.h"
>

View File

@ -74,7 +74,7 @@ const x86IndexerTypeExplicit<1> ptr8;
// ------------------------------------------------------------------------
template< int OperandSize > const iRegister<OperandSize> iRegister<OperandSize>::Empty;
const x86IndexReg x86IndexReg::Empty;
const x86IndexReg x86IndexReg::Empty;
const iRegister32
eax( 0 ), ebx( 3 ),
@ -89,11 +89,13 @@ const iRegister16
bp( 5 ), sp( 4 );
const iRegister8
al( 0 ), cl( 1 ),
al( 0 ),
dl( 2 ), bl( 3 ),
ah( 4 ), ch( 5 ),
dh( 6 ), bh( 7 );
const iRegisterCL cl;
namespace Internal
{
// Performance note: VC++ wants to use byte/word register form for the following
@ -250,8 +252,11 @@ const Group2ImplAll<G2Type_SHL> iSHL;
const Group2ImplAll<G2Type_SHR> iSHR;
const Group2ImplAll<G2Type_SAR> iSAR;
const MovExtendImplAll<true> iMOVSX;
const MovExtendImplAll<false> iMOVZX;
const MovExtendImplAll<true> iMOVSX;
const Internal::DwordShiftImplAll<false> iSHLD;
const Internal::DwordShiftImplAll<true> iSHRD;
const CMovImplGeneric iCMOV;
@ -641,6 +646,150 @@ void iMOV( const iRegister8& to, u8 imm, bool preserve_flags )
MOV8::Emit( to, imm );
}
//////////////////////////////////////////////////////////////////////////////////////////
// DIV/MUL/IDIV/IMUL instructions (Implemented!)
// F6 is r8, F7 is r32.
// MUL is 4, DIV is 6.
enum MulDivType
{
MDT_Mul = 4,
MDT_iMul = 5,
MDT_Div = 6,
MDT_iDiv = 7
};
// ------------------------------------------------------------------------
// EAX form emitter for Mul/Div/iMUL/iDIV
//
template< int OperandSize >
static __forceinline void EmitMulDiv_OneRegForm( MulDivType InstType, const iRegister<OperandSize>& from )
{
if( OperandSize == 2 ) iWrite<u8>( 0x66 );
iWrite<u8>( (OperandSize == 1) ? 0xf6 : 0xf7 );
ModRM( ModRm_Direct, InstType, from.Id );
}
static __forceinline void EmitMulDiv_OneRegForm( MulDivType InstType, const ModSibSized& sibsrc )
{
if( sibsrc.OperandSize == 2 ) iWrite<u8>( 0x66 );
iWrite<u8>( (sibsrc.OperandSize == 1) ? 0xf6 : 0xf7 );
EmitSibMagic( InstType, sibsrc );
}
//////////////////////////////////////////////////////////////////////////////////////////
// All ioMul forms are valid for 16 and 32 bit register operands only!
template< typename ImmType >
class iMulImpl
{
public:
static const uint OperandSize = sizeof(ImmType);
protected:
static void prefix16() { if( OperandSize == 2 ) iWrite<u8>( 0x66 ); }
public:
// ------------------------------------------------------------------------
static __forceinline void Emit( const iRegister<OperandSize>& to, const iRegister<OperandSize>& from )
{
prefix16();
write16( 0xaf0f );
ModRM( ModRm_Direct, to.Id, from.Id );
}
// ------------------------------------------------------------------------
static __forceinline void Emit( const iRegister<OperandSize>& to, const void* src )
{
prefix16();
write16( 0xaf0f );
iWriteDisp( to.Id, src );
}
// ------------------------------------------------------------------------
static __forceinline void Emit( const iRegister<OperandSize>& to, const ModSibBase& src )
{
prefix16();
write16( 0xaf0f );
EmitSibMagic( to.Id, src );
}
// ------------------------------------------------------------------------
static __forceinline void Emit( const iRegister<OperandSize>& to, const iRegister<OperandSize>& from, ImmType imm )
{
prefix16();
write16( is_s8( imm ) ? 0x6b : 0x69 );
ModRM( ModRm_Direct, to.Id, from.Id );
if( is_s8( imm ) )
write8( imm );
else
iWrite<ImmType>( imm );
}
// ------------------------------------------------------------------------
static __forceinline void Emit( const iRegister<OperandSize>& to, const void* src, ImmType imm )
{
prefix16();
write16( is_s8( imm ) ? 0x6b : 0x69 );
iWriteDisp( to.Id, src );
if( is_s8( imm ) )
write8( imm );
else
iWrite<ImmType>( imm );
}
// ------------------------------------------------------------------------
static __forceinline void Emit( const iRegister<OperandSize>& to, const ModSibBase& src, ImmType imm )
{
prefix16();
write16( is_s8( imm ) ? 0x6b : 0x69 );
EmitSibMagic( to.Id, src );
if( is_s8( imm ) )
write8( imm );
else
iWrite<ImmType>( imm );
}
};
namespace Internal
{
typedef iMulImpl<u32> iMUL32;
typedef iMulImpl<u16> 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 ); }
__noinline void iUMUL( const ModSibSized& from ) { EmitMulDiv_OneRegForm( MDT_Mul, from ); }
__forceinline void iUDIV( const iRegister32& from ) { EmitMulDiv_OneRegForm( MDT_Div, from ); }
__forceinline void iUDIV( const iRegister16& from ) { EmitMulDiv_OneRegForm( MDT_Div, from ); }
__forceinline void iUDIV( const iRegister8& from ) { EmitMulDiv_OneRegForm( MDT_Div, from ); }
__noinline void iUDIV( const ModSibSized& from ) { EmitMulDiv_OneRegForm( MDT_Div, from ); }
__forceinline void iSDIV( const iRegister32& from ) { EmitMulDiv_OneRegForm( MDT_iDiv, from ); }
__forceinline void iSDIV( const iRegister16& from ) { EmitMulDiv_OneRegForm( MDT_iDiv, from ); }
__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& 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 ); }
//////////////////////////////////////////////////////////////////////////////////////////
// Push / Pop Emitters

View File

@ -52,10 +52,8 @@ protected:
static void prefix16() { if( OperandSize == 2 ) iWrite<u8>( 0x66 ); }
public:
static __emitinline void Emit( const iRegister<OperandSize>& to, const iRegister8& from )
static __emitinline void Emit( const iRegister<OperandSize>& to )
{
jASSUME( from == cl ); // cl is the only valid shift register. (turn this into a compile time check?)
prefix16();
iWrite<u8>( Is8BitOperand() ? 0xd2 : 0xd3 );
ModRM( 3, InstType, to.Id );
@ -80,13 +78,11 @@ public:
}
}
static __emitinline void Emit( const ModSibStrict<OperandSize>& sibdest, const iRegister8& from )
static __emitinline void Emit( const ModSibStrict<OperandSize>& sibdest )
{
jASSUME( from == cl ); // cl is the only valid shift register. (turn this into a compile time check?)
prefix16();
iWrite<u8>( Is8BitOperand() ? 0xd2 : 0xd3 );
EmitSibMagic( from.Id, sibdest );
EmitSibMagic( InstType, sibdest );
}
static __emitinline void Emit( const ModSibStrict<OperandSize>& sibdest, u8 imm )
@ -130,20 +126,20 @@ protected:
public:
// ---------- 32 Bit Interface -----------
__forceinline void operator()( const iRegister32& to, const iRegister8& from ) const { m_32::Emit( to, from ); }
__noinline void operator()( const ModSibStrict<4>& sibdest, const iRegister8& from ) const { m_32::Emit( sibdest, from ); }
__forceinline void operator()( const iRegister32& to, __unused const iRegisterCL& from ) const{ m_32::Emit( to ); }
__noinline void operator()( const ModSibStrict<4>& sibdest, __unused const iRegisterCL& from ) const{ m_32::Emit( sibdest ); }
__noinline void operator()( const ModSibStrict<4>& sibdest, u8 imm ) const { m_32::Emit( sibdest, imm ); }
void operator()( const iRegister32& to, u8 imm ) const { m_32::Emit( to, imm ); }
// ---------- 16 Bit Interface -----------
__forceinline void operator()( const iRegister16& to, const iRegister8& from ) const { m_16::Emit( to, from ); }
__noinline void operator()( const ModSibStrict<2>& sibdest, const iRegister8& from ) const { m_16::Emit( sibdest, from ); }
__forceinline void operator()( const iRegister16& to, __unused const iRegisterCL& from ) const{ m_16::Emit( to ); }
__noinline void operator()( const ModSibStrict<2>& sibdest, __unused const iRegisterCL& from ) const{ m_16::Emit( sibdest ); }
__noinline void operator()( const ModSibStrict<2>& sibdest, u8 imm ) const { m_16::Emit( sibdest, imm ); }
void operator()( const iRegister16& to, u8 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 ); }
__noinline void operator()( const ModSibStrict<1>& sibdest, const iRegister8& from ) const { m_8::Emit( sibdest, from ); }
__forceinline void operator()( const iRegister8& to, __unused const iRegisterCL& from ) const{ m_8::Emit( to ); }
__noinline void operator()( const ModSibStrict<1>& sibdest, __unused const iRegisterCL& from ) const{ m_8::Emit( sibdest ); }
__noinline void operator()( const ModSibStrict<1>& sibdest, u8 imm ) const { m_8::Emit( sibdest, imm ); }
void operator()( const iRegister8& to, u8 imm ) const { m_8::Emit( to, imm ); }

View File

@ -83,6 +83,42 @@ namespace x86Emitter
// NOP 1-byte
__forceinline void iNOP() { write8(0x90); }
//////////////////////////////////////////////////////////////////////////////////////////
// MUL / DIV instructions
extern void iUMUL( const iRegister32& from );
extern void iUMUL( const iRegister16& from );
extern void iUMUL( const iRegister8& from );
extern void iUMUL( const ModSibSized& from );
extern void iUDIV( const iRegister32& from );
extern void iUDIV( const iRegister16& from );
extern void iUDIV( const iRegister8& from );
extern void iUDIV( const ModSibSized& from );
extern void iSDIV( const iRegister32& from );
extern void iSDIV( const iRegister16& from );
extern void iSDIV( const iRegister8& from );
extern void iSDIV( const ModSibSized& from );
extern void iSMUL( const iRegister32& from );
extern void iSMUL( const iRegister32& to, const iRegister32& from );
extern void iSMUL( const iRegister32& to, const void* src );
extern void iSMUL( const iRegister32& to, const iRegister32& from, s32 imm );
extern void iSMUL( const iRegister32& to, const ModSibBase& src );
extern void iSMUL( const iRegister32& to, const ModSibBase& src, s32 imm );
extern void iSMUL( const iRegister16& from );
extern void iSMUL( const iRegister16& to, const iRegister16& from );
extern void iSMUL( const iRegister16& to, const void* src );
extern void iSMUL( const iRegister16& to, const iRegister16& from, s16 imm );
extern void iSMUL( const iRegister16& to, const ModSibBase& src );
extern void iSMUL( const iRegister16& to, const ModSibBase& src, s16 imm );
extern void iSMUL( const iRegister8& from );
extern void iSMUL( const ModSibSized& from );
//////////////////////////////////////////////////////////////////////////////////////////
// MOV instructions!
// ---------- 32 Bit Interface -----------

View File

@ -117,9 +117,9 @@ DEFINE_OPCODE_LEGACY( MOV )
// ------------------------------------------------------------------------
#define DEFINE_LEGACY_MOVEXTEND( form, destbits, srcbits ) \
emitterT void MOV##form##destbits##R##srcbits##toR( x86IntRegType to, x86IntRegType from ) { iMOV##form##( iRegister##destbits( to ), iRegister##srcbits( from ) ); } \
emitterT void MOV##form##destbits##Rm##srcbits##toR( x86IntRegType to, x86IntRegType from, int offset ) { iMOV##form##( iRegister##destbits( to ), ptr##srcbits[x86IndexReg( from ) + offset] ); } \
emitterT void MOV##form##destbits##M##srcbits##toR( x86IntRegType to, u32 from ) { iMOV##form##( iRegister##destbits( to ), ptr##srcbits[from] ); }
emitterT void MOV##form##destbits##R##srcbits##toR( x86IntRegType to, x86IntRegType from ) { iMOV##form( iRegister##destbits( to ), iRegister##srcbits( from ) ); } \
emitterT void MOV##form##destbits##Rm##srcbits##toR( x86IntRegType to, x86IntRegType from, int offset ) { iMOV##form( iRegister##destbits( to ), ptr##srcbits[x86IndexReg( from ) + offset] ); } \
emitterT void MOV##form##destbits##M##srcbits##toR( x86IntRegType to, u32 from ) { iMOV##form( iRegister##destbits( to ), ptr##srcbits[from] ); }
DEFINE_LEGACY_MOVEXTEND( SX, 32, 16 )
DEFINE_LEGACY_MOVEXTEND( ZX, 32, 16 )
@ -164,7 +164,53 @@ emitterT void CMOVE32RtoR( x86IntRegType to, x86IntRegType from )
iCMOVE( iRegister32(to), iRegister32(from) );
}
// shld imm8 to r32
emitterT void SHLD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift )
{
iSHLD( iRegister32(to), iRegister32(from), shift );
}
// shrd imm8 to r32
emitterT void SHRD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift )
{
iSHRD( iRegister32(to), iRegister32(from), shift );
}
emitterT void LEA32RtoR(x86IntRegType to, x86IntRegType from, s32 offset)
{
iLEA( iRegister32( to ), ptr[x86IndexReg(from)+offset] );
}
emitterT void LEA32RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1)
{
iLEA( iRegister32( to ), ptr[x86IndexReg(from0)+x86IndexReg(from1)] );
}
// Don't inline recursive functions
emitterT void LEA32RStoR(x86IntRegType to, x86IntRegType from, u32 scale)
{
iLEA( iRegister32( to ), ptr[x86IndexReg(from)*(1<<scale)] );
}
// to = from + offset
emitterT void LEA16RtoR(x86IntRegType to, x86IntRegType from, s16 offset)
{
iLEA( iRegister16( to ), ptr[x86IndexReg(from)+offset] );
}
// to = from0 + from1
emitterT void LEA16RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1)
{
iLEA( iRegister16( to ), ptr[x86IndexReg(from0)+x86IndexReg(from1)] );
}
// to = from << scale (max is 3)
emitterT void LEA16RStoR(x86IntRegType to, x86IntRegType from, u32 scale)
{
iLEA( iRegister16( to ), ptr[x86IndexReg(from)*(1<<scale)] );
}
//////////////////////////////////////////////////////////////////////////////////////////
// Note: the 'to' field can either be a register or a special opcode extension specifier
// depending on the opcode's encoding.
@ -368,96 +414,28 @@ emitterT void DEC16M( u32 to )
}
/* mul eax by r32 to edx:eax */
emitterT void MUL32R( x86IntRegType from )
{
RexB(0,from);
write8( 0xF7 );
ModRM( 3, 4, from );
}
emitterT void MUL32R( x86IntRegType from ) { iUMUL( iRegister32(from) ); }
/* imul eax by r32 to edx:eax */
emitterT void IMUL32R( x86IntRegType from )
{
RexB(0,from);
write8( 0xF7 );
ModRM( 3, 5, from );
}
emitterT void IMUL32R( x86IntRegType from ) { iSMUL( iRegister32(from) ); }
/* mul eax by m32 to edx:eax */
emitterT void MUL32M( u32 from )
{
write8( 0xF7 );
ModRM( 0, 4, DISP32 );
write32( MEMADDR(from, 4) );
}
emitterT void MUL32M( u32 from ) { iUMUL( ptr32[from] ); }
/* imul eax by m32 to edx:eax */
emitterT void IMUL32M( u32 from )
{
write8( 0xF7 );
ModRM( 0, 5, DISP32 );
write32( MEMADDR(from, 4) );
}
emitterT void IMUL32M( u32 from ) { iSMUL( ptr32[from] ); }
/* imul r32 by r32 to r32 */
emitterT void IMUL32RtoR( x86IntRegType to, x86IntRegType from )
{
RexRB(0,to,from);
write16( 0xAF0F );
ModRM( 3, to, from );
iSMUL( iRegister32(to), iRegister32(from) );
}
/* div eax by r32 to edx:eax */
emitterT void DIV32R( x86IntRegType from )
{
RexB(0,from);
write8( 0xF7 );
ModRM( 3, 6, from );
}
emitterT void DIV32R( x86IntRegType from ) { iUDIV( iRegister32(from) ); }
/* idiv eax by r32 to edx:eax */
emitterT void IDIV32R( x86IntRegType from )
{
RexB(0,from);
write8( 0xF7 );
ModRM( 3, 7, from );
}
emitterT void IDIV32R( x86IntRegType from ) { iSDIV( iRegister32(from) ); }
/* div eax by m32 to edx:eax */
emitterT void DIV32M( u32 from )
{
write8( 0xF7 );
ModRM( 0, 6, DISP32 );
write32( MEMADDR(from, 4) );
}
emitterT void DIV32M( u32 from ) { iUDIV( ptr32[from] ); }
/* idiv eax by m32 to edx:eax */
emitterT void IDIV32M( u32 from )
{
write8( 0xF7 );
ModRM( 0, 7, DISP32 );
write32( MEMADDR(from, 4) );
}
// shld imm8 to r32
emitterT void SHLD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift )
{
RexRB(0,from,to);
write8( 0x0F );
write8( 0xA4 );
ModRM( 3, from, to );
write8( shift );
}
// shrd imm8 to r32
emitterT void SHRD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift )
{
RexRB(0,from,to);
write8( 0x0F );
write8( 0xAC );
ModRM( 3, from, to );
write8( shift );
}
emitterT void IDIV32M( u32 from ) { iSDIV( ptr32[from] ); }
////////////////////////////////////
// logical instructions /
@ -1011,37 +989,3 @@ emitterT void BSWAP32R( x86IntRegType to )
write8( 0x0F );
write8( 0xC8 + to );
}
emitterT void LEA32RtoR(x86IntRegType to, x86IntRegType from, s32 offset)
{
iLEA( iRegister32( to ), ptr[x86IndexReg(from)+offset] );
}
emitterT void LEA32RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1)
{
iLEA( iRegister32( to ), ptr[x86IndexReg(from0)+x86IndexReg(from1)] );
}
// Don't inline recursive functions
emitterT void LEA32RStoR(x86IntRegType to, x86IntRegType from, u32 scale)
{
iLEA( iRegister32( to ), ptr[x86IndexReg(from)*(1<<scale)] );
}
// to = from + offset
emitterT void LEA16RtoR(x86IntRegType to, x86IntRegType from, s16 offset)
{
iLEA( iRegister16( to ), ptr[x86IndexReg(from)+offset] );
}
// to = from0 + from1
emitterT void LEA16RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1)
{
iLEA( iRegister16( to ), ptr[x86IndexReg(from0)+x86IndexReg(from1)] );
}
// to = from << scale (max is 3)
emitterT void LEA16RStoR(x86IntRegType to, x86IntRegType from, u32 scale)
{
iLEA( iRegister16( to ), ptr[x86IndexReg(from)*(1<<scale)] );
}

View File

@ -147,6 +147,7 @@ namespace x86Emitter
# define __noinline
#endif
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)
@ -233,32 +234,25 @@ namespace x86Emitter
typedef iRegister<2> iRegister16;
typedef iRegister<1> iRegister8;
extern const iRegister32 eax;
extern const iRegister32 ebx;
extern const iRegister32 ecx;
extern const iRegister32 edx;
extern const iRegister32 esi;
extern const iRegister32 edi;
extern const iRegister32 ebp;
extern const iRegister32 esp;
class iRegisterCL : public iRegister8
{
public:
iRegisterCL(): iRegister8( 1 ) {}
};
extern const iRegister16 ax;
extern const iRegister16 bx;
extern const iRegister16 cx;
extern const iRegister16 dx;
extern const iRegister16 si;
extern const iRegister16 di;
extern const iRegister16 bp;
extern const iRegister16 sp;
extern const iRegister32
eax, ebx, ecx, edx,
esi, edi, ebp, esp;
extern const iRegister8 al;
extern const iRegister8 cl;
extern const iRegister8 dl;
extern const iRegister8 bl;
extern const iRegister8 ah;
extern const iRegister8 ch;
extern const iRegister8 dh;
extern const iRegister8 bh;
extern const iRegister16
ax, bx, cx, dx,
si, di, bp, sp;
extern const iRegister8
al, dl, bl,
ah, ch, dh, bh;
extern const iRegisterCL cl; // I'm special!
//////////////////////////////////////////////////////////////////////////////////////////
// Use 32 bit registers as out index register (for ModSib memory address calculations)
@ -346,6 +340,13 @@ namespace x86Emitter
__forceinline iAddressInfo operator-( s32 imm ) const { return iAddressInfo( *this ).Add( -imm ); }
};
enum OperandSizeType
{
OpSize_8 = 1,
OpSize_16 = 2,
OpSize_32 = 4,
};
//////////////////////////////////////////////////////////////////////////////////////////
// ModSib - Internal low-level representation of the ModRM/SIB information.
//
@ -387,26 +388,64 @@ namespace x86Emitter
};
//////////////////////////////////////////////////////////////////////////////////////////
// Strictly-typed version of ModSibBase, which is used to apply operand size information
// to ImmToMem operations.
//
template< int OperandSize >
class ModSibStrict : public ModSibBase
class ModSibSized : public ModSibBase
{
public:
__forceinline explicit ModSibStrict( const iAddressInfo& src ) : ModSibBase( src ) {}
__forceinline explicit ModSibStrict( s32 disp ) : ModSibBase( disp ) {}
__forceinline ModSibStrict( x86IndexReg base, x86IndexReg index, int scale=0, s32 displacement=0 ) :
ModSibBase( base, index, scale, displacement ) {}
int OperandSize;
__forceinline ModSibStrict<OperandSize>& Add( s32 imm )
ModSibSized( int opsize, const iAddressInfo& src ) :
ModSibBase( src ),
OperandSize( opsize )
{
jASSUME( OperandSize == 1 || OperandSize == 2 || OperandSize == 4 );
}
ModSibSized( int opsize, s32 disp ) :
ModSibBase( disp ),
OperandSize( opsize )
{
jASSUME( OperandSize == 1 || OperandSize == 2 || OperandSize == 4 );
}
ModSibSized( int opsize, x86IndexReg base, x86IndexReg index, int scale=0, s32 displacement=0 ) :
ModSibBase( base, index, scale, displacement ),
OperandSize( opsize )
{
jASSUME( OperandSize == 1 || OperandSize == 2 || OperandSize == 4 );
}
__forceinline ModSibSized& Add( s32 imm )
{
Displacement += imm;
return *this;
}
__forceinline ModSibStrict<OperandSize> operator+( const s32 imm ) const { return ModSibStrict<OperandSize>( *this ).Add( imm ); }
__forceinline ModSibStrict<OperandSize> operator-( const s32 imm ) const { return ModSibStrict<OperandSize>( *this ).Add( -imm ); }
__forceinline ModSibSized operator+( const s32 imm ) const { return ModSibSized( *this ).Add( imm ); }
__forceinline ModSibSized operator-( const s32 imm ) const { return ModSibSized( *this ).Add( -imm ); }
};
//////////////////////////////////////////////////////////////////////////////////////////
// Strictly-typed version of ModSibBase, which is used to apply operand size information
// to ImmToMem operations.
//
template< int OpSize >
class ModSibStrict : public ModSibSized
{
public:
__forceinline explicit ModSibStrict( const iAddressInfo& src ) : ModSibSized( OpSize, src ) {}
__forceinline explicit ModSibStrict( s32 disp ) : ModSibSized( OpSize, disp ) {}
__forceinline ModSibStrict( x86IndexReg base, x86IndexReg index, int scale=0, s32 displacement=0 ) :
ModSibSized( OpSize, base, index, scale, displacement ) {}
__forceinline ModSibStrict<OpSize>& Add( s32 imm )
{
Displacement += imm;
return *this;
}
__forceinline ModSibStrict<OpSize> operator+( const s32 imm ) const { return ModSibStrict<OpSize>( *this ).Add( imm ); }
__forceinline ModSibStrict<OpSize> operator-( const s32 imm ) const { return ModSibStrict<OpSize>( *this ).Add( -imm ); }
};
//////////////////////////////////////////////////////////////////////////////////////////
@ -605,7 +644,8 @@ namespace x86Emitter
#include "ix86_impl_group1.h"
#include "ix86_impl_group2.h"
#include "ix86_impl_movs.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.
@ -675,8 +715,11 @@ namespace x86Emitter
extern const Internal::Group2ImplAll<Internal::G2Type_SHR> iSHR;
extern const Internal::Group2ImplAll<Internal::G2Type_SAR> iSAR;
extern const Internal::MovExtendImplAll<true> iMOVSX;
extern const Internal::MovExtendImplAll<false> iMOVZX;
extern const Internal::MovExtendImplAll<true> iMOVSX;
extern const Internal::DwordShiftImplAll<false> iSHLD;
extern const Internal::DwordShiftImplAll<true> iSHRD;
extern const Internal::CMovImplGeneric iCMOV;