mirror of https://github.com/PCSX2/pcsx2.git
Emitter rewrite, part 4 of 5: De-templificated all x86 base integer operations.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2142 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
285ead05ec
commit
2b5964199c
|
@ -203,6 +203,10 @@
|
|||
RelativePath="..\..\src\x86emitter\fpu.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\x86emitter\groups.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\x86emitter\jmp.cpp"
|
||||
>
|
||||
|
@ -215,6 +219,10 @@
|
|||
RelativePath="..\..\src\x86emitter\legacy_sse.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\x86emitter\movs.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\x86emitter\PrecompiledHeader.cpp"
|
||||
>
|
||||
|
@ -352,10 +360,6 @@
|
|||
RelativePath="..\..\include\x86emitter\implement\simd_shufflepack.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\x86emitter\implement\simd_templated_helpers.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
|
|
@ -15,38 +15,30 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// Implementations here cover SHLD and SHRD.
|
||||
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
||||
namespace x86Emitter {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementations here cover SHLD and SHRD.
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_DowrdShift
|
||||
// --------------------------------------------------------------------------------------
|
||||
// I use explicit method declarations here instead of templates, in order to provide
|
||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in SHLD/SHRD).
|
||||
//
|
||||
// Optimization Note: Imm shifts by 0 are ignore (no code generated). This is a safe optimization
|
||||
// because shifts by 0 do *not* affect flags status.
|
||||
// because shifts by 0 do *not* affect flags status (intel docs cited).
|
||||
//
|
||||
template< bool isShiftRight >
|
||||
class DwordShiftImplAll
|
||||
struct xImpl_DwordShift
|
||||
{
|
||||
static const u8 m_shiftop = isShiftRight ? 0x8 : 0;
|
||||
u16 OpcodeBase;
|
||||
|
||||
public:
|
||||
// ---------- 32 Bit Interface -----------
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister32& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0xa5 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister32& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister32& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, from, dest, shiftcnt ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, from, dest, shiftcnt ); }
|
||||
void operator()( const xRegister32& to, const xRegister32& from, const xRegisterCL& clreg ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from, const xRegisterCL& clreg ) const;
|
||||
void operator()( const xRegister32& to, const xRegister32& from, u8 shiftcnt ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from, u8 shiftcnt ) const;
|
||||
|
||||
// ---------- 16 Bit Interface -----------
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister16& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister16& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister16& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, from, dest ); }
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister16& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, to, from ); }
|
||||
__forceinline void operator()( void* dest, const xRegister16& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, from, dest, shiftcnt ); }
|
||||
__forceinline void operator()( const ModSibBase& dest, const xRegister16& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, from, dest, shiftcnt ); }
|
||||
|
||||
DwordShiftImplAll() {} // Why does GCC need these?
|
||||
void operator()( const ModSibBase& dest,const xRegister16or32& from, const xRegisterCL& clreg ) const;
|
||||
void operator()( const ModSibBase& dest,const xRegister16or32& from, u8 shiftcnt ) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
||||
// Instructions implemented in this header are as follows -->>
|
||||
namespace x86Emitter {
|
||||
|
||||
enum G1Type
|
||||
{
|
||||
|
@ -30,84 +29,23 @@ enum G1Type
|
|||
G1Type_CMP
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
template< G1Type InstType >
|
||||
class xImpl_Group1
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group1
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_Group1
|
||||
{
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __forceinline void operator()( const xRegister<T>& to, const xRegister<T>& from ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( (Is8BitOp<T>() ? 0 : 1) | (InstType<<3) );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
G1Type InstType;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __noinline void operator()( const ModSibBase& sibdest, const xRegister<T>& from ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( (Is8BitOp<T>() ? 0 : 1) | (InstType<<3) );
|
||||
EmitSibMagic( from, sibdest );
|
||||
}
|
||||
void operator()( const xRegister8& to, const xRegister8& from ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister32& to, const xRegister32& from ) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __noinline void operator()( const xRegister<T>& to, const ModSibBase& sibsrc ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( (Is8BitOp<T>() ? 2 : 3) | (InstType<<3) );
|
||||
EmitSibMagic( to, sibsrc );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Note on Imm forms : use int as the source operand since it's "reasonably inert" from a compiler
|
||||
// perspective. (using uint tends to make the compiler try and fail to match signed immediates with
|
||||
// one of the other overloads).
|
||||
|
||||
template< typename T > __noinline void operator()( const ModSibStrict<T>& sibdest, int imm ) const
|
||||
{
|
||||
if( Is8BitOp<T>() )
|
||||
{
|
||||
xWrite8( 0x80 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
xWrite<s8>( imm );
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( is_s8( imm ) ? 0x83 : 0x81 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
if( is_s8( imm ) )
|
||||
xWrite<s8>( imm );
|
||||
else
|
||||
xWrite<T>( imm );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __forceinline void operator()( const xRegister<T>& to, int imm ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
if( !Is8BitOp<T>() && is_s8( imm ) )
|
||||
{
|
||||
xWrite8( 0x83 );
|
||||
EmitSibMagic( InstType, to );
|
||||
xWrite<s8>( imm );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( to.IsAccumulator() )
|
||||
xWrite8( (Is8BitOp<T>() ? 4 : 5) | (InstType<<3) );
|
||||
else
|
||||
{
|
||||
xWrite8( Is8BitOp<T>() ? 0x80 : 0x81 );
|
||||
EmitSibMagic( InstType, to );
|
||||
}
|
||||
xWrite<T>( imm );
|
||||
}
|
||||
}
|
||||
void operator()( const ModSibBase& to, const xRegisterInt& from ) const;
|
||||
void operator()( const xRegisterInt& to, const ModSibBase& from ) const;
|
||||
void operator()( const xRegisterInt& to, int imm ) const;
|
||||
void operator()( const ModSib32orLess& to, int imm ) const;
|
||||
|
||||
#if 0
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __noinline void operator()( const ModSibBase& to, const xImmReg<T>& immOrReg ) const
|
||||
{
|
||||
|
@ -129,68 +67,83 @@ public:
|
|||
_DoI_helpermess( *this, to, from );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xRegister<T>& to, const xDirectOrIndirect<T>& from ) const
|
||||
// FIXME : Make this struct to 8, 16, and 32 bit registers
|
||||
template< typename T > __noinline void operator()( const xRegisterBase& to, const xDirectOrIndirect<T>& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, xDirectOrIndirect<T>( to ), from );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xRegister<T>& from ) const
|
||||
// FIXME : Make this struct to 8, 16, and 32 bit registers
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xRegisterBase& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
||||
}
|
||||
|
||||
xImpl_Group1() {} // Why does GCC need these?
|
||||
#endif
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// This class combines x86 with SSE/SSE2 logic operations (ADD, OR, and NOT).
|
||||
// Note: ANDN [AndNot] is handled below separately.
|
||||
//
|
||||
template< G1Type InstType, u16 OpcodeSSE >
|
||||
class xImpl_G1Logic : public xImpl_Group1<InstType>
|
||||
struct xImpl_G1Logic
|
||||
{
|
||||
public:
|
||||
using xImpl_Group1<InstType>::operator();
|
||||
G1Type InstType;
|
||||
|
||||
const SimdImpl_DestRegSSE<0x00,OpcodeSSE> PS; // packed single precision
|
||||
const SimdImpl_DestRegSSE<0x66,OpcodeSSE> PD; // packed double precision
|
||||
void operator()( const xRegister8& to, const xRegister8& from ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister32& to, const xRegister32& from ) const;
|
||||
|
||||
xImpl_G1Logic() {}
|
||||
void operator()( const ModSibBase& to, const xRegisterInt& from ) const;
|
||||
void operator()( const xRegisterInt& to, const ModSibBase& from ) const;
|
||||
void operator()( const xRegisterInt& to, int imm ) const;
|
||||
|
||||
void operator()( const ModSib32orLess& to, int imm ) const;
|
||||
|
||||
xImplSimd_DestRegSSE PS; // packed single precision
|
||||
xImplSimd_DestRegSSE PD; // packed double precision
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// This class combines x86 with SSE/SSE2 arithmetic operations (ADD/SUB).
|
||||
//
|
||||
template< G1Type InstType, u16 OpcodeSSE >
|
||||
class xImpl_G1Arith : public xImpl_G1Logic<InstType, OpcodeSSE >
|
||||
struct xImpl_G1Arith
|
||||
{
|
||||
public:
|
||||
using xImpl_Group1<InstType>::operator();
|
||||
G1Type InstType;
|
||||
|
||||
const SimdImpl_DestRegSSE<0xf3,OpcodeSSE> SS; // scalar single precision
|
||||
const SimdImpl_DestRegSSE<0xf2,OpcodeSSE> SD; // scalar double precision
|
||||
void operator()( const xRegister8& to, const xRegister8& from ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister32& to, const xRegister32& from ) const;
|
||||
|
||||
xImpl_G1Arith() {}
|
||||
void operator()( const ModSibBase& to, const xRegisterInt& from ) const;
|
||||
void operator()( const xRegisterInt& to, const ModSibBase& from ) const;
|
||||
void operator()( const xRegisterInt& to, int imm ) const;
|
||||
|
||||
void operator()( const ModSib32orLess& to, int imm ) const;
|
||||
|
||||
xImplSimd_DestRegSSE PS; // packed single precision
|
||||
xImplSimd_DestRegSSE PD; // packed double precision
|
||||
xImplSimd_DestRegSSE SS; // scalar single precision
|
||||
xImplSimd_DestRegSSE SD; // scalar double precision
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
class xImpl_G1Compare : xImpl_Group1< G1Type_CMP >
|
||||
struct xImpl_G1Compare
|
||||
{
|
||||
protected:
|
||||
template< u8 Prefix > struct Woot
|
||||
{
|
||||
__forceinline void operator()( const xRegisterSSE& to, const xRegisterSSE& from, SSE2_ComparisonType cmptype ) const{ xOpWrite0F( Prefix, 0xc2, to, from, (u8)cmptype ); }
|
||||
__forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from, SSE2_ComparisonType cmptype ) const { xOpWrite0F( Prefix, 0xc2, to, from, (u8)cmptype ); }
|
||||
Woot() {}
|
||||
};
|
||||
void operator()( const xRegister8& to, const xRegister8& from ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister32& to, const xRegister32& from ) const;
|
||||
|
||||
public:
|
||||
using xImpl_Group1<G1Type_CMP>::operator();
|
||||
void operator()( const ModSibBase& to, const xRegisterInt& from ) const;
|
||||
void operator()( const xRegisterInt& to, const ModSibBase& from ) const;
|
||||
void operator()( const xRegisterInt& to, int imm ) const;
|
||||
|
||||
const Woot<0x00> PS;
|
||||
const Woot<0x66> PD;
|
||||
const Woot<0xf3> SS;
|
||||
const Woot<0xf2> SD;
|
||||
void operator()( const ModSib32orLess& to, int imm ) const;
|
||||
|
||||
xImpl_G1Compare() {} //GCWhat?
|
||||
xImplSimd_DestSSE_CmpImm PS;
|
||||
xImplSimd_DestSSE_CmpImm PD;
|
||||
xImplSimd_DestSSE_CmpImm SS;
|
||||
xImplSimd_DestSSE_CmpImm SD;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
||||
// Instructions implemented in this header are as follows -->>
|
||||
namespace x86Emitter {
|
||||
|
||||
enum G2Type
|
||||
{
|
||||
|
@ -30,73 +29,23 @@ enum G2Type
|
|||
G2Type_SAR
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group2
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Group 2 (shift) instructions have no Sib/ModRM forms.
|
||||
// Optimization Note: For Imm forms, we ignore the instruction if the shift count is zero.
|
||||
// This is a safe optimization since any zero-value shift does not affect any flags.
|
||||
//
|
||||
template< G2Type InstType >
|
||||
class Group2ImplAll
|
||||
struct xImpl_Group2
|
||||
{
|
||||
public:
|
||||
template< typename T > __forceinline void operator()( const xRegister<T>& to, const xRegisterCL& /* from */ ) const
|
||||
{
|
||||
//if( !Is8BitOp<T>() )
|
||||
// pxAssert( to != xRegister<T>( ebp.Id ) );
|
||||
G2Type InstType;
|
||||
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0xd2 : 0xd3 );
|
||||
EmitSibMagic( InstType, to );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const ModSibStrict<T>& sibdest, const xRegisterCL& /* from */ ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0xd2 : 0xd3 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const ModSibStrict<T>& sibdest, u8 imm ) const
|
||||
{
|
||||
if( imm == 0 ) return;
|
||||
|
||||
prefix16<T>();
|
||||
if( imm == 1 )
|
||||
{
|
||||
// special encoding of 1's
|
||||
xWrite8( Is8BitOp<T>() ? 0xd0 : 0xd1 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
}
|
||||
else
|
||||
{
|
||||
xWrite8( Is8BitOp<T>() ? 0xc0 : 0xc1 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
xWrite8( imm );
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T > __forceinline void operator()( const xRegister<T>& to, u8 imm ) const
|
||||
{
|
||||
if( imm == 0 ) return;
|
||||
|
||||
//if( !Is8BitOp<T>() )
|
||||
// pxAssert( to != xRegister<T>( ebp.Id ) );
|
||||
|
||||
prefix16<T>();
|
||||
if( imm == 1 )
|
||||
{
|
||||
// special encoding of 1's
|
||||
xWrite8( Is8BitOp<T>() ? 0xd0 : 0xd1 );
|
||||
EmitSibMagic( InstType, to );
|
||||
}
|
||||
else
|
||||
{
|
||||
xWrite8( Is8BitOp<T>() ? 0xc0 : 0xc1 );
|
||||
EmitSibMagic( InstType, to );
|
||||
xWrite8( imm );
|
||||
}
|
||||
}
|
||||
void operator()( const xRegisterInt& to, const xRegisterCL& from ) const;
|
||||
void operator()( const ModSib32orLess& to, const xRegisterCL& from ) const;
|
||||
void operator()( const xRegisterInt& to, u8 imm ) const;
|
||||
void operator()( const ModSib32orLess& to, u8 imm ) const;
|
||||
|
||||
#if 0
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, u8 imm ) const
|
||||
{
|
||||
|
@ -107,7 +56,7 @@ public:
|
|||
{
|
||||
_DoI_helpermess( *this, to, from );
|
||||
}
|
||||
|
||||
|
||||
Group2ImplAll() {} // I am a class with no members, so I need an explicit constructor! Sense abounds.
|
||||
#endif
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
||||
// Instructions implemented in this header are as follows -->>
|
||||
namespace x86Emitter {
|
||||
|
||||
enum G3Type
|
||||
{
|
||||
|
@ -28,84 +27,83 @@ enum G3Type
|
|||
G3Type_iDIV = 7
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
template< G3Type InstType >
|
||||
class xImpl_Group3
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group3
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_Group3
|
||||
{
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __emitinline void operator()( const xRegister<T>& from ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8(Is8BitOp<T>() ? 0xf6 : 0xf7 );
|
||||
EmitSibMagic( InstType, from );
|
||||
}
|
||||
G3Type InstType;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __emitinline void operator()( const ModSibStrict<T>& from ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0xf6 : 0xf7 );
|
||||
EmitSibMagic( InstType, from );
|
||||
}
|
||||
void operator()( const xRegisterInt& from ) const;
|
||||
void operator()( const ModSib32orLess& from ) const;
|
||||
|
||||
template< typename T > __emitinline void operator()( const xDirectOrIndirect<T>& from ) const
|
||||
#if 0
|
||||
template< typename T >
|
||||
void operator()( const xDirectOrIndirect<T>& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, from );
|
||||
}
|
||||
xImpl_Group3() {}
|
||||
#endif
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MulDivBase
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV.
|
||||
//
|
||||
template< G3Type InstType, u16 OpcodeSSE >
|
||||
class ImplMulDivBase : public xImpl_Group3<InstType>
|
||||
struct xImpl_MulDivBase
|
||||
{
|
||||
public:
|
||||
ImplMulDivBase() {}
|
||||
const SimdImpl_DestRegSSE<0x00,OpcodeSSE> PS;
|
||||
const SimdImpl_DestRegSSE<0x66,OpcodeSSE> PD;
|
||||
const SimdImpl_DestRegSSE<0xf3,OpcodeSSE> SS;
|
||||
const SimdImpl_DestRegSSE<0xf2,OpcodeSSE> SD;
|
||||
G3Type InstType;
|
||||
u16 OpcodeSSE;
|
||||
|
||||
void operator()( const xRegisterInt& from ) const;
|
||||
void operator()( const ModSib32orLess& from ) const;
|
||||
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_iDiv
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_iDiv
|
||||
{
|
||||
void operator()( const xRegisterInt& from ) const;
|
||||
void operator()( const ModSib32orLess& from ) const;
|
||||
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_iMul
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
class xImpl_iDiv : public ImplMulDivBase<G3Type_iDIV,0x5e>
|
||||
struct xImpl_iMul
|
||||
{
|
||||
public:
|
||||
using ImplMulDivBase<G3Type_iDIV,0x5e>::operator();
|
||||
void operator()( const xRegisterInt& from ) const;
|
||||
void operator()( const ModSib32orLess& from ) const;
|
||||
|
||||
// The following iMul-specific forms are valid for 16 and 32 bit register operands only!
|
||||
|
||||
void operator()( const xRegister32& to, const xRegister32& from ) const;
|
||||
void operator()( const xRegister32& to, const ModSibBase& src ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister16& to, const ModSibBase& src ) const;
|
||||
|
||||
void operator()( const xRegister32& to, const xRegister32& from, s32 imm ) const;
|
||||
void operator()( const xRegister32& to, const ModSibBase& from, s32 imm ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from, s16 imm ) const;
|
||||
void operator()( const xRegister16& to, const ModSibBase& from, s16 imm ) const;
|
||||
|
||||
const xImplSimd_DestRegSSE PS;
|
||||
const xImplSimd_DestRegSSE PD;
|
||||
const xImplSimd_DestRegSSE SS;
|
||||
const xImplSimd_DestRegSSE SD;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// The following iMul-specific forms are valid for 16 and 32 bit register operands only!
|
||||
//
|
||||
class xImpl_iMul : public ImplMulDivBase<G3Type_iMUL,0x59>
|
||||
{
|
||||
template< typename T1, typename T2, typename ImmType >
|
||||
static __forceinline void ImmStyle( const T1& param1, const T2& param2, ImmType imm8 )
|
||||
{
|
||||
xOpWrite0F( (sizeof(ImmType) == 2) ? 0x66 : 0, is_s8( imm8 ) ? 0x6b : 0x69, param1, param2 );
|
||||
if( is_s8( imm8 ) )
|
||||
xWrite8( (u8)imm8 );
|
||||
else
|
||||
xWrite<ImmType>( imm8 );
|
||||
}
|
||||
|
||||
public:
|
||||
using ImplMulDivBase<G3Type_iMUL,0x59>::operator();
|
||||
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { xOpWrite0F( 0xaf, to, from ); }
|
||||
__forceinline void operator()( const xRegister32& to, const ModSibBase& src ) const { xOpWrite0F( 0xaf, to, src ); }
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister32& from, s32 imm ) const{ ImmStyle( to, from, imm ); }
|
||||
__forceinline void operator()( const xRegister32& to, const ModSibBase& from, s32 imm ) const { ImmStyle( to, from, imm ); }
|
||||
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister16& from ) const { xOpWrite0F( 0x66, 0xaf, to, from ); }
|
||||
__forceinline void operator()( const xRegister16& to, const ModSibBase& src ) const { xOpWrite0F( 0x66, 0xaf, to, src ); }
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister16& from, s16 imm ) const{ ImmStyle( to, from, imm ); }
|
||||
__forceinline void operator()( const xRegister16& to, const ModSibBase& from, s16 imm ) const { ImmStyle( to, from, imm ); }
|
||||
|
||||
xImpl_iMul() {}
|
||||
};
|
||||
}
|
|
@ -13,83 +13,16 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// helpers.h -- Various universally helpful functions for emitter convenience!
|
||||
//
|
||||
// Note: Header file should be included from the x86Emitter::Internal namespace, such
|
||||
// that all members contained within are in said namespace.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#define OpWriteSSE( pre, op ) xOpWrite0F( pre, op, to, from )
|
||||
namespace x86Emitter {
|
||||
|
||||
extern void SimdPrefix( u8 prefix, u16 opcode );
|
||||
extern void EmitSibMagic( uint regfield, const void* address );
|
||||
extern void EmitSibMagic( uint regfield, const ModSibBase& info );
|
||||
extern void xJccKnownTarget( JccComparisonType comparison, const void* target, bool slideForward );
|
||||
// helpermess is currently broken >_<
|
||||
|
||||
template< typename T > bool Is8BitOp() { return sizeof(T) == 1; }
|
||||
template< typename T > void prefix16() { if( sizeof(T) == 2 ) xWrite8( 0x66 ); }
|
||||
|
||||
|
||||
// Writes a ModRM byte for "Direct" register access forms, which is used for all
|
||||
// instructions taking a form of [reg,reg].
|
||||
template< typename T > __emitinline
|
||||
void EmitSibMagic( uint reg1, const xRegisterBase<T>& reg2 )
|
||||
{
|
||||
xWrite8( (Mod_Direct << 6) | (reg1 << 3) | reg2.Id );
|
||||
}
|
||||
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void EmitSibMagic( const xRegisterBase<T1> reg1, const xRegisterBase<T2>& reg2 )
|
||||
{
|
||||
xWrite8( (Mod_Direct << 6) | (reg1.Id << 3) | reg2.Id );
|
||||
}
|
||||
|
||||
template< typename T1 > __emitinline
|
||||
void EmitSibMagic( const xRegisterBase<T1> reg1, const void* src ) { EmitSibMagic( reg1.Id, src ); }
|
||||
|
||||
template< typename T1 > __emitinline
|
||||
void EmitSibMagic( const xRegisterBase<T1> reg1, const ModSibBase& sib ) { EmitSibMagic( reg1.Id, sib ); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite( u8 prefix, u8 opcode, const T1& param1, const T2& param2 )
|
||||
{
|
||||
if( prefix != 0 )
|
||||
xWrite16( (opcode<<8) | prefix );
|
||||
else
|
||||
xWrite8( opcode );
|
||||
|
||||
EmitSibMagic( param1, param2 );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite0F( u8 prefix, u16 opcode, const T1& param1, const T2& param2 )
|
||||
{
|
||||
SimdPrefix( prefix, opcode );
|
||||
EmitSibMagic( param1, param2 );
|
||||
}
|
||||
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite0F( u8 prefix, u16 opcode, const T1& param1, const T2& param2, u8 imm8 )
|
||||
{
|
||||
xOpWrite0F( prefix, opcode, param1, param2 );
|
||||
xWrite8( imm8 );
|
||||
}
|
||||
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite0F( u16 opcode, const T1& param1, const T2& param2 ) { xOpWrite0F( 0, opcode, param1, param2 ); }
|
||||
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite0F( u16 opcode, const T1& param1, const T2& param2, u8 imm8 ) { xOpWrite0F( 0, opcode, param1, param2, imm8 ); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
#if 0
|
||||
|
||||
template< typename xImpl, typename T >
|
||||
void _DoI_helpermess( const xImpl& helpme, const xDirectOrIndirect<T>& to, const xImmReg<T>& immOrReg )
|
||||
void _DoI_helpermess( const xImpl& helpme, const xDirectOrIndirect& to, const xImmReg<T>& immOrReg )
|
||||
{
|
||||
if( to.IsDirect() )
|
||||
{
|
||||
|
@ -113,7 +46,7 @@ void _DoI_helpermess( const xImpl& helpme, const ModSibBase& to, const xImmReg<T
|
|||
if( immOrReg.IsReg() )
|
||||
helpme( to, immOrReg.GetReg() );
|
||||
else
|
||||
helpme( ModSibStrict<T>(to), immOrReg.GetImm() );
|
||||
helpme( (ModSibStrict)to, immOrReg.GetImm() );
|
||||
}
|
||||
|
||||
template< typename xImpl, typename T >
|
||||
|
@ -153,3 +86,6 @@ void _DoI_helpermess( const xImpl& helpme, const xDirectOrIndirect<T>& to, const
|
|||
|
||||
pxFailDev( "Invalid asm instruction: Both operands are indirect memory addresses." );
|
||||
}
|
||||
#endif
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -16,35 +16,19 @@
|
|||
#pragma once
|
||||
|
||||
// Implementations found here: Increment and Decrement Instructions!
|
||||
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
||||
// (They're soooo lonely... but I dunno where else to stick this class!)
|
||||
|
||||
namespace x86Emitter {
|
||||
|
||||
template< bool isDec >
|
||||
class xImpl_IncDec
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_IncDec
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct xImpl_IncDec
|
||||
{
|
||||
public:
|
||||
template< typename T >
|
||||
__forceinline void operator()( const xRegister<T>& to ) const
|
||||
{
|
||||
if( Is8BitOp<T>() )
|
||||
{
|
||||
xWrite8( 0xfe );
|
||||
EmitSibMagic( isDec ? 1 : 0, to );
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( (isDec ? 0x48 : 0x40) | to.Id );
|
||||
}
|
||||
}
|
||||
bool isDec;
|
||||
|
||||
template< typename T >
|
||||
__forceinline void operator()( const ModSibStrict<T>& sibdest ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0xfe : 0xff );
|
||||
EmitSibMagic( isDec ? 1 : 0, sibdest );
|
||||
}
|
||||
|
||||
xImpl_IncDec() {} // don't ask.
|
||||
void operator()( const xRegisterInt& to ) const;
|
||||
void operator()( const ModSib32orLess& to ) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
#pragma once
|
||||
|
||||
// Implementations found here: CALL and JMP! (unconditional only)
|
||||
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
||||
|
||||
namespace x86Emitter {
|
||||
|
||||
#ifdef __GNUG__
|
||||
// GCC has a bug that causes the templated function handler for Jmp/Call emitters to generate
|
||||
|
@ -29,18 +30,18 @@
|
|||
# define __always_inline_tmpl_fail
|
||||
#endif
|
||||
|
||||
extern void xJccKnownTarget( JccComparisonType comparison, const void* target, bool slideForward );
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< bool isJmp >
|
||||
class xImpl_JmpCall
|
||||
struct xImpl_JmpCall
|
||||
{
|
||||
public:
|
||||
xImpl_JmpCall() {}
|
||||
bool isJmp;
|
||||
|
||||
__forceinline void operator()( const xRegister32& absreg ) const { xOpWrite( 0x00, 0xff, isJmp ? 4 : 2, absreg ); }
|
||||
__forceinline void operator()( const ModSibStrict<u32>& src ) const { xOpWrite( 0x00, 0xff, isJmp ? 4 : 2, src ); }
|
||||
void operator()( const xRegister32& absreg ) const;
|
||||
void operator()( const ModSib32& src ) const;
|
||||
|
||||
__forceinline void operator()( const xRegister16& absreg ) const { xOpWrite( 0x66, 0xff, isJmp ? 4 : 2, absreg ); }
|
||||
__forceinline void operator()( const ModSibStrict<u16>& src ) const { xOpWrite( 0x66, 0xff, isJmp ? 4 : 2, src ); }
|
||||
void operator()( const xRegister16& absreg ) const;
|
||||
void operator()( const ModSib16& src ) const;
|
||||
|
||||
// Special form for calling functions. This form automatically resolves the
|
||||
// correct displacement based on the size of the instruction being generated.
|
||||
|
@ -61,3 +62,5 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
||||
|
|
|
@ -18,92 +18,27 @@
|
|||
// Header: ix86_impl_movs.h -- covers mov, cmov, movsx/movzx, and SETcc (which shares
|
||||
// with cmov many similarities).
|
||||
|
||||
namespace x86Emitter {
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MovImplAll
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MOV instruction Implementation, plus many SIMD sub-mov variants.
|
||||
|
||||
class MovImplAll
|
||||
//
|
||||
struct xImpl_Mov
|
||||
{
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __forceinline void operator()( const xRegister<T>& to, const xRegister<T>& from ) const
|
||||
{
|
||||
if( to == from ) return; // ignore redundant MOVs.
|
||||
xImpl_Mov() {} // Satisfy GCC's whims.
|
||||
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0x88 : 0x89 );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
void operator()( const xRegister8& to, const xRegister8& from ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister32& to, const xRegister32& from ) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __noinline void operator()( const ModSibBase& dest, const xRegister<T>& from ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
void operator()( const ModSibBase& dest, const xRegisterInt& from ) const;
|
||||
void operator()( const xRegisterInt& to, const ModSibBase& src ) const;
|
||||
void operator()( const ModSib32orLess& dest, int imm ) const;
|
||||
void operator()( const xRegisterInt& to, int imm, bool preserve_flags=false ) const;
|
||||
|
||||
// mov eax has a special from when writing directly to a DISP32 address
|
||||
// (sans any register index/base registers).
|
||||
|
||||
if( from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty() )
|
||||
{
|
||||
xWrite8( Is8BitOp<T>() ? 0xa2 : 0xa3 );
|
||||
xWrite32( dest.Displacement );
|
||||
}
|
||||
else
|
||||
{
|
||||
xWrite8( Is8BitOp<T>() ? 0x88 : 0x89 );
|
||||
EmitSibMagic( from.Id, dest );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __noinline void operator()( const xRegister<T>& to, const ModSibBase& src ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
|
||||
// mov eax has a special from when reading directly from a DISP32 address
|
||||
// (sans any register index/base registers).
|
||||
|
||||
if( to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty() )
|
||||
{
|
||||
xWrite8( Is8BitOp<T>() ? 0xa0 : 0xa1 );
|
||||
xWrite32( src.Displacement );
|
||||
}
|
||||
else
|
||||
{
|
||||
xWrite8( Is8BitOp<T>() ? 0x8a : 0x8b );
|
||||
EmitSibMagic( to, src );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __noinline void operator()( const ModSibStrict<T>& dest, int imm ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0xc6 : 0xc7 );
|
||||
EmitSibMagic( 0, dest );
|
||||
xWrite<T>( imm );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// preserve_flags - set to true to disable optimizations which could alter the state of
|
||||
// the flags (namely replacing mov reg,0 with xor).
|
||||
template< typename T > __emitinline void operator()( const xRegister<T>& to, int imm, bool preserve_flags=false ) const
|
||||
{
|
||||
if( !preserve_flags && (imm == 0) )
|
||||
xXOR( to, to );
|
||||
else
|
||||
{
|
||||
// Note: MOV does not have (reg16/32,imm8) forms.
|
||||
|
||||
prefix16<T>();
|
||||
xWrite8( (Is8BitOp<T>() ? 0xb0 : 0xb8) | to.Id );
|
||||
xWrite<T>( imm );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
#if 0
|
||||
template< typename T > __noinline void operator()( const ModSibBase& to, const xImmReg<T>& immOrReg ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, immOrReg );
|
||||
|
@ -125,7 +60,7 @@ public:
|
|||
_DoI_helpermess( *this, to, from );
|
||||
}
|
||||
|
||||
template< typename T > __noinline void operator()( const xRegister<T>& to, const xDirectOrIndirect<T>& from ) const
|
||||
/*template< typename T > __noinline void operator()( const xRegister<T>& to, const xDirectOrIndirect<T>& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, xDirectOrIndirect<T>( to ), from );
|
||||
}
|
||||
|
@ -133,16 +68,15 @@ public:
|
|||
template< typename T > __noinline void operator()( const xDirectOrIndirect<T>& to, const xRegister<T>& from ) const
|
||||
{
|
||||
_DoI_helpermess( *this, to, xDirectOrIndirect<T>( from ) );
|
||||
}
|
||||
|
||||
MovImplAll() {} // Satisfy GCC's whims.
|
||||
}*/
|
||||
#endif
|
||||
};
|
||||
|
||||
#define ccSane() pxAssertDev( ccType >= 0 && ccType <= 0x0f, "Invalid comparison type specifier." )
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CMOV !! [in all of it's disappointing lack-of glory] .. and ..
|
||||
// SETcc!! [more glory, less lack!]
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_CMov
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CMOVcc !! [in all of it's disappointing lack-of glory] .. and ..
|
||||
// SETcc !! [more glory, less lack!]
|
||||
//
|
||||
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
|
||||
// realize that it cannot load immediate values into registers. -_-
|
||||
|
@ -150,92 +84,67 @@ public:
|
|||
// I use explicit method declarations here instead of templates, in order to provide
|
||||
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV).
|
||||
//
|
||||
class CMovImplGeneric
|
||||
|
||||
struct xImpl_CMov
|
||||
{
|
||||
public:
|
||||
__forceinline void operator()( JccComparisonType ccType, const xRegister32& to, const xRegister32& from ) const { ccSane(); xOpWrite0F( 0x40 | ccType, to, from ); }
|
||||
__noinline void operator()( JccComparisonType ccType, const xRegister32& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x40 | ccType, to, sibsrc ); }
|
||||
//__noinline void operator()( JccComparisonType ccType, const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); } // too.. lazy.. to fix.
|
||||
JccComparisonType ccType;
|
||||
|
||||
__forceinline void operator()( JccComparisonType ccType, const xRegister16& to, const xRegister16& from ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, from ); }
|
||||
__noinline void operator()( JccComparisonType ccType, const xRegister16& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, sibsrc ); }
|
||||
//__noinline void operator()( JccComparisonType ccType, const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
void operator()( const xRegister32& to, const xRegister32& from ) const;
|
||||
void operator()( const xRegister32& to, const ModSibBase& sibsrc ) const;
|
||||
|
||||
CMovImplGeneric() {} // don't ask.
|
||||
void operator()( const xRegister16& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister16& to, const ModSibBase& sibsrc ) const;
|
||||
|
||||
//void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from );
|
||||
//void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< JccComparisonType ccType >
|
||||
class CMovImplAll
|
||||
struct xImpl_Set
|
||||
{
|
||||
static const u16 Opcode = 0x40 | ccType;
|
||||
JccComparisonType ccType;
|
||||
|
||||
public:
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { ccSane(); xOpWrite0F( Opcode, to, from ); }
|
||||
__noinline void operator()( const xRegister32& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( Opcode, to, sibsrc ); }
|
||||
__noinline void operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
void operator()( const xRegister8& to ) const;
|
||||
void operator()( const ModSib8& dest ) const;
|
||||
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister16& from ) const { ccSane(); xOpWrite0F( 0x66, Opcode, to, from ); }
|
||||
__noinline void operator()( const xRegister16& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x66, Opcode, to, sibsrc ); }
|
||||
__noinline void operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
|
||||
CMovImplAll() {} // don't ask.
|
||||
//void operator()( const xDirectOrIndirect8& dest ) const;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
class SetImplGeneric
|
||||
{
|
||||
// note: SETcc are 0x90, with 0 in the Reg field of ModRM.
|
||||
public:
|
||||
__forceinline void operator()( JccComparisonType ccType, const xRegister8& to ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, to ); }
|
||||
__noinline void operator()( JccComparisonType ccType, const ModSibStrict<u8>& dest ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, dest ); }
|
||||
|
||||
SetImplGeneric() {} // if you do, ask GCC.
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< JccComparisonType ccType >
|
||||
class SetImplAll
|
||||
{
|
||||
static const u16 Opcode = 0x90 | ccType; // SETcc are 0x90 base opcode, with 0 in the Reg field of ModRM.
|
||||
|
||||
public:
|
||||
__forceinline void operator()( const xRegister8& to ) const { ccSane(); xOpWrite0F( Opcode, 0, to ); }
|
||||
__noinline void operator()( const ModSibStrict<u8>& dest ) const { ccSane(); xOpWrite0F( Opcode, 0, dest ); }
|
||||
__noinline void operator()( const xDirectOrIndirect8& dest ) const { ccSane(); _DoI_helpermess( *this, dest ); }
|
||||
|
||||
SetImplAll() {} // if you do, ask GCC.
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Mov with sign/zero extension implementations (movsx / movzx)
|
||||
//
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< bool SignExtend >
|
||||
class MovExtendImplAll
|
||||
class xRegister16or32
|
||||
{
|
||||
protected:
|
||||
static const u16 Opcode = 0xb6 | (SignExtend ? 8 : 0 );
|
||||
|
||||
// Macro useful for trapping unwanted use of EBP.
|
||||
//#define EbpAssert() pxAssert( to != ebp )
|
||||
#define EbpAssert()
|
||||
const xRegisterInt& m_convtype;
|
||||
|
||||
public:
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister16& from ) const { EbpAssert(); xOpWrite0F( Opcode+1, to, from ); }
|
||||
__noinline void operator()( const xRegister32& to, const ModSibStrict<u16>& sibsrc ) const { EbpAssert(); xOpWrite0F( Opcode+1, to, sibsrc ); }
|
||||
__noinline void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const { EbpAssert(); _DoI_helpermess( *this, to, src ); }
|
||||
xRegister16or32( const xRegister32& src ) : m_convtype( src ) {}
|
||||
xRegister16or32( const xRegister16& src ) : m_convtype( src ) {}
|
||||
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister8& from ) const { EbpAssert(); xOpWrite0F( Opcode, to, from ); }
|
||||
__noinline void operator()( const xRegister32& to, const ModSibStrict<u8>& sibsrc ) const { EbpAssert(); xOpWrite0F( Opcode, to, sibsrc ); }
|
||||
__noinline void operator()( const xRegister32& to, const xDirectOrIndirect8& src ) const { EbpAssert(); _DoI_helpermess( *this, to, src ); }
|
||||
//operator const xRegisterInt&() const { return m_convtype; }
|
||||
operator const xRegisterBase&() const { return m_convtype; }
|
||||
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister8& from ) const { xOpWrite0F( 0x66, Opcode, to, from ); }
|
||||
__noinline void operator()( const xRegister16& to, const ModSibStrict<u8>& sibsrc ) const { xOpWrite0F( 0x66, Opcode, to, sibsrc ); }
|
||||
__noinline void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const { _DoI_helpermess( *this, to, src ); }
|
||||
|
||||
MovExtendImplAll() {} // don't ask.
|
||||
const xRegisterInt* operator->() const
|
||||
{
|
||||
return &m_convtype;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_MovExtend
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Mov with sign/zero extension implementations (movsx / movzx)
|
||||
//
|
||||
struct xImpl_MovExtend
|
||||
{
|
||||
bool SignExtend;
|
||||
|
||||
void operator()( const xRegister16or32& to, const xRegister8& from ) const;
|
||||
void operator()( const xRegister16or32& to, const ModSib8& sibsrc ) const;
|
||||
void operator()( const xRegister32& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister32& to, const ModSib16& sibsrc ) const;
|
||||
|
||||
//void operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const;
|
||||
//void operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const;
|
||||
//void operator()( const xRegister16& to, const xDirectOrIndirect8& src ) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -47,6 +47,15 @@ struct xImplSimd_DestRegImmSSE
|
|||
void operator()( const xRegisterSSE& to, const ModSibBase& from, u8 imm ) const;
|
||||
};
|
||||
|
||||
struct xImplSimd_DestSSE_CmpImm
|
||||
{
|
||||
u8 Prefix;
|
||||
u16 Opcode;
|
||||
|
||||
void operator()( const xRegisterSSE& to, const xRegisterSSE& from, SSE2_ComparisonType imm ) const;
|
||||
void operator()( const xRegisterSSE& to, const ModSibBase& from, SSE2_ComparisonType imm ) const;
|
||||
};
|
||||
|
||||
struct xImplSimd_DestRegImmMMX
|
||||
{
|
||||
u8 Prefix;
|
||||
|
|
|
@ -142,32 +142,32 @@ struct xImplSimd_PMove
|
|||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into word integers
|
||||
// and store them in dest.
|
||||
void BW( const xRegisterSSE& to, const xRegisterSSE& from ) const;
|
||||
void BW( const xRegisterSSE& to, const ModSibStrict<u64>& from ) const;
|
||||
void BW( const xRegisterSSE& to, const ModSib64& from ) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into dword integers
|
||||
// and store them in dest.
|
||||
void BD( const xRegisterSSE& to, const xRegisterSSE& from ) const;
|
||||
void BD( const xRegisterSSE& to, const ModSibStrict<u32>& from ) const;
|
||||
void BD( const xRegisterSSE& to, const ModSib32& from ) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low byte values in src into qword integers
|
||||
// and store them in dest.
|
||||
void BQ( const xRegisterSSE& to, const xRegisterSSE& from ) const;
|
||||
void BQ( const xRegisterSSE& to, const ModSibStrict<u16>& from ) const;
|
||||
void BQ( const xRegisterSSE& to, const ModSib16& from ) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into dword integers
|
||||
// and store them in dest.
|
||||
void WD( const xRegisterSSE& to, const xRegisterSSE& from ) const;
|
||||
void WD( const xRegisterSSE& to, const ModSibStrict<u64>& from ) const;
|
||||
void WD( const xRegisterSSE& to, const ModSib64& from ) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low word values in src into qword integers
|
||||
// and store them in dest.
|
||||
void WQ( const xRegisterSSE& to, const xRegisterSSE& from ) const;
|
||||
void WQ( const xRegisterSSE& to, const ModSibStrict<u32>& from ) const;
|
||||
void WQ( const xRegisterSSE& to, const ModSib32& from ) const;
|
||||
|
||||
// [SSE-4.1] Zero/Sign-extend the low dword values in src into qword integers
|
||||
// and store them in dest.
|
||||
void DQ( const xRegisterSSE& to, const xRegisterSSE& from ) const;
|
||||
void DQ( const xRegisterSSE& to, const ModSibStrict<u64>& from ) const;
|
||||
void DQ( const xRegisterSSE& to, const ModSib64& from ) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -16,50 +16,20 @@
|
|||
#pragma once
|
||||
|
||||
// Implementations found here: TEST + BTS/BT/BTC/BTR + BSF/BSR! (for lack of better location)
|
||||
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TEST instruction Implementation
|
||||
namespace x86Emitter {
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Test
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
class xImpl_Test
|
||||
struct xImpl_Test
|
||||
{
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __forceinline
|
||||
void operator()( const xRegister<T>& to, const xRegister<T>& from ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0x84 : 0x85 );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __forceinline
|
||||
void operator()( const ModSibStrict<T>& dest, int imm ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
xWrite8( Is8BitOp<T>() ? 0xf6 : 0xf7 );
|
||||
EmitSibMagic( 0, dest );
|
||||
xWrite<T>( imm );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename T > __forceinline
|
||||
void operator()( const xRegister<T>& to, int imm ) const
|
||||
{
|
||||
prefix16<T>();
|
||||
|
||||
if( to.IsAccumulator() )
|
||||
xWrite8( Is8BitOp<T>() ? 0xa8 : 0xa9 );
|
||||
else
|
||||
{
|
||||
xWrite8( Is8BitOp<T>() ? 0xf6 : 0xf7 );
|
||||
EmitSibMagic( 0, to );
|
||||
}
|
||||
xWrite<T>( imm );
|
||||
}
|
||||
|
||||
xImpl_Test() {} // Why does GCC need these?
|
||||
void operator()( const xRegister8& to, const xRegister8& from ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister32& to, const xRegister32& from ) const;
|
||||
void operator()( const ModSib32orLess& dest, int imm ) const;
|
||||
void operator()( const xRegisterInt& to, int imm ) const;
|
||||
};
|
||||
|
||||
enum G8Type
|
||||
|
@ -70,40 +40,38 @@ enum G8Type
|
|||
G8Type_BTC,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BSF / BSR -- 16/32 operands supported only.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BSF / BSR
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 16/32 operands are available. No 8 bit ones, not that any of you cared, I bet.
|
||||
//
|
||||
// 0xbc [fwd] / 0xbd [rev]
|
||||
//
|
||||
template< u16 Opcode >
|
||||
class xImpl_BitScan
|
||||
struct xImpl_BitScan
|
||||
{
|
||||
public:
|
||||
xImpl_BitScan() {}
|
||||
// 0xbc [fwd] / 0xbd [rev]
|
||||
u16 Opcode;
|
||||
|
||||
__forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { xOpWrite0F( Opcode, to, from ); }
|
||||
__forceinline void operator()( const xRegister16& to, const xRegister16& from ) const { xOpWrite0F( 0x66, Opcode, to, from ); }
|
||||
__forceinline void operator()( const xRegister32& to, const ModSibBase& sibsrc ) const { xOpWrite0F( Opcode, to, sibsrc ); }
|
||||
__forceinline void operator()( const xRegister16& to, const ModSibBase& sibsrc ) const { xOpWrite0F( 0x66, Opcode, to, sibsrc ); }
|
||||
void operator()( const xRegister32& to, const xRegister32& from ) const;
|
||||
void operator()( const xRegister16& to, const xRegister16& from ) const;
|
||||
void operator()( const xRegister16or32& to, const ModSibBase& sibsrc ) const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xImpl_Group8
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Bit Test Instructions - Valid on 16/32 bit instructions only.
|
||||
//
|
||||
template< G8Type InstType >
|
||||
class xImpl_Group8
|
||||
struct xImpl_Group8
|
||||
{
|
||||
static const uint RegFormOp = 0xa3 | (InstType << 3);
|
||||
public:
|
||||
__forceinline void operator()( const xRegister32& bitbase, const xRegister32& bitoffset ) const { xOpWrite0F( RegFormOp, bitbase, bitoffset ); }
|
||||
__forceinline void operator()( const xRegister16& bitbase, const xRegister16& bitoffset ) const { xOpWrite0F( 0x66, RegFormOp, bitbase, bitoffset ); }
|
||||
__forceinline void operator()( const ModSibBase& bitbase, const xRegister32& bitoffset ) const { xOpWrite0F( RegFormOp, bitoffset, bitbase ); }
|
||||
__forceinline void operator()( const ModSibBase& bitbase, const xRegister16& bitoffset ) const { xOpWrite0F( 0x66, RegFormOp, bitoffset, bitbase ); }
|
||||
G8Type InstType;
|
||||
|
||||
__forceinline void operator()( const ModSibStrict<u32>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0xba, InstType, bitbase, bitoffset ); }
|
||||
__forceinline void operator()( const ModSibStrict<u16>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0x66, 0xba, InstType, bitbase, bitoffset ); }
|
||||
__forceinline void operator()( const xRegister<u32>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0xba, InstType, bitbase, bitoffset ); }
|
||||
__forceinline void operator()( const xRegister<u16>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0x66, 0xba, InstType, bitbase, bitoffset ); }
|
||||
void operator()( const xRegister32& bitbase, const xRegister32& bitoffset ) const;
|
||||
void operator()( const xRegister16& bitbase, const xRegister16& bitoffset ) const;
|
||||
void operator()( const xRegister16or32& bitbase, u8 bitoffset ) const;
|
||||
|
||||
xImpl_Group8() {}
|
||||
void operator()( const ModSibBase& bitbase, const xRegister16or32& bitoffset ) const;
|
||||
void operator()( const ModSib32& bitbase, u8 bitoffset ) const;
|
||||
void operator()( const ModSib16& bitbase, u8 bitoffset ) const;
|
||||
};
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
||||
|
|
|
@ -17,3 +17,8 @@
|
|||
|
||||
// This header file is intended to be the future home of xchg, cmpxchg, xadd, and
|
||||
// other threading-related exchange instructions.
|
||||
|
||||
namespace x86Emitter {
|
||||
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* ix86 core v0.9.0
|
||||
* ix86 core v0.9.1
|
||||
*
|
||||
* Original Authors (v0.6.2 and prior):
|
||||
* linuzappz <linuzappz@pcsx.net>
|
||||
|
@ -22,7 +22,7 @@
|
|||
* goldfinger
|
||||
* zerofrog(@gmail.com)
|
||||
*
|
||||
* Authors of v0.9.0:
|
||||
* Authors of v0.9.1:
|
||||
* Jake.Stine(@gmail.com)
|
||||
* cottonvibes(@gmail.com)
|
||||
* sudonim(1@gmail.com)
|
||||
|
@ -45,52 +45,10 @@
|
|||
|
||||
namespace x86Emitter
|
||||
{
|
||||
extern const char *const x86_regnames_gpr8[8];
|
||||
extern const char *const x86_regnames_gpr16[8];
|
||||
extern const char *const x86_regnames_gpr32[8];
|
||||
// --------------------------------------------------------------------------------------
|
||||
// x86Register Method Implementations (inlined!)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
extern const char *const x86_regnames_sse[8];
|
||||
extern const char *const x86_regnames_mmx[8];
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Diagnostic -- returns a string representation of this register.
|
||||
//
|
||||
template< typename T >
|
||||
const char* xGetRegName( const xRegister<T>& src )
|
||||
{
|
||||
if( src.IsEmpty() ) return "empty";
|
||||
|
||||
switch( sizeof(T) )
|
||||
{
|
||||
case 1: return x86_regnames_gpr8[ src.Id ];
|
||||
case 2: return x86_regnames_gpr16[ src.Id ];
|
||||
case 4: return x86_regnames_gpr32[ src.Id ];
|
||||
|
||||
jNO_DEFAULT
|
||||
}
|
||||
|
||||
return "oops?";
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
const char* xGetRegName( const xRegisterSIMD<T>& src )
|
||||
{
|
||||
if( src.IsEmpty() ) return "empty";
|
||||
|
||||
switch( sizeof(T) )
|
||||
{
|
||||
case 8: return x86_regnames_mmx[ src.Id ];
|
||||
case 16: return x86_regnames_sse[ src.Id ];
|
||||
|
||||
jNO_DEFAULT
|
||||
}
|
||||
|
||||
return "oops?";
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// x86Register Method Implementations
|
||||
//
|
||||
__forceinline xAddressInfo xAddressReg::operator+( const xAddressReg& right ) const
|
||||
{
|
||||
pxAssertMsg( Id != -1, "Uninitialized x86 register." );
|
||||
|
@ -132,184 +90,12 @@ namespace x86Emitter
|
|||
__forceinline xAddressInfo xAddressReg::operator*( u32 right ) const
|
||||
{
|
||||
pxAssertMsg( Id != -1, "Uninitialized x86 register." );
|
||||
return xAddressInfo( Empty, *this, right );
|
||||
return xAddressInfo( xEmptyReg, *this, right );
|
||||
}
|
||||
|
||||
__forceinline xAddressInfo xAddressReg::operator<<( u32 shift ) const
|
||||
{
|
||||
pxAssertMsg( Id != -1, "Uninitialized x86 register." );
|
||||
return xAddressInfo( Empty, *this, 1<<shift );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ModSib Method Implementations
|
||||
//
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
__forceinline ModSibBase::ModSibBase( const xAddressInfo& src ) :
|
||||
Base( src.Base ),
|
||||
Index( src.Index ),
|
||||
Scale( src.Factor ),
|
||||
Displacement( src.Displacement )
|
||||
{
|
||||
Reduce();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
__forceinline ModSibBase::ModSibBase( xAddressReg base, xAddressReg index, int scale, s32 displacement ) :
|
||||
Base( base ),
|
||||
Index( index ),
|
||||
Scale( scale ),
|
||||
Displacement( displacement )
|
||||
{
|
||||
Reduce();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
__forceinline ModSibBase::ModSibBase( s32 displacement ) :
|
||||
Base(),
|
||||
Index(),
|
||||
Scale(0),
|
||||
Displacement( displacement )
|
||||
{
|
||||
// no reduction necessary :D
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
__forceinline ModSibBase::ModSibBase( const void* target ) :
|
||||
Base(),
|
||||
Index(),
|
||||
Scale(0),
|
||||
Displacement( (s32)target )
|
||||
{
|
||||
// no reduction necessary :D
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// xAddressInfo Method Implementations
|
||||
//
|
||||
__forceinline xAddressInfo& xAddressInfo::Add( const xAddressReg& src )
|
||||
{
|
||||
if( src == Index )
|
||||
{
|
||||
Factor++;
|
||||
}
|
||||
else if( src == Base )
|
||||
{
|
||||
// Compound the existing register reference into the Index/Scale pair.
|
||||
Base = xAddressReg::Empty;
|
||||
|
||||
if( src == Index )
|
||||
Factor++;
|
||||
else
|
||||
{
|
||||
pxAssertDev( Index.IsEmpty(), "x86Emitter: Only one scaled index register is allowed in an address modifier." );
|
||||
Index = src;
|
||||
Factor = 2;
|
||||
}
|
||||
}
|
||||
else if( Base.IsEmpty() )
|
||||
Base = src;
|
||||
else if( Index.IsEmpty() )
|
||||
Index = src;
|
||||
else
|
||||
pxFailDev( L"x86Emitter: address modifiers cannot have more than two index registers." ); // oops, only 2 regs allowed per ModRm!
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
__forceinline xAddressInfo& xAddressInfo::Add( const xAddressInfo& src )
|
||||
{
|
||||
Add( src.Base );
|
||||
Add( src.Displacement );
|
||||
|
||||
// If the factor is 1, we can just treat index like a base register also.
|
||||
if( src.Factor == 1 )
|
||||
{
|
||||
Add( src.Index );
|
||||
}
|
||||
else if( Index.IsEmpty() )
|
||||
{
|
||||
Index = src.Index;
|
||||
Factor = src.Factor;
|
||||
}
|
||||
else if( Index == src.Index )
|
||||
{
|
||||
Factor += src.Factor;
|
||||
}
|
||||
else
|
||||
pxFailDev( L"x86Emitter: address modifiers cannot have more than two index registers." ); // oops, only 2 regs allowed per ModRm!
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename OperandType >
|
||||
xForwardJump<OperandType>::xForwardJump( JccComparisonType cctype ) :
|
||||
BasePtr( (s8*)xGetPtr() +
|
||||
((OperandSize == 1) ? 2 : // j8's are always 2 bytes.
|
||||
((cctype==Jcc_Unconditional) ? 5 : 6 )) // j32's are either 5 or 6 bytes
|
||||
)
|
||||
{
|
||||
pxAssert( cctype != Jcc_Unknown );
|
||||
pxAssert( OperandSize == 1 || OperandSize == 4 );
|
||||
|
||||
if( OperandSize == 1 )
|
||||
xWrite8( (cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype) );
|
||||
else
|
||||
{
|
||||
if( cctype == Jcc_Unconditional )
|
||||
xWrite8( 0xe9 );
|
||||
else
|
||||
{
|
||||
xWrite8( 0x0f );
|
||||
xWrite8( 0x80 | cctype );
|
||||
}
|
||||
}
|
||||
|
||||
xAdvancePtr( OperandSize );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
template< typename OperandType >
|
||||
void xForwardJump<OperandType>::SetTarget() const
|
||||
{
|
||||
pxAssert( BasePtr != NULL );
|
||||
|
||||
sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
|
||||
if( OperandSize == 1 )
|
||||
{
|
||||
if( !is_s8( displacement ) )
|
||||
{
|
||||
pxAssert( false );
|
||||
// Don't ask. --arcum42
|
||||
#if !defined(__LINUX__) || !defined(DEBUG)
|
||||
|
||||
Console.Error( "Emitter Error: Invalid short jump displacement = 0x%x", (int)displacement );
|
||||
#endif
|
||||
}
|
||||
BasePtr[-1] = (s8)displacement;
|
||||
}
|
||||
else
|
||||
{
|
||||
// full displacement, no sanity checks needed :D
|
||||
((s32*)BasePtr)[-1] = displacement;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// returns the inverted conditional type for this Jcc condition. Ie, JNS will become JS.
|
||||
//
|
||||
static __forceinline JccComparisonType xInvertCond( JccComparisonType src )
|
||||
{
|
||||
pxAssert( src != Jcc_Unknown );
|
||||
if( Jcc_Unconditional == src ) return Jcc_Unconditional;
|
||||
|
||||
// x86 conditionals are clever! To invert conditional types, just invert the lower bit:
|
||||
return (JccComparisonType)((int)src ^ 1);
|
||||
return xAddressInfo( xEmptyReg, *this, 1<<shift );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* ix86 definitions v0.9.0
|
||||
* ix86 definitions v0.9.1
|
||||
*
|
||||
* Original Authors (v0.6.2 and prior):
|
||||
* linuzappz <linuzappz@pcsx.net>
|
||||
|
@ -22,7 +22,7 @@
|
|||
* goldfinger
|
||||
* zerofrog(@gmail.com)
|
||||
*
|
||||
* Authors of v0.9.0:
|
||||
* Authors of v0.9.1:
|
||||
* Jake.Stine(@gmail.com)
|
||||
* cottonvibes(@gmail.com)
|
||||
* sudonim(1@gmail.com)
|
||||
|
@ -38,16 +38,16 @@ namespace x86Emitter
|
|||
// ------------------------------------------------------------------------
|
||||
// Group 1 Instruction Class
|
||||
|
||||
extern const Internal::xImpl_G1Logic<Internal::G1Type_AND,0x54> xAND;
|
||||
extern const Internal::xImpl_G1Logic<Internal::G1Type_OR,0x56> xOR;
|
||||
extern const Internal::xImpl_G1Logic<Internal::G1Type_XOR,0x57> xXOR;
|
||||
extern const xImpl_Group1 xADC;
|
||||
extern const xImpl_Group1 xSBB;
|
||||
|
||||
extern const Internal::xImpl_G1Arith<Internal::G1Type_ADD,0x58> xADD;
|
||||
extern const Internal::xImpl_G1Arith<Internal::G1Type_SUB,0x5c> xSUB;
|
||||
extern const Internal::xImpl_G1Compare xCMP;
|
||||
extern const xImpl_G1Logic xAND;
|
||||
extern const xImpl_G1Logic xOR;
|
||||
extern const xImpl_G1Logic xXOR;
|
||||
|
||||
extern const Internal::xImpl_Group1<Internal::G1Type_ADC> xADC;
|
||||
extern const Internal::xImpl_Group1<Internal::G1Type_SBB> xSBB;
|
||||
extern const xImpl_G1Arith xADD;
|
||||
extern const xImpl_G1Arith xSUB;
|
||||
extern const xImpl_G1Compare xCMP;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Group 2 Instruction Class
|
||||
|
@ -56,102 +56,66 @@ namespace x86Emitter
|
|||
// zero. This is a safe optimization since any zero-value shift does not affect any
|
||||
// flags.
|
||||
|
||||
extern const Internal::MovImplAll xMOV;
|
||||
extern const Internal::xImpl_Test xTEST;
|
||||
extern const xImpl_Mov xMOV;
|
||||
extern const xImpl_Test xTEST;
|
||||
|
||||
extern const Internal::Group2ImplAll<Internal::G2Type_ROL> xROL;
|
||||
extern const Internal::Group2ImplAll<Internal::G2Type_ROR> xROR;
|
||||
extern const Internal::Group2ImplAll<Internal::G2Type_RCL> xRCL;
|
||||
extern const Internal::Group2ImplAll<Internal::G2Type_RCR> xRCR;
|
||||
extern const Internal::Group2ImplAll<Internal::G2Type_SHL> xSHL;
|
||||
extern const Internal::Group2ImplAll<Internal::G2Type_SHR> xSHR;
|
||||
extern const Internal::Group2ImplAll<Internal::G2Type_SAR> xSAR;
|
||||
extern const xImpl_Group2 xROL, xROR,
|
||||
xRCL, xRCR,
|
||||
xSHL, xSHR,
|
||||
xSAR;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Group 3 Instruction Class
|
||||
|
||||
extern const Internal::xImpl_Group3<Internal::G3Type_NOT> xNOT;
|
||||
extern const Internal::xImpl_Group3<Internal::G3Type_NEG> xNEG;
|
||||
extern const Internal::xImpl_Group3<Internal::G3Type_MUL> xUMUL;
|
||||
extern const Internal::xImpl_Group3<Internal::G3Type_DIV> xUDIV;
|
||||
extern const Internal::xImpl_iDiv xDIV;
|
||||
extern const Internal::xImpl_iMul xMUL;
|
||||
extern const xImpl_Group3 xNOT, xNEG;
|
||||
extern const xImpl_Group3 xUMUL, xUDIV;
|
||||
extern const xImpl_iDiv xDIV;
|
||||
extern const xImpl_iMul xMUL;
|
||||
|
||||
extern const Internal::xImpl_IncDec<false> xINC;
|
||||
extern const Internal::xImpl_IncDec<true> xDEC;
|
||||
extern const xImpl_IncDec xINC, xDEC;
|
||||
|
||||
extern const Internal::MovExtendImplAll<false> xMOVZX;
|
||||
extern const Internal::MovExtendImplAll<true> xMOVSX;
|
||||
extern const xImpl_MovExtend xMOVZX, xMOVSX;
|
||||
|
||||
extern const Internal::DwordShiftImplAll<false> xSHLD;
|
||||
extern const Internal::DwordShiftImplAll<true> xSHRD;
|
||||
extern const xImpl_DwordShift xSHLD, xSHRD;
|
||||
|
||||
extern const Internal::xImpl_Group8<Internal::G8Type_BT> xBT;
|
||||
extern const Internal::xImpl_Group8<Internal::G8Type_BTR> xBTR;
|
||||
extern const Internal::xImpl_Group8<Internal::G8Type_BTS> xBTS;
|
||||
extern const Internal::xImpl_Group8<Internal::G8Type_BTC> xBTC;
|
||||
extern const xImpl_Group8 xBT;
|
||||
extern const xImpl_Group8 xBTR;
|
||||
extern const xImpl_Group8 xBTS;
|
||||
extern const xImpl_Group8 xBTC;
|
||||
|
||||
extern const Internal::xImpl_JmpCall<true> xJMP;
|
||||
extern const Internal::xImpl_JmpCall<false> xCALL;
|
||||
extern const xImpl_BitScan xBSF, xBSR;
|
||||
|
||||
extern const Internal::xImpl_BitScan<0xbc> xBSF;
|
||||
extern const Internal::xImpl_BitScan<0xbd> xBSR;
|
||||
extern const xImpl_JmpCall xJMP, xCALL;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
extern const Internal::CMovImplGeneric xCMOV;
|
||||
extern const xImpl_CMov
|
||||
xCMOVA, xCMOVAE,
|
||||
xCMOVB, xCMOVBE,
|
||||
xCMOVG, xCMOVGE,
|
||||
xCMOVL, xCMOVLE,
|
||||
|
||||
extern const Internal::CMovImplAll<Jcc_Above> xCMOVA;
|
||||
extern const Internal::CMovImplAll<Jcc_AboveOrEqual> xCMOVAE;
|
||||
extern const Internal::CMovImplAll<Jcc_Below> xCMOVB;
|
||||
extern const Internal::CMovImplAll<Jcc_BelowOrEqual> xCMOVBE;
|
||||
xCMOVZ, xCMOVE,
|
||||
xCMOVNZ, xCMOVNE,
|
||||
xCMOVO, xCMOVNO,
|
||||
xCMOVC, xCMOVNC,
|
||||
|
||||
extern const Internal::CMovImplAll<Jcc_Greater> xCMOVG;
|
||||
extern const Internal::CMovImplAll<Jcc_GreaterOrEqual> xCMOVGE;
|
||||
extern const Internal::CMovImplAll<Jcc_Less> xCMOVL;
|
||||
extern const Internal::CMovImplAll<Jcc_LessOrEqual> xCMOVLE;
|
||||
|
||||
extern const Internal::CMovImplAll<Jcc_Zero> xCMOVZ;
|
||||
extern const Internal::CMovImplAll<Jcc_Equal> xCMOVE;
|
||||
extern const Internal::CMovImplAll<Jcc_NotZero> xCMOVNZ;
|
||||
extern const Internal::CMovImplAll<Jcc_NotEqual> xCMOVNE;
|
||||
|
||||
extern const Internal::CMovImplAll<Jcc_Overflow> xCMOVO;
|
||||
extern const Internal::CMovImplAll<Jcc_NotOverflow> xCMOVNO;
|
||||
extern const Internal::CMovImplAll<Jcc_Carry> xCMOVC;
|
||||
extern const Internal::CMovImplAll<Jcc_NotCarry> xCMOVNC;
|
||||
|
||||
extern const Internal::CMovImplAll<Jcc_Signed> xCMOVS;
|
||||
extern const Internal::CMovImplAll<Jcc_Unsigned> xCMOVNS;
|
||||
extern const Internal::CMovImplAll<Jcc_ParityEven> xCMOVPE;
|
||||
extern const Internal::CMovImplAll<Jcc_ParityOdd> xCMOVPO;
|
||||
xCMOVS, xCMOVNS,
|
||||
xCMOVPE, xCMOVPO;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
extern const Internal::SetImplGeneric xSET;
|
||||
extern const xImpl_Set
|
||||
xSETA, xSETAE,
|
||||
xSETB, xSETBE,
|
||||
xSETG, xSETGE,
|
||||
xSETL, xSETLE,
|
||||
|
||||
extern const Internal::SetImplAll<Jcc_Above> xSETA;
|
||||
extern const Internal::SetImplAll<Jcc_AboveOrEqual> xSETAE;
|
||||
extern const Internal::SetImplAll<Jcc_Below> xSETB;
|
||||
extern const Internal::SetImplAll<Jcc_BelowOrEqual> xSETBE;
|
||||
xSETZ, xSETE,
|
||||
xSETNZ, xSETNE,
|
||||
xSETO, xSETNO,
|
||||
xSETC, xSETNC,
|
||||
|
||||
extern const Internal::SetImplAll<Jcc_Greater> xSETG;
|
||||
extern const Internal::SetImplAll<Jcc_GreaterOrEqual> xSETGE;
|
||||
extern const Internal::SetImplAll<Jcc_Less> xSETL;
|
||||
extern const Internal::SetImplAll<Jcc_LessOrEqual> xSETLE;
|
||||
|
||||
extern const Internal::SetImplAll<Jcc_Zero> xSETZ;
|
||||
extern const Internal::SetImplAll<Jcc_Equal> xSETE;
|
||||
extern const Internal::SetImplAll<Jcc_NotZero> xSETNZ;
|
||||
extern const Internal::SetImplAll<Jcc_NotEqual> xSETNE;
|
||||
|
||||
extern const Internal::SetImplAll<Jcc_Overflow> xSETO;
|
||||
extern const Internal::SetImplAll<Jcc_NotOverflow> xSETNO;
|
||||
extern const Internal::SetImplAll<Jcc_Carry> xSETC;
|
||||
extern const Internal::SetImplAll<Jcc_NotCarry> xSETNC;
|
||||
|
||||
extern const Internal::SetImplAll<Jcc_Signed> xSETS;
|
||||
extern const Internal::SetImplAll<Jcc_Unsigned> xSETNS;
|
||||
extern const Internal::SetImplAll<Jcc_ParityEven> xSETPE;
|
||||
extern const Internal::SetImplAll<Jcc_ParityOdd> xSETPO;
|
||||
xSETS, xSETNS,
|
||||
xSETPE, xSETPO;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Miscellaneous Instructions
|
||||
|
@ -419,10 +383,10 @@ namespace x86Emitter
|
|||
extern const xImplSimd_DestRegSSE xMOVSHDUP;
|
||||
|
||||
extern void xINSERTPS( const xRegisterSSE& to, const xRegisterSSE& from, u8 imm8 );
|
||||
extern void xINSERTPS( const xRegisterSSE& to, const ModSibStrict<u32>& from, u8 imm8 );
|
||||
extern void xINSERTPS( const xRegisterSSE& to, const ModSib32& from, u8 imm8 );
|
||||
|
||||
extern void xEXTRACTPS( const xRegister32& to, const xRegisterSSE& from, u8 imm8 );
|
||||
extern void xEXTRACTPS( const ModSibStrict<u32>& dest, const xRegisterSSE& from, u8 imm8 );
|
||||
extern void xEXTRACTPS( const ModSib32& dest, const xRegisterSSE& from, u8 imm8 );
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
@ -431,7 +395,7 @@ namespace x86Emitter
|
|||
extern const xImplSimd_DestRegEither xPOR;
|
||||
extern const xImplSimd_DestRegEither xPXOR;
|
||||
|
||||
extern /*const*/ xImplSimd_Shuffle xSHUF;
|
||||
extern const xImplSimd_Shuffle xSHUF;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -17,3 +17,52 @@
|
|||
|
||||
#include "x86types.h"
|
||||
#include "instructions.h"
|
||||
|
||||
#define OpWriteSSE( pre, op ) xOpWrite0F( pre, op, to, from )
|
||||
|
||||
namespace x86Emitter {
|
||||
|
||||
extern void SimdPrefix( u8 prefix, u16 opcode );
|
||||
extern void EmitSibMagic( uint regfield, const void* address );
|
||||
extern void EmitSibMagic( uint regfield, const ModSibBase& info );
|
||||
extern void EmitSibMagic( uint reg1, const xRegisterBase& reg2 );
|
||||
extern void EmitSibMagic( const xRegisterBase& reg1, const xRegisterBase& reg2 );
|
||||
extern void EmitSibMagic( const xRegisterBase& reg1, const void* src );
|
||||
extern void EmitSibMagic( const xRegisterBase& reg1, const ModSibBase& sib );
|
||||
|
||||
extern void _xMovRtoR( const xRegisterInt& to, const xRegisterInt& from );
|
||||
extern void _g1_EmitOp( G1Type InstType, const xRegisterInt& to, const xRegisterInt& from );
|
||||
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite( u8 prefix, u8 opcode, const T1& param1, const T2& param2 )
|
||||
{
|
||||
if( prefix != 0 )
|
||||
xWrite16( (opcode<<8) | prefix );
|
||||
else
|
||||
xWrite8( opcode );
|
||||
|
||||
EmitSibMagic( param1, param2 );
|
||||
}
|
||||
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite0F( u8 prefix, u16 opcode, const T1& param1, const T2& param2 )
|
||||
{
|
||||
SimdPrefix( prefix, opcode );
|
||||
EmitSibMagic( param1, param2 );
|
||||
}
|
||||
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite0F( u8 prefix, u16 opcode, const T1& param1, const T2& param2, u8 imm8 )
|
||||
{
|
||||
xOpWrite0F( prefix, opcode, param1, param2 );
|
||||
xWrite8( imm8 );
|
||||
}
|
||||
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite0F( u16 opcode, const T1& param1, const T2& param2 ) { xOpWrite0F( 0, opcode, param1, param2 ); }
|
||||
|
||||
template< typename T1, typename T2 > __emitinline
|
||||
void xOpWrite0F( u16 opcode, const T1& param1, const T2& param2, u8 imm8 ) { xOpWrite0F( 0, opcode, param1, param2, imm8 ); }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* ix86 public header v0.9.0
|
||||
* ix86 public header v0.9.1
|
||||
*
|
||||
* Original Authors (v0.6.2 and prior):
|
||||
* linuzappz <linuzappz@pcsx.net>
|
||||
|
@ -22,7 +22,7 @@
|
|||
* goldfinger
|
||||
* zerofrog(@gmail.com)
|
||||
*
|
||||
* Authors of v0.9.0:
|
||||
* Authors of v0.9.1:
|
||||
* Jake.Stine(@gmail.com)
|
||||
* cottonvibes(@gmail.com)
|
||||
* sudonim(1@gmail.com)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,287 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ix86 core v0.9.1
|
||||
*
|
||||
* Original Authors (v0.6.2 and prior):
|
||||
* linuzappz <linuzappz@pcsx.net>
|
||||
* alexey silinov
|
||||
* goldfinger
|
||||
* zerofrog(@gmail.com)
|
||||
*
|
||||
* Authors of v0.9.1:
|
||||
* Jake.Stine(@gmail.com)
|
||||
* cottonvibes(@gmail.com)
|
||||
* sudonim(1@gmail.com)
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "internal.h"
|
||||
#include "implement/helpers.h"
|
||||
|
||||
namespace x86Emitter {
|
||||
|
||||
// =====================================================================================================
|
||||
// Group 1 Instructions - ADD, SUB, ADC, etc.
|
||||
// =====================================================================================================
|
||||
|
||||
// Note on "[Indirect],Imm" forms : use int as the source operand since it's "reasonably inert" from a
|
||||
// compiler perspective. (using uint tends to make the compiler try and fail to match signed immediates
|
||||
// with one of the other overloads).
|
||||
static void _g1_IndirectImm( G1Type InstType, const ModSib32orLess& sibdest, int imm )
|
||||
{
|
||||
if( sibdest.Is8BitOp() )
|
||||
{
|
||||
xWrite8( 0x80 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
xWrite<s8>( imm );
|
||||
}
|
||||
else
|
||||
{
|
||||
sibdest.prefix16();
|
||||
xWrite8( is_s8( imm ) ? 0x83 : 0x81 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
if( is_s8( imm ) )
|
||||
xWrite<s8>( imm );
|
||||
else
|
||||
sibdest.xWriteImm( imm );
|
||||
}
|
||||
}
|
||||
|
||||
void _g1_EmitOp( G1Type InstType, const xRegisterInt& to, const xRegisterInt& from )
|
||||
{
|
||||
pxAssert( to.GetOperandSize() == from.GetOperandSize() );
|
||||
to.prefix16();
|
||||
xWrite8( (to.Is8BitOp() ? 0 : 1) | (InstType<<3) );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
|
||||
static void _g1_EmitOp( G1Type InstType, const ModSibBase& sibdest, const xRegisterInt& from )
|
||||
{
|
||||
from.prefix16();
|
||||
xWrite8( (from.Is8BitOp() ? 0 : 1) | (InstType<<3) );
|
||||
EmitSibMagic( from, sibdest );
|
||||
}
|
||||
|
||||
static void _g1_EmitOp( G1Type InstType, const xRegisterInt& to, const ModSibBase& sibsrc )
|
||||
{
|
||||
to.prefix16();
|
||||
xWrite8( (to.Is8BitOp() ? 2 : 3) | (InstType<<3) );
|
||||
EmitSibMagic( to, sibsrc );
|
||||
}
|
||||
|
||||
static void _g1_EmitOp( G1Type InstType, const xRegisterInt& to, int imm )
|
||||
{
|
||||
to.prefix16();
|
||||
if( !to.Is8BitOp() && is_s8( imm ) )
|
||||
{
|
||||
xWrite8( 0x83 );
|
||||
EmitSibMagic( InstType, to );
|
||||
xWrite<s8>( imm );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( to.IsAccumulator() )
|
||||
xWrite8( (to.Is8BitOp() ? 4 : 5) | (InstType<<3) );
|
||||
else
|
||||
{
|
||||
xWrite8( to.Is8BitOp() ? 0x80 : 0x81 );
|
||||
EmitSibMagic( InstType, to );
|
||||
}
|
||||
to.xWriteImm( imm );
|
||||
}
|
||||
}
|
||||
|
||||
#define ImplementGroup1( g1type, insttype ) \
|
||||
void g1type::operator()( const xRegister8& to, const xRegister8& from ) const { _g1_EmitOp( insttype, to, from ); } \
|
||||
void g1type::operator()( const xRegister16& to, const xRegister16& from ) const { _g1_EmitOp( insttype, to, from ); } \
|
||||
void g1type::operator()( const xRegister32& to, const xRegister32& from ) const { _g1_EmitOp( insttype, to, from ); } \
|
||||
void g1type::operator()( const ModSibBase& to, const xRegisterInt& from ) const { _g1_EmitOp( insttype, to, from ); } \
|
||||
void g1type::operator()( const xRegisterInt& to, const ModSibBase& from ) const { _g1_EmitOp( insttype, to, from ); } \
|
||||
void g1type::operator()( const xRegisterInt& to, int imm ) const { _g1_EmitOp( insttype, to, imm ); } \
|
||||
void g1type::operator()( const ModSib32orLess& sibdest, int imm ) const { _g1_IndirectImm( insttype, sibdest, imm ); }
|
||||
|
||||
ImplementGroup1( xImpl_Group1, InstType )
|
||||
ImplementGroup1( xImpl_G1Logic, InstType )
|
||||
ImplementGroup1( xImpl_G1Arith, InstType )
|
||||
ImplementGroup1( xImpl_G1Compare, G1Type_CMP )
|
||||
|
||||
const xImpl_G1Logic xAND = { G1Type_AND, { 0x00, 0x54 }, { 0x66, 0x54 } };
|
||||
const xImpl_G1Logic xOR = { G1Type_OR, { 0x00, 0x56 }, { 0x66, 0x56 } };
|
||||
const xImpl_G1Logic xXOR = { G1Type_XOR, { 0x00, 0x57 }, { 0x66, 0x57 } };
|
||||
|
||||
const xImpl_G1Arith xADD = { G1Type_ADD, { 0x00, 0x58 }, { 0x66, 0x58 }, { 0xf3, 0x58 }, { 0xf2, 0x58 } };
|
||||
const xImpl_G1Arith xSUB = { G1Type_SUB, { 0x00, 0x5c }, { 0x66, 0x5c }, { 0xf3, 0x5c }, { 0xf2, 0x5c } };
|
||||
const xImpl_G1Compare xCMP = { { 0x00, 0xc2 }, { 0x66, 0xc2 }, { 0xf3, 0xc2 }, { 0xf2, 0xc2 } };
|
||||
|
||||
const xImpl_Group1 xADC = { G1Type_ADC };
|
||||
const xImpl_Group1 xSBB = { G1Type_SBB };
|
||||
|
||||
// =====================================================================================================
|
||||
// Group 2 Instructions - SHR, SHL, etc.
|
||||
// =====================================================================================================
|
||||
|
||||
void xImpl_Group2::operator()( const xRegisterInt& to, const xRegisterCL& /* from */ ) const
|
||||
{
|
||||
to.prefix16();
|
||||
xWrite8( to.Is8BitOp() ? 0xd2 : 0xd3 );
|
||||
EmitSibMagic( InstType, to );
|
||||
}
|
||||
|
||||
void xImpl_Group2::operator()(const xRegisterInt& to, u8 imm ) const
|
||||
{
|
||||
if( imm == 0 ) return;
|
||||
|
||||
to.prefix16();
|
||||
if( imm == 1 )
|
||||
{
|
||||
// special encoding of 1's
|
||||
xWrite8( to.Is8BitOp() ? 0xd0 : 0xd1 );
|
||||
EmitSibMagic( InstType, to );
|
||||
}
|
||||
else
|
||||
{
|
||||
xWrite8( to.Is8BitOp() ? 0xc0 : 0xc1 );
|
||||
EmitSibMagic( InstType, to );
|
||||
xWrite8( imm );
|
||||
}
|
||||
}
|
||||
|
||||
void xImpl_Group2::operator()( const ModSib32orLess& sibdest, const xRegisterCL& /* from */ ) const
|
||||
{
|
||||
sibdest.prefix16();
|
||||
xWrite8( sibdest.Is8BitOp() ? 0xd2 : 0xd3 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
}
|
||||
|
||||
void xImpl_Group2::operator()( const ModSib32orLess& sibdest, u8 imm ) const
|
||||
{
|
||||
if( imm == 0 ) return;
|
||||
|
||||
sibdest.prefix16();
|
||||
if( imm == 1 )
|
||||
{
|
||||
// special encoding of 1's
|
||||
xWrite8( sibdest.Is8BitOp() ? 0xd0 : 0xd1 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
}
|
||||
else
|
||||
{
|
||||
xWrite8( sibdest.Is8BitOp() ? 0xc0 : 0xc1 );
|
||||
EmitSibMagic( InstType, sibdest );
|
||||
xWrite8( imm );
|
||||
}
|
||||
}
|
||||
|
||||
const xImpl_Group2 xROL = { G2Type_ROL };
|
||||
const xImpl_Group2 xROR = { G2Type_ROR };
|
||||
const xImpl_Group2 xRCL = { G2Type_RCL };
|
||||
const xImpl_Group2 xRCR = { G2Type_RCR };
|
||||
const xImpl_Group2 xSHL = { G2Type_SHL };
|
||||
const xImpl_Group2 xSHR = { G2Type_SHR };
|
||||
const xImpl_Group2 xSAR = { G2Type_SAR };
|
||||
|
||||
|
||||
// =====================================================================================================
|
||||
// Group 3 Instructions - NOT, NEG, MUL, DIV
|
||||
// =====================================================================================================
|
||||
|
||||
static void _g3_EmitOp( G3Type InstType, const xRegisterInt& from )
|
||||
{
|
||||
from.prefix16();
|
||||
xWrite8(from.Is8BitOp() ? 0xf6 : 0xf7 );
|
||||
EmitSibMagic( InstType, from );
|
||||
}
|
||||
|
||||
static void _g3_EmitOp( G3Type InstType, const ModSib32orLess& from )
|
||||
{
|
||||
from.prefix16();
|
||||
xWrite8( from.Is8BitOp() ? 0xf6 : 0xf7 );
|
||||
EmitSibMagic( InstType, from );
|
||||
}
|
||||
|
||||
void xImpl_Group3::operator()( const xRegisterInt& from ) const { _g3_EmitOp( InstType, from ); }
|
||||
void xImpl_Group3::operator()( const ModSib32orLess& from ) const { _g3_EmitOp( InstType, from ); }
|
||||
|
||||
void xImpl_iDiv::operator()( const xRegisterInt& from ) const { _g3_EmitOp( G3Type_iDIV, from ); }
|
||||
void xImpl_iDiv::operator()( const ModSib32orLess& from ) const { _g3_EmitOp( G3Type_iDIV, from ); }
|
||||
|
||||
template< typename SrcType >
|
||||
static void _imul_ImmStyle( const xRegisterInt& param1, const SrcType& param2, int imm )
|
||||
{
|
||||
// for iMul OpSize is allowed to be 16 or 32 bit only.
|
||||
const int OpSize = param1.GetOperandSize();
|
||||
|
||||
pxAssert( OpSize == param2.GetOperandSize() );
|
||||
pxAssert( OpSize > 1 );
|
||||
|
||||
xOpWrite0F( (OpSize == 2) ? 0x66 : 0, is_s8( imm ) ? 0x6b : 0x69, param1, param2 );
|
||||
|
||||
if( is_s8( imm ) )
|
||||
xWrite8( (u8)imm );
|
||||
else
|
||||
param1.xWriteImm( imm );
|
||||
}
|
||||
|
||||
void xImpl_iMul::operator()( const xRegisterInt& from ) const { _g3_EmitOp( G3Type_iMUL, from ); }
|
||||
void xImpl_iMul::operator()( const ModSib32orLess& from ) const { _g3_EmitOp( G3Type_iMUL, from ); }
|
||||
|
||||
void xImpl_iMul::operator()( const xRegister32& to, const xRegister32& from ) const { xOpWrite0F( 0xaf, to, from ); }
|
||||
void xImpl_iMul::operator()( const xRegister32& to, const ModSibBase& src ) const { xOpWrite0F( 0xaf, to, src ); }
|
||||
void xImpl_iMul::operator()( const xRegister16& to, const xRegister16& from ) const { xOpWrite0F( 0x66, 0xaf, to, from ); }
|
||||
void xImpl_iMul::operator()( const xRegister16& to, const ModSibBase& src ) const { xOpWrite0F( 0x66, 0xaf, to, src ); }
|
||||
|
||||
void xImpl_iMul::operator()( const xRegister32& to, const xRegister32& from, s32 imm ) const{ _imul_ImmStyle( to, from, imm ); }
|
||||
void xImpl_iMul::operator()( const xRegister32& to, const ModSibBase& from, s32 imm ) const { _imul_ImmStyle( to, from, imm ); }
|
||||
void xImpl_iMul::operator()( const xRegister16& to, const xRegister16& from, s16 imm ) const{ _imul_ImmStyle( to, from, imm ); }
|
||||
void xImpl_iMul::operator()( const xRegister16& to, const ModSibBase& from, s16 imm ) const { _imul_ImmStyle( to, from, imm ); }
|
||||
|
||||
const xImpl_Group3 xNOT = { G3Type_NOT };
|
||||
const xImpl_Group3 xNEG = { G3Type_NEG };
|
||||
const xImpl_Group3 xUMUL = { G3Type_MUL };
|
||||
const xImpl_Group3 xUDIV = { G3Type_DIV };
|
||||
|
||||
const xImpl_iDiv xDIV = { { 0x00, 0x5e }, { 0x66, 0x5e }, { 0xf3, 0x5e }, { 0xf2, 0x5e } };
|
||||
const xImpl_iMul xMUL = { { 0x00, 0x59 }, { 0x66, 0x59 }, { 0xf3, 0x59 }, { 0xf2, 0x59 } };
|
||||
|
||||
// =====================================================================================================
|
||||
// Group 8 Instructions
|
||||
// =====================================================================================================
|
||||
|
||||
void xImpl_Group8::operator()( const xRegister32& bitbase, const xRegister32& bitoffset ) const { xOpWrite0F( 0xa3 | (InstType << 3), bitbase, bitoffset ); }
|
||||
void xImpl_Group8::operator()( const xRegister16& bitbase, const xRegister16& bitoffset ) const { xOpWrite0F( 0x66, 0xa3 | (InstType << 3), bitbase, bitoffset ); }
|
||||
void xImpl_Group8::operator()( const ModSib32& bitbase, u8 bitoffset ) const { xOpWrite0F( 0xba, InstType, bitbase, bitoffset ); }
|
||||
void xImpl_Group8::operator()( const ModSib16& bitbase, u8 bitoffset ) const { xOpWrite0F( 0x66, 0xba, InstType, bitbase, bitoffset ); }
|
||||
|
||||
void xImpl_Group8::operator()( const xRegister16or32& bitbase, u8 bitoffset ) const
|
||||
{
|
||||
xOpWrite0F( (bitbase->GetOperandSize() == 2) ? 0x66 : 0x00, 0xba, InstType, bitbase, bitoffset );
|
||||
}
|
||||
|
||||
void xImpl_Group8::operator()( const ModSibBase& bitbase, const xRegister16or32& bitoffset ) const
|
||||
{
|
||||
xOpWrite0F( (bitoffset->GetOperandSize() == 2) ? 0x66 : 0x00, 0xa3 | (InstType << 3), bitoffset, bitbase );
|
||||
}
|
||||
|
||||
const xImpl_Group8 xBT = { G8Type_BT };
|
||||
const xImpl_Group8 xBTR = { G8Type_BTR };
|
||||
const xImpl_Group8 xBTS = { G8Type_BTS };
|
||||
const xImpl_Group8 xBTC = { G8Type_BTC };
|
||||
|
||||
|
||||
|
||||
} // End namespace x86Emitter
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* ix86 core v0.9.0
|
||||
* ix86 core v0.9.1
|
||||
*
|
||||
* Original Authors (v0.6.2 and prior):
|
||||
* linuzappz <linuzappz@pcsx.net>
|
||||
|
@ -22,7 +22,7 @@
|
|||
* goldfinger
|
||||
* zerofrog(@gmail.com)
|
||||
*
|
||||
* Authors of v0.9.0:
|
||||
* Authors of v0.9.1:
|
||||
* Jake.Stine(@gmail.com)
|
||||
* cottonvibes(@gmail.com)
|
||||
* sudonim(1@gmail.com)
|
||||
|
@ -33,12 +33,15 @@
|
|||
|
||||
namespace x86Emitter {
|
||||
|
||||
using namespace Internal;
|
||||
void xImpl_JmpCall::operator()( const xRegister32& absreg ) const { xOpWrite( 0x00, 0xff, isJmp ? 4 : 2, absreg ); }
|
||||
void xImpl_JmpCall::operator()( const ModSib32& src ) const { xOpWrite( 0x00, 0xff, isJmp ? 4 : 2, src ); }
|
||||
|
||||
const xImpl_JmpCall<true> xJMP;
|
||||
const xImpl_JmpCall<false> xCALL;
|
||||
void xImpl_JmpCall::operator()( const xRegister16& absreg ) const { xOpWrite( 0x66, 0xff, isJmp ? 4 : 2, absreg ); }
|
||||
void xImpl_JmpCall::operator()( const ModSib16& src ) const { xOpWrite( 0x66, 0xff, isJmp ? 4 : 2, src ); }
|
||||
|
||||
const xImpl_JmpCall xJMP = { true };
|
||||
const xImpl_JmpCall xCALL = { false };
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void xSmartJump::SetTarget()
|
||||
{
|
||||
u8* target = xGetPtr();
|
||||
|
@ -104,7 +107,7 @@ __emitinline s8* xJcc8( JccComparisonType comparison, s8 displacement )
|
|||
// slideForward - used internally by xSmartJump to indicate that the jump target is going
|
||||
// to slide forward in the event of an 8 bit displacement.
|
||||
//
|
||||
__emitinline void Internal::xJccKnownTarget( JccComparisonType comparison, const void* target, bool slideForward )
|
||||
__emitinline void xJccKnownTarget( JccComparisonType comparison, const void* target, bool slideForward )
|
||||
{
|
||||
// Calculate the potential j8 displacement first, assuming an instruction length of 2:
|
||||
sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2);
|
||||
|
@ -134,5 +137,56 @@ __emitinline void xJcc( JccComparisonType comparison, const void* target )
|
|||
xJccKnownTarget( comparison, target, false );
|
||||
}
|
||||
|
||||
xForwardJumpBase::xForwardJumpBase( uint opsize, JccComparisonType cctype )
|
||||
{
|
||||
pxAssert( opsize == 1 || opsize == 4 );
|
||||
pxAssertDev( cctype != Jcc_Unknown, "Invalid ForwardJump conditional type." );
|
||||
|
||||
BasePtr = (s8*)xGetPtr() +
|
||||
((opsize == 1) ? 2 : // j8's are always 2 bytes.
|
||||
((cctype==Jcc_Unconditional) ? 5 : 6 )); // j32's are either 5 or 6 bytes
|
||||
|
||||
if( opsize == 1 )
|
||||
xWrite8( (cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype) );
|
||||
else
|
||||
{
|
||||
if( cctype == Jcc_Unconditional )
|
||||
xWrite8( 0xe9 );
|
||||
else
|
||||
{
|
||||
xWrite8( 0x0f );
|
||||
xWrite8( 0x80 | cctype );
|
||||
}
|
||||
}
|
||||
|
||||
xAdvancePtr( opsize );
|
||||
}
|
||||
|
||||
void xForwardJumpBase::_setTarget( uint opsize ) const
|
||||
{
|
||||
pxAssertDev( BasePtr != NULL, "" );
|
||||
|
||||
sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
|
||||
if( opsize == 1 )
|
||||
{
|
||||
pxAssertDev( is_s8( displacement ), "Emitter Error: Invalid short jump displacement." );
|
||||
BasePtr[-1] = (s8)displacement;
|
||||
}
|
||||
else
|
||||
{
|
||||
// full displacement, no sanity checks needed :D
|
||||
((s32*)BasePtr)[-1] = displacement;
|
||||
}
|
||||
}
|
||||
|
||||
// returns the inverted conditional type for this Jcc condition. Ie, JNS will become JS.
|
||||
__forceinline JccComparisonType xInvertCond( JccComparisonType src )
|
||||
{
|
||||
pxAssert( src != Jcc_Unknown );
|
||||
if( Jcc_Unconditional == src ) return Jcc_Unconditional;
|
||||
|
||||
// x86 conditionals are clever! To invert conditional types, just invert the lower bit:
|
||||
return (JccComparisonType)((int)src ^ 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ emitterT void ModRM( uint mod, uint reg, uint rm )
|
|||
|
||||
emitterT void SibSB( uint ss, uint index, uint base )
|
||||
{
|
||||
// Note: Following ASSUMEs are for legacy support only.
|
||||
// Note: Following asserts are for legacy support only.
|
||||
// The new emitter performs these sanity checks during operand construction, so these
|
||||
// assertions can probably be removed once all legacy emitter code has been removed.
|
||||
pxAssert( ss < 4 );
|
||||
|
@ -54,60 +54,64 @@ emitterT void SibSB( uint ss, uint index, uint base )
|
|||
|
||||
using namespace x86Emitter;
|
||||
|
||||
template< typename ImmType >
|
||||
static __forceinline xRegister<ImmType> _reghlp( x86IntRegType src )
|
||||
static ModSib32 _mhlp32( x86IntRegType to )
|
||||
{
|
||||
return xRegister<ImmType>( src );
|
||||
return ptr32[xAddressReg( to )];
|
||||
}
|
||||
|
||||
static __forceinline ModSibBase _mrmhlp( x86IntRegType src )
|
||||
static ModSib32 _mhlp32( x86IntRegType to1, x86IntRegType to2 )
|
||||
{
|
||||
return ptr[_reghlp<u32>(src)];
|
||||
return ptr32[xAddressReg( to1 ) + xAddressReg( to2 )];
|
||||
}
|
||||
|
||||
template< typename ImmType >
|
||||
static __forceinline ModSibStrict<ImmType> _mhlp( x86IntRegType src )
|
||||
static ModSib16 _mhlp16( x86IntRegType to )
|
||||
{
|
||||
return ModSibStrict<ImmType>( xAddressReg::Empty, xAddressReg(src) );
|
||||
return ptr16[xAddressReg( to )];
|
||||
}
|
||||
|
||||
template< typename ImmType >
|
||||
static __forceinline ModSibStrict<ImmType> _mhlp2( x86IntRegType src1, x86IntRegType src2 )
|
||||
static ModSib16 _mhlp16( x86IntRegType to1, x86IntRegType to2 )
|
||||
{
|
||||
return ModSibStrict<ImmType>( xAddressReg(src2), xAddressReg(src1) );
|
||||
return ptr16[xAddressReg( to1 ) + xAddressReg( to2 )];
|
||||
}
|
||||
|
||||
static ModSib8 _mhlp8( x86IntRegType to )
|
||||
{
|
||||
return ptr8[xAddressReg( to )];
|
||||
}
|
||||
|
||||
static ModSib8 _mhlp8( x86IntRegType to1, x86IntRegType to2 )
|
||||
{
|
||||
return ptr8[xAddressReg( to1 ) + xAddressReg( to2 )];
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
#define DEFINE_LEGACY_HELPER( cod, bits ) \
|
||||
emitterT void cod##bits##RtoR( x86IntRegType to, x86IntRegType from ) { x##cod( _reghlp<u##bits>(to), _reghlp<u##bits>(from) ); } \
|
||||
emitterT void cod##bits##ItoR( x86IntRegType to, u##bits imm ) { x##cod( _reghlp<u##bits>(to), imm ); } \
|
||||
emitterT void cod##bits##MtoR( x86IntRegType to, uptr from ) { x##cod( _reghlp<u##bits>(to), (void*)from ); } \
|
||||
emitterT void cod##bits##RtoM( uptr to, x86IntRegType from ) { x##cod( (void*)to, _reghlp<u##bits>(from) ); } \
|
||||
emitterT void cod##bits##RtoR( x86IntRegType to, x86IntRegType from ) { x##cod( xRegister##bits(to), xRegister##bits(from) ); } \
|
||||
emitterT void cod##bits##ItoR( x86IntRegType to, u##bits imm ) { x##cod( xRegister##bits(to), imm ); } \
|
||||
emitterT void cod##bits##MtoR( x86IntRegType to, uptr from ) { x##cod( xRegister##bits(to), (void*)from ); } \
|
||||
emitterT void cod##bits##RtoM( uptr to, x86IntRegType from ) { x##cod( (void*)to, xRegister##bits(from) ); } \
|
||||
emitterT void cod##bits##ItoM( uptr to, u##bits imm ) { x##cod( ptr##bits[to], imm ); } \
|
||||
emitterT void cod##bits##ItoRm( x86IntRegType to, u##bits imm, int offset ) { x##cod( _mhlp<u##bits>(to) + offset, imm ); } \
|
||||
emitterT void cod##bits##RmtoR( x86IntRegType to, x86IntRegType from, int offset ) { x##cod( _reghlp<u##bits>(to), _mhlp<u##bits>(from) + offset ); } \
|
||||
emitterT void cod##bits##RtoRm( x86IntRegType to, x86IntRegType from, int offset ) { x##cod( _mhlp<u##bits>(to) + offset, _reghlp<u##bits>(from) ); } \
|
||||
emitterT void cod##bits##ItoRm( x86IntRegType to, u##bits imm, int offset ) { x##cod( _mhlp##bits(to) + offset, imm ); } \
|
||||
emitterT void cod##bits##RmtoR( x86IntRegType to, x86IntRegType from, int offset ) { x##cod( xRegister##bits(to), _mhlp##bits(from) + offset ); } \
|
||||
emitterT void cod##bits##RtoRm( x86IntRegType to, x86IntRegType from, int offset ) { x##cod( _mhlp##bits(to) + offset, xRegister##bits(from) ); } \
|
||||
emitterT void cod##bits##RtoRmS( x86IntRegType to1, x86IntRegType to2, x86IntRegType from, int offset ) \
|
||||
{ x##cod( _mhlp2<u##bits>(to1,to2) + offset, _reghlp<u##bits>(from) ); } \
|
||||
{ x##cod( _mhlp##bits(to1,to2) + offset, xRegister##bits(from) ); } \
|
||||
emitterT void cod##bits##RmStoR( x86IntRegType to, x86IntRegType from1, x86IntRegType from2, int offset ) \
|
||||
{ x##cod( _reghlp<u##bits>(to), _mhlp2<u##bits>(from1,from2) + offset ); }
|
||||
{ x##cod( xRegister##bits(to), _mhlp##bits(from1,from2) + offset ); }
|
||||
|
||||
#define DEFINE_LEGACY_SHIFT_HELPER( cod, bits ) \
|
||||
emitterT void cod##bits##CLtoR( x86IntRegType to ) { x##cod( _reghlp<u##bits>(to), cl ); } \
|
||||
emitterT void cod##bits##ItoR( x86IntRegType to, u8 imm ) { x##cod( _reghlp<u##bits>(to), imm ); } \
|
||||
emitterT void cod##bits##CLtoR( x86IntRegType to ) { x##cod( xRegister##bits(to), cl ); } \
|
||||
emitterT void cod##bits##ItoR( x86IntRegType to, u8 imm ) { x##cod( xRegister##bits(to), imm ); } \
|
||||
emitterT void cod##bits##CLtoM( uptr to ) { x##cod( ptr##bits[to], cl ); } \
|
||||
emitterT void cod##bits##ItoM( uptr to, u8 imm ) { x##cod( ptr##bits[to], imm ); } \
|
||||
emitterT void cod##bits##ItoRm( x86IntRegType to, u8 imm, int offset ) { x##cod( _mhlp<u##bits>(to) + offset, imm ); } \
|
||||
emitterT void cod##bits##CLtoRm( x86IntRegType to, int offset ) { x##cod( _mhlp<u##bits>(to) + offset, cl ); }
|
||||
emitterT void cod##bits##ItoRm( x86IntRegType to, u8 imm, int offset ) { x##cod( _mhlp##bits(to) + offset, imm ); } \
|
||||
emitterT void cod##bits##CLtoRm( x86IntRegType to, int offset ) { x##cod( _mhlp##bits(to) + offset, cl ); }
|
||||
|
||||
#define DEFINE_LEGACY_ONEREG_HELPER( cod, bits ) \
|
||||
emitterT void cod##bits##R( x86IntRegType to ) { x##cod( _reghlp<u##bits>(to) ); } \
|
||||
emitterT void cod##bits##R( x86IntRegType to ) { x##cod( xRegister##bits(to) ); } \
|
||||
emitterT void cod##bits##M( uptr to ) { x##cod( ptr##bits[to] ); } \
|
||||
emitterT void cod##bits##Rm( x86IntRegType to, uptr offset ) { x##cod( _mhlp<u##bits>(to) + offset ); }
|
||||
|
||||
//emitterT void cod##bits##RtoRmS( x86IntRegType to1, x86IntRegType to2, x86IntRegType from, int offset )
|
||||
// { cod( _mhlp2<u##bits>(to1,to2) + offset, _reghlp<u##bits>(from) ); }
|
||||
emitterT void cod##bits##Rm( x86IntRegType to, uptr offset ) { x##cod( _mhlp##bits(to) + offset ); }
|
||||
|
||||
#define DEFINE_OPCODE_LEGACY( cod ) \
|
||||
DEFINE_LEGACY_HELPER( cod, 32 ) \
|
||||
|
@ -198,7 +202,7 @@ emitterT void MOV8RmSOffsettoR( x86IntRegType to, x86IntRegType from1, s32 from2
|
|||
|
||||
emitterT void AND32I8toR( x86IntRegType to, s8 from )
|
||||
{
|
||||
xAND( _reghlp<u32>(to), from );
|
||||
xAND( xRegister32(to), from );
|
||||
}
|
||||
|
||||
emitterT void AND32I8toM( uptr to, s8 from )
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ix86 core v0.9.1
|
||||
*
|
||||
* Original Authors (v0.6.2 and prior):
|
||||
* linuzappz <linuzappz@pcsx.net>
|
||||
* alexey silinov
|
||||
* goldfinger
|
||||
* zerofrog(@gmail.com)
|
||||
*
|
||||
* Authors of v0.9.1:
|
||||
* Jake.Stine(@gmail.com)
|
||||
* cottonvibes(@gmail.com)
|
||||
* sudonim(1@gmail.com)
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "internal.h"
|
||||
#include "implement/helpers.h"
|
||||
|
||||
namespace x86Emitter {
|
||||
|
||||
void _xMovRtoR( const xRegisterInt& to, const xRegisterInt& from )
|
||||
{
|
||||
pxAssert( to.GetOperandSize() == from.GetOperandSize() );
|
||||
|
||||
if( to == from ) return; // ignore redundant MOVs.
|
||||
|
||||
from.prefix16();
|
||||
xWrite8( from.Is8BitOp() ? 0x88 : 0x89 );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()( const xRegister8& to, const xRegister8& from ) const
|
||||
{
|
||||
if( to == from ) return; // ignore redundant MOVs.
|
||||
xWrite8( 0x88 );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()( const xRegister16& to, const xRegister16& from ) const
|
||||
{
|
||||
if( to == from ) return; // ignore redundant MOVs.
|
||||
from.prefix16();
|
||||
xWrite8( 0x89 );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()( const xRegister32& to, const xRegister32& from ) const
|
||||
{
|
||||
if( to == from ) return; // ignore redundant MOVs.
|
||||
xWrite8( 0x89 );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()( const ModSibBase& dest, const xRegisterInt& from ) const
|
||||
{
|
||||
from.prefix16();
|
||||
|
||||
// mov eax has a special from when writing directly to a DISP32 address
|
||||
// (sans any register index/base registers).
|
||||
|
||||
if( from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty() )
|
||||
{
|
||||
xWrite8( from.Is8BitOp() ? 0xa2 : 0xa3 );
|
||||
xWrite32( dest.Displacement );
|
||||
}
|
||||
else
|
||||
{
|
||||
xWrite8( from.Is8BitOp() ? 0x88 : 0x89 );
|
||||
EmitSibMagic( from.Id, dest );
|
||||
}
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()( const xRegisterInt& to, const ModSibBase& src ) const
|
||||
{
|
||||
to.prefix16();
|
||||
|
||||
// mov eax has a special from when reading directly from a DISP32 address
|
||||
// (sans any register index/base registers).
|
||||
|
||||
if( to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty() )
|
||||
{
|
||||
xWrite8( to.Is8BitOp() ? 0xa0 : 0xa1 );
|
||||
xWrite32( src.Displacement );
|
||||
}
|
||||
else
|
||||
{
|
||||
xWrite8( to.Is8BitOp() ? 0x8a : 0x8b );
|
||||
EmitSibMagic( to, src );
|
||||
}
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()( const ModSib32orLess& dest, int imm ) const
|
||||
{
|
||||
dest.prefix16();
|
||||
xWrite8( dest.Is8BitOp() ? 0xc6 : 0xc7 );
|
||||
EmitSibMagic( 0, dest );
|
||||
dest.xWriteImm( imm );
|
||||
}
|
||||
|
||||
// preserve_flags - set to true to disable optimizations which could alter the state of
|
||||
// the flags (namely replacing mov reg,0 with xor).
|
||||
void xImpl_Mov::operator()( const xRegisterInt& to, int imm, bool preserve_flags ) const
|
||||
{
|
||||
if( !preserve_flags && (imm == 0) )
|
||||
_g1_EmitOp( G1Type_XOR, to, to );
|
||||
else
|
||||
{
|
||||
// Note: MOV does not have (reg16/32,imm8) forms.
|
||||
|
||||
to.prefix16();
|
||||
xWrite8( (to.Is8BitOp() ? 0xb0 : 0xb8) | to.Id );
|
||||
to.xWriteImm( imm );
|
||||
}
|
||||
}
|
||||
|
||||
const xImpl_Mov xMOV;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CMOVcc
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
#define ccSane() pxAssertDev( ccType >= 0 && ccType <= 0x0f, "Invalid comparison type specifier." )
|
||||
|
||||
// Macro useful for trapping unwanted use of EBP.
|
||||
//#define EbpAssert() pxAssert( to != ebp )
|
||||
#define EbpAssert()
|
||||
|
||||
|
||||
void xCMOV( JccComparisonType ccType, const xRegister32& to, const xRegister32& from ) { ccSane(); xOpWrite0F( 0x40 | ccType, to, from ); }
|
||||
void xCMOV( JccComparisonType ccType, const xRegister32& to, const ModSibBase& sibsrc ) { ccSane(); xOpWrite0F( 0x40 | ccType, to, sibsrc ); }
|
||||
//void xCMOV( JccComparisonType ccType, const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); } // too.. lazy.. to fix.
|
||||
|
||||
void xCMOV( JccComparisonType ccType, const xRegister16& to, const xRegister16& from ) { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, from ); }
|
||||
void xCMOV( JccComparisonType ccType, const xRegister16& to, const ModSibBase& sibsrc ) { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, sibsrc ); }
|
||||
//void xCMOV( JccComparisonType ccType, const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
|
||||
void xSET( JccComparisonType ccType, const xRegister8& to ) { ccSane(); xOpWrite0F( 0x90 | ccType, 0, to ); }
|
||||
void xSET( JccComparisonType ccType, const ModSib8& dest ) { ccSane(); xOpWrite0F( 0x90 | ccType, 0, dest ); }
|
||||
|
||||
void xImpl_CMov::operator()( const xRegister32& to, const xRegister32& from ) const { ccSane(); xOpWrite0F( 0x40 | ccType, to, from ); }
|
||||
void xImpl_CMov::operator()( const xRegister32& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x40 | ccType, to, sibsrc ); }
|
||||
void xImpl_CMov::operator()( const xRegister16& to, const xRegister16& from ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, from ); }
|
||||
void xImpl_CMov::operator()( const xRegister16& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, sibsrc ); }
|
||||
|
||||
//void xImpl_CMov::operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
//void xImpl_CMov::operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); }
|
||||
|
||||
void xImpl_Set::operator()( const xRegister8& to ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, to ); }
|
||||
void xImpl_Set::operator()( const ModSib8& dest ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, dest ); }
|
||||
//void xImpl_Set::operator()( const xDirectOrIndirect8& dest ) const { ccSane(); _DoI_helpermess( *this, dest ); }
|
||||
|
||||
void xImpl_MovExtend::operator()( const xRegister16or32& to, const xRegister8& from ) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(
|
||||
( to->GetOperandSize() == 2 ) ? 0x66 : 0,
|
||||
SignExtend ? 0xbe : 0xb6,
|
||||
to, from
|
||||
);
|
||||
}
|
||||
|
||||
void xImpl_MovExtend::operator()( const xRegister16or32& to, const ModSib8& sibsrc ) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F(
|
||||
( to->GetOperandSize() == 2 ) ? 0x66 : 0,
|
||||
SignExtend ? 0xbe : 0xb6,
|
||||
to, sibsrc
|
||||
);
|
||||
}
|
||||
|
||||
void xImpl_MovExtend::operator()( const xRegister32& to, const xRegister16& from ) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F( SignExtend ? 0xbf : 0xb7, to, from );
|
||||
}
|
||||
|
||||
void xImpl_MovExtend::operator()( const xRegister32& to, const ModSib16& sibsrc ) const
|
||||
{
|
||||
EbpAssert();
|
||||
xOpWrite0F( SignExtend ? 0xbf : 0xb7, to, sibsrc );
|
||||
}
|
||||
|
||||
#if 0
|
||||
void xImpl_MovExtend::operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const
|
||||
{
|
||||
EbpAssert();
|
||||
_DoI_helpermess( *this, to, src );
|
||||
}
|
||||
|
||||
void xImpl_MovExtend::operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const
|
||||
{
|
||||
EbpAssert();
|
||||
_DoI_helpermess( *this, to, src );
|
||||
}
|
||||
#endif
|
||||
|
||||
const xImpl_MovExtend xMOVSX = { true };
|
||||
const xImpl_MovExtend xMOVZX = { false };
|
||||
|
||||
const xImpl_CMov xCMOVA = { Jcc_Above };
|
||||
const xImpl_CMov xCMOVAE = { Jcc_AboveOrEqual };
|
||||
const xImpl_CMov xCMOVB = { Jcc_Below };
|
||||
const xImpl_CMov xCMOVBE = { Jcc_BelowOrEqual };
|
||||
|
||||
const xImpl_CMov xCMOVG = { Jcc_Greater };
|
||||
const xImpl_CMov xCMOVGE = { Jcc_GreaterOrEqual };
|
||||
const xImpl_CMov xCMOVL = { Jcc_Less };
|
||||
const xImpl_CMov xCMOVLE = { Jcc_LessOrEqual };
|
||||
|
||||
const xImpl_CMov xCMOVZ = { Jcc_Zero };
|
||||
const xImpl_CMov xCMOVE = { Jcc_Equal };
|
||||
const xImpl_CMov xCMOVNZ = { Jcc_NotZero };
|
||||
const xImpl_CMov xCMOVNE = { Jcc_NotEqual };
|
||||
|
||||
const xImpl_CMov xCMOVO = { Jcc_Overflow };
|
||||
const xImpl_CMov xCMOVNO = { Jcc_NotOverflow };
|
||||
const xImpl_CMov xCMOVC = { Jcc_Carry };
|
||||
const xImpl_CMov xCMOVNC = { Jcc_NotCarry };
|
||||
|
||||
const xImpl_CMov xCMOVS = { Jcc_Signed };
|
||||
const xImpl_CMov xCMOVNS = { Jcc_Unsigned };
|
||||
const xImpl_CMov xCMOVPE = { Jcc_ParityEven };
|
||||
const xImpl_CMov xCMOVPO = { Jcc_ParityOdd };
|
||||
|
||||
|
||||
const xImpl_Set xSETA = { Jcc_Above };
|
||||
const xImpl_Set xSETAE = { Jcc_AboveOrEqual };
|
||||
const xImpl_Set xSETB = { Jcc_Below };
|
||||
const xImpl_Set xSETBE = { Jcc_BelowOrEqual };
|
||||
|
||||
const xImpl_Set xSETG = { Jcc_Greater };
|
||||
const xImpl_Set xSETGE = { Jcc_GreaterOrEqual };
|
||||
const xImpl_Set xSETL = { Jcc_Less };
|
||||
const xImpl_Set xSETLE = { Jcc_LessOrEqual };
|
||||
|
||||
const xImpl_Set xSETZ = { Jcc_Zero };
|
||||
const xImpl_Set xSETE = { Jcc_Equal };
|
||||
const xImpl_Set xSETNZ = { Jcc_NotZero };
|
||||
const xImpl_Set xSETNE = { Jcc_NotEqual };
|
||||
|
||||
const xImpl_Set xSETO = { Jcc_Overflow };
|
||||
const xImpl_Set xSETNO = { Jcc_NotOverflow };
|
||||
const xImpl_Set xSETC = { Jcc_Carry };
|
||||
const xImpl_Set xSETNC = { Jcc_NotCarry };
|
||||
|
||||
const xImpl_Set xSETS = { Jcc_Signed };
|
||||
const xImpl_Set xSETNS = { Jcc_Unsigned };
|
||||
const xImpl_Set xSETPE = { Jcc_ParityEven };
|
||||
const xImpl_Set xSETPO = { Jcc_ParityOdd };
|
||||
|
||||
} // end namespace x86Emitter
|
|
@ -67,8 +67,6 @@ SSE_MXCSR::operator x86Emitter::ModSib32() const
|
|||
|
||||
namespace x86Emitter {
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// SimdPrefix - If the lower byte of the opcode is 0x38 or 0x3a, then the opcode is
|
||||
// treated as a 16 bit value (in SSE 0x38 and 0x3a denote prefixes for extended SSE3/4
|
||||
|
@ -76,7 +74,7 @@ using namespace Internal;
|
|||
// Non-zero upper bytes, when the lower byte is not the 0x38 or 0x3a prefix, will
|
||||
// generate an assertion.
|
||||
//
|
||||
__emitinline void Internal::SimdPrefix( u8 prefix, u16 opcode )
|
||||
__emitinline void SimdPrefix( u8 prefix, u16 opcode )
|
||||
{
|
||||
const bool is16BitOpcode = ((opcode & 0xff) == 0x38) || ((opcode & 0xff) == 0x3a);
|
||||
|
||||
|
@ -193,6 +191,9 @@ void xImplSimd_DestRegEither::operator()( const xRegisterSSE& to, const ModSibBa
|
|||
void xImplSimd_DestRegEither::operator()( const xRegisterMMX& to, const xRegisterMMX& from ) const { OpWriteSSE( 0x00, Opcode ); }
|
||||
void xImplSimd_DestRegEither::operator()( const xRegisterMMX& to, const ModSibBase& from ) const { OpWriteSSE( 0x00, Opcode ); }
|
||||
|
||||
void xImplSimd_DestSSE_CmpImm::operator()( const xRegisterSSE& to, const xRegisterSSE& from, SSE2_ComparisonType imm ) const { xOpWrite0F( Prefix, Opcode, to, from, imm ); }
|
||||
void xImplSimd_DestSSE_CmpImm::operator()( const xRegisterSSE& to, const ModSibBase& from, SSE2_ComparisonType imm ) const { xOpWrite0F( Prefix, Opcode, to, from, imm ); }
|
||||
|
||||
// =====================================================================================================
|
||||
// SIMD Arithmetic Instructions
|
||||
// =====================================================================================================
|
||||
|
@ -351,16 +352,16 @@ const xImplSimd_Round xROUND =
|
|||
// =====================================================================================================
|
||||
|
||||
void xImplSimd_Compare::PS( const xRegisterSSE& to, const xRegisterSSE& from ) const { xOpWrite0F( 0x00, 0xc2, to, from, (u8)CType ); }
|
||||
void xImplSimd_Compare::PS( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( 0x00, 0xc2, to, from, (u8)CType ); }
|
||||
void xImplSimd_Compare::PS( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( 0x00, 0xc2, to, from, (u8)CType ); }
|
||||
|
||||
void xImplSimd_Compare::PD( const xRegisterSSE& to, const xRegisterSSE& from ) const { xOpWrite0F( 0x66, 0xc2, to, from, (u8)CType ); }
|
||||
void xImplSimd_Compare::PD( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( 0x66, 0xc2, to, from, (u8)CType ); }
|
||||
void xImplSimd_Compare::PD( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( 0x66, 0xc2, to, from, (u8)CType ); }
|
||||
|
||||
void xImplSimd_Compare::SS( const xRegisterSSE& to, const xRegisterSSE& from ) const { xOpWrite0F( 0xf3, 0xc2, to, from, (u8)CType ); }
|
||||
void xImplSimd_Compare::SS( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( 0xf3, 0xc2, to, from, (u8)CType ); }
|
||||
void xImplSimd_Compare::SS( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( 0xf3, 0xc2, to, from, (u8)CType ); }
|
||||
|
||||
void xImplSimd_Compare::SD( const xRegisterSSE& to, const xRegisterSSE& from ) const { xOpWrite0F( 0xf2, 0xc2, to, from, (u8)CType ); }
|
||||
void xImplSimd_Compare::SD( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( 0xf2, 0xc2, to, from, (u8)CType ); }
|
||||
void xImplSimd_Compare::SD( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( 0xf2, 0xc2, to, from, (u8)CType ); }
|
||||
|
||||
const xImplSimd_MinMax xMIN =
|
||||
{
|
||||
|
@ -486,7 +487,7 @@ void SimdImpl_PExtract::W( const xRegister32& to, const xRegisterSSE& from, u8 i
|
|||
void SimdImpl_PExtract::W( const xRegister32& to, const xRegisterMMX& from, u8 imm8 ) const { xOpWrite0F( 0xc5, to, from, imm8 ); }
|
||||
void SimdImpl_PExtract::W( const ModSibBase& dest, const xRegisterSSE& from, u8 imm8 ) const { xOpWrite0F( 0x66, 0x153a, from, dest, imm8 ); }
|
||||
|
||||
/*const*/ xImplSimd_Shuffle xSHUF;
|
||||
const xImplSimd_Shuffle xSHUF = { };
|
||||
|
||||
const xImplSimd_PShuffle xPSHUF =
|
||||
{
|
||||
|
@ -600,22 +601,22 @@ void xImplSimd_MoveDQ::operator()( const ModSibBase& to, const xRegisterSSE& fro
|
|||
}
|
||||
|
||||
void xImplSimd_PMove::BW( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, OpcodeBase ); }
|
||||
void xImplSimd_PMove::BW( const xRegisterSSE& to, const ModSibStrict<u64>& from ) const { OpWriteSSE( 0x66, OpcodeBase ); }
|
||||
void xImplSimd_PMove::BW( const xRegisterSSE& to, const ModSib64& from ) const { OpWriteSSE( 0x66, OpcodeBase ); }
|
||||
|
||||
void xImplSimd_PMove::BD( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x100 ); }
|
||||
void xImplSimd_PMove::BD( const xRegisterSSE& to, const ModSibStrict<u32>& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x100 ); }
|
||||
void xImplSimd_PMove::BD( const xRegisterSSE& to, const ModSib32& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x100 ); }
|
||||
|
||||
void xImplSimd_PMove::BQ( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x200 ); }
|
||||
void xImplSimd_PMove::BQ( const xRegisterSSE& to, const ModSibStrict<u16>& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x200 ); }
|
||||
void xImplSimd_PMove::BQ( const xRegisterSSE& to, const ModSib16& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x200 ); }
|
||||
|
||||
void xImplSimd_PMove::WD( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x300 ); }
|
||||
void xImplSimd_PMove::WD( const xRegisterSSE& to, const ModSibStrict<u64>& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x300 ); }
|
||||
void xImplSimd_PMove::WD( const xRegisterSSE& to, const ModSib64& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x300 ); }
|
||||
|
||||
void xImplSimd_PMove::WQ( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x400 ); }
|
||||
void xImplSimd_PMove::WQ( const xRegisterSSE& to, const ModSibStrict<u32>& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x400 ); }
|
||||
void xImplSimd_PMove::WQ( const xRegisterSSE& to, const ModSib32& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x400 ); }
|
||||
|
||||
void xImplSimd_PMove::DQ( const xRegisterSSE& to, const xRegisterSSE& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x500 ); }
|
||||
void xImplSimd_PMove::DQ( const xRegisterSSE& to, const ModSibStrict<u64>& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x500 ); }
|
||||
void xImplSimd_PMove::DQ( const xRegisterSSE& to, const ModSib64& from ) const { OpWriteSSE( 0x66, OpcodeBase+0x500 ); }
|
||||
|
||||
|
||||
const xImplSimd_MoveSSE xMOVAPS = { 0x00, true };
|
||||
|
@ -794,15 +795,15 @@ __forceinline void xPALIGNR( const xRegisterMMX& to, const xRegisterMMX& from, u
|
|||
// * ZMASK: Each bit of Imm8[3:0] selects a dword element in dest to be written
|
||||
// with 0.0 if set to 1.
|
||||
//
|
||||
__emitinline void xINSERTPS( const xRegisterSSE& to, const xRegisterSSE& from, u8 imm8 ) { xOpWrite0F( 0x66, 0x213a, to, from, imm8 ); }
|
||||
__emitinline void xINSERTPS( const xRegisterSSE& to, const ModSibStrict<u32>& from, u8 imm8 ) { xOpWrite0F( 0x66, 0x213a, to, from, imm8 ); }
|
||||
__emitinline void xINSERTPS( const xRegisterSSE& to, const xRegisterSSE& from, u8 imm8 ) { xOpWrite0F( 0x66, 0x213a, to, from, imm8 ); }
|
||||
__emitinline void xINSERTPS( const xRegisterSSE& to, const ModSib32& from, u8 imm8 ) { xOpWrite0F( 0x66, 0x213a, to, from, imm8 ); }
|
||||
|
||||
// [SSE-4.1] Extract a single-precision floating-point value from src at an offset
|
||||
// determined by imm8[1-0]*32. The extracted single precision floating-point value
|
||||
// is stored into the low 32-bits of dest (or at a 32-bit memory pointer).
|
||||
//
|
||||
__emitinline void xEXTRACTPS( const xRegister32& to, const xRegisterSSE& from, u8 imm8 ) { xOpWrite0F( 0x66, 0x173a, to, from, imm8 ); }
|
||||
__emitinline void xEXTRACTPS( const ModSibStrict<u32>& dest, const xRegisterSSE& from, u8 imm8 ){ xOpWrite0F( 0x66, 0x173a, from, dest, imm8 ); }
|
||||
__emitinline void xEXTRACTPS( const xRegister32& to, const xRegisterSSE& from, u8 imm8 ) { xOpWrite0F( 0x66, 0x173a, to, from, imm8 ); }
|
||||
__emitinline void xEXTRACTPS( const ModSib32& dest, const xRegisterSSE& from, u8 imm8 ) { xOpWrite0F( 0x66, 0x173a, from, dest, imm8 ); }
|
||||
|
||||
|
||||
// =====================================================================================================
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* ix86 core v0.9.0
|
||||
* ix86 core v0.9.1
|
||||
*
|
||||
* Original Authors (v0.6.2 and prior):
|
||||
* linuzappz <linuzappz@pcsx.net>
|
||||
|
@ -22,7 +22,7 @@
|
|||
* goldfinger
|
||||
* zerofrog(@gmail.com)
|
||||
*
|
||||
* Authors of v0.9.0:
|
||||
* Authors of v0.9.1:
|
||||
* Jake.Stine(@gmail.com)
|
||||
* cottonvibes(@gmail.com)
|
||||
* sudonim(1@gmail.com)
|
||||
|
@ -70,6 +70,18 @@ __threadlocal XMMSSEType g_xmmtypes[iREGCNT_XMM] = { XMMT_INT };
|
|||
|
||||
namespace x86Emitter {
|
||||
|
||||
template< typename T > __forceinline void xWrite( T val )
|
||||
{
|
||||
*(T*)x86Ptr = val;
|
||||
x86Ptr += sizeof(T);
|
||||
}
|
||||
|
||||
template void xWrite<u8>( u8 val );
|
||||
template void xWrite<u16>( u16 val );
|
||||
template void xWrite<u32>( u32 val );
|
||||
template void xWrite<u64>( u64 val );
|
||||
template void xWrite<u128>( u128 val );
|
||||
|
||||
__forceinline void xWrite8( u8 val )
|
||||
{
|
||||
xWrite( val );
|
||||
|
@ -90,18 +102,16 @@ __forceinline void xWrite64( u64 val )
|
|||
xWrite( val );
|
||||
}
|
||||
|
||||
const xAddressIndexerBase ptr;
|
||||
const xAddressIndexer<u128> ptr128;
|
||||
const xAddressIndexer<u64> ptr64;
|
||||
const xAddressIndexer<u32> ptr32;
|
||||
const xAddressIndexer<u16> ptr16;
|
||||
const xAddressIndexer<u8> ptr8;
|
||||
const xAddressIndexer<ModSibBase> ptr;
|
||||
const xAddressIndexer<ModSib128> ptr128;
|
||||
const xAddressIndexer<ModSib64> ptr64;
|
||||
const xAddressIndexer<ModSib32> ptr32;
|
||||
const xAddressIndexer<ModSib16> ptr16;
|
||||
const xAddressIndexer<ModSib8> ptr8;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
template< typename OperandType > const xRegisterBase<OperandType> xRegisterBase<OperandType>::Empty;
|
||||
|
||||
const xAddressReg xAddressReg::Empty;
|
||||
const xRegisterEmpty xEmptyReg;
|
||||
|
||||
const xRegisterSSE
|
||||
xmm0( 0 ), xmm1( 1 ),
|
||||
|
@ -165,284 +175,207 @@ const char *const x86_regnames_mmx[8] =
|
|||
"mm4", "mm5", "mm6", "mm7"
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Internal
|
||||
const char* xRegisterBase::GetName()
|
||||
{
|
||||
if( Id == xRegId_Invalid ) return "invalid";
|
||||
if( Id == xRegId_Empty ) return "empty";
|
||||
|
||||
template< typename T >
|
||||
const char* xGetRegName( const xRegister<T>& src )
|
||||
// bad error? Return a "big" error string. Might break formatting of register tables
|
||||
// but that's the least of your worries if you see this baby.
|
||||
if( Id >= 8 || Id <= -3 ) return "!Register index out of range!";
|
||||
|
||||
switch( GetOperandSize() )
|
||||
{
|
||||
if( src.IsEmpty() ) return "empty";
|
||||
switch( sizeof(T) )
|
||||
case 1: return x86_regnames_gpr8[ Id ];
|
||||
case 2: return x86_regnames_gpr16[ Id ];
|
||||
case 4: return x86_regnames_gpr32[ Id ];
|
||||
case 8: return x86_regnames_mmx[ Id ];
|
||||
case 16: return x86_regnames_sse[ Id ];
|
||||
}
|
||||
|
||||
return "oops?";
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Performance note: VC++ wants to use byte/word register form for the following
|
||||
// ModRM/SibSB constructors when we use xWrite<u8>, and furthermore unrolls the
|
||||
// the shift using a series of ADDs for the following results:
|
||||
// add cl,cl
|
||||
// add cl,cl
|
||||
// add cl,cl
|
||||
// or cl,bl
|
||||
// add cl,cl
|
||||
// ... etc.
|
||||
//
|
||||
// This is unquestionably bad optimization by Core2 standard, an generates tons of
|
||||
// register aliases and false dependencies. (although may have been ideal for early-
|
||||
// brand P4s with a broken barrel shifter?). The workaround is to do our own manual
|
||||
// x86Ptr access and update using a u32 instead of u8. Thanks to little endianness,
|
||||
// the same end result is achieved and no false dependencies are generated. The draw-
|
||||
// back is that it clobbers 3 bytes past the end of the write, which could cause a
|
||||
// headache for someone who himself is doing some kind of headache-inducing amount of
|
||||
// recompiler SMC. So we don't do a work-around, and just hope for the compiler to
|
||||
// stop sucking someday instead. :)
|
||||
//
|
||||
// (btw, I know this isn't a critical performance item by any means, but it's
|
||||
// annoying simply because it *should* be an easy thing to optimize)
|
||||
|
||||
static __forceinline void ModRM( uint mod, uint reg, uint rm )
|
||||
{
|
||||
xWrite8( (mod << 6) | (reg << 3) | rm );
|
||||
}
|
||||
|
||||
static __forceinline void SibSB( u32 ss, u32 index, u32 base )
|
||||
{
|
||||
xWrite8( (ss << 6) | (index << 3) | base );
|
||||
}
|
||||
|
||||
void EmitSibMagic( uint regfield, const void* address )
|
||||
{
|
||||
ModRM( 0, regfield, ModRm_UseDisp32 );
|
||||
xWrite<s32>( (s32)address );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// emitter helpers for xmm instruction with prefixes, most of which are using
|
||||
// the basic opcode format (items inside braces denote optional or conditional
|
||||
// emission):
|
||||
//
|
||||
// [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB]
|
||||
//
|
||||
// Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or
|
||||
// 0x3a [and other value will result in assertion failue].
|
||||
//
|
||||
__emitinline void xOpWrite0F( u8 prefix, u16 opcode, int instId, const ModSibBase& sib )
|
||||
{
|
||||
SimdPrefix( prefix, opcode );
|
||||
EmitSibMagic( instId, sib );
|
||||
}
|
||||
|
||||
__emitinline void xOpWrite0F( u8 prefix, u16 opcode, int instId, const void* data )
|
||||
{
|
||||
SimdPrefix( prefix, opcode );
|
||||
EmitSibMagic( instId, data );
|
||||
}
|
||||
|
||||
__emitinline void xOpWrite0F( u16 opcode, int instId, const ModSibBase& sib )
|
||||
{
|
||||
xOpWrite0F( 0, opcode, instId, sib );
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// returns TRUE if this instruction requires SIB to be encoded, or FALSE if the
|
||||
// instruction ca be encoded as ModRm alone.
|
||||
static __forceinline bool NeedsSibMagic( const ModSibBase& info )
|
||||
{
|
||||
// no registers? no sibs!
|
||||
// (ModSibBase::Reduce always places a register in Index, and optionally leaves
|
||||
// Base empty if only register is specified)
|
||||
if( info.Index.IsEmpty() ) return false;
|
||||
|
||||
// A scaled register needs a SIB
|
||||
if( info.Scale != 0 ) return true;
|
||||
|
||||
// two registers needs a SIB
|
||||
if( !info.Base.IsEmpty() ) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Conditionally generates Sib encoding information!
|
||||
//
|
||||
// regfield - register field to be written to the ModRm. This is either a register specifier
|
||||
// or an opcode extension. In either case, the instruction determines the value for us.
|
||||
//
|
||||
void EmitSibMagic( uint regfield, const ModSibBase& info )
|
||||
{
|
||||
pxAssertDev( regfield < 8, "Invalid x86 register identifier." );
|
||||
|
||||
int displacement_size = (info.Displacement == 0) ? 0 :
|
||||
( ( info.IsByteSizeDisp() ) ? 1 : 2 );
|
||||
|
||||
if( !NeedsSibMagic( info ) )
|
||||
{
|
||||
// Use ModRm-only encoding, with the rm field holding an index/base register, if
|
||||
// one has been specified. If neither register is specified then use Disp32 form,
|
||||
// which is encoded as "EBP w/o displacement" (which is why EBP must always be
|
||||
// encoded *with* a displacement of 0, if it would otherwise not have one).
|
||||
|
||||
if( info.Index.IsEmpty() )
|
||||
{
|
||||
case 1: return x86_regnames_gpr8[ src.Id ];
|
||||
case 2: return x86_regnames_gpr16[ src.Id ];
|
||||
case 4: return x86_regnames_gpr32[ src.Id ];
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Performance note: VC++ wants to use byte/word register form for the following
|
||||
// ModRM/SibSB constructors when we use xWrite<u8>, and furthermore unrolls the
|
||||
// the shift using a series of ADDs for the following results:
|
||||
// add cl,cl
|
||||
// add cl,cl
|
||||
// add cl,cl
|
||||
// or cl,bl
|
||||
// add cl,cl
|
||||
// ... etc.
|
||||
//
|
||||
// This is unquestionably bad optimization by Core2 standard, an generates tons of
|
||||
// register aliases and false dependencies. (although may have been ideal for early-
|
||||
// brand P4s with a broken barrel shifter?). The workaround is to do our own manual
|
||||
// x86Ptr access and update using a u32 instead of u8. Thanks to little endianness,
|
||||
// the same end result is achieved and no false dependencies are generated. The draw-
|
||||
// back is that it clobbers 3 bytes past the end of the write, which could cause a
|
||||
// headache for someone who himself is doing some kind of headache-inducing amount of
|
||||
// recompiler SMC. So we don't do a work-around, and just hope for the compiler to
|
||||
// stop sucking someday instead. :)
|
||||
//
|
||||
// (btw, I know this isn't a critical performance item by any means, but it's
|
||||
// annoying simply because it *should* be an easy thing to optimize)
|
||||
|
||||
static __forceinline void ModRM( uint mod, uint reg, uint rm )
|
||||
{
|
||||
xWrite8( (mod << 6) | (reg << 3) | rm );
|
||||
}
|
||||
|
||||
static __forceinline void SibSB( u32 ss, u32 index, u32 base )
|
||||
{
|
||||
xWrite8( (ss << 6) | (index << 3) | base );
|
||||
}
|
||||
|
||||
__forceinline void EmitSibMagic( uint regfield, const void* address )
|
||||
{
|
||||
ModRM( 0, regfield, ModRm_UseDisp32 );
|
||||
xWrite<s32>( (s32)address );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// emitter helpers for xmm instruction with prefixes, most of which are using
|
||||
// the basic opcode format (items inside braces denote optional or conditional
|
||||
// emission):
|
||||
//
|
||||
// [Prefix] / 0x0f / [OpcodePrefix] / Opcode / ModRM+[SibSB]
|
||||
//
|
||||
// Prefixes are typically 0x66, 0xf2, or 0xf3. OpcodePrefixes are either 0x38 or
|
||||
// 0x3a [and other value will result in assertion failue].
|
||||
//
|
||||
__emitinline void xOpWrite0F( u8 prefix, u16 opcode, int instId, const ModSibBase& sib )
|
||||
{
|
||||
SimdPrefix( prefix, opcode );
|
||||
EmitSibMagic( instId, sib );
|
||||
}
|
||||
|
||||
__emitinline void xOpWrite0F( u8 prefix, u16 opcode, int instId, const void* data )
|
||||
{
|
||||
SimdPrefix( prefix, opcode );
|
||||
EmitSibMagic( instId, data );
|
||||
}
|
||||
|
||||
__emitinline void xOpWrite0F( u16 opcode, int instId, const ModSibBase& sib )
|
||||
{
|
||||
xOpWrite0F( 0, opcode, instId, sib );
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// returns TRUE if this instruction requires SIB to be encoded, or FALSE if the
|
||||
// instruction ca be encoded as ModRm alone.
|
||||
static __forceinline bool NeedsSibMagic( const ModSibBase& info )
|
||||
{
|
||||
// no registers? no sibs!
|
||||
// (ModSibBase::Reduce always places a register in Index, and optionally leaves
|
||||
// Base empty if only register is specified)
|
||||
if( info.Index.IsEmpty() ) return false;
|
||||
|
||||
// A scaled register needs a SIB
|
||||
if( info.Scale != 0 ) return true;
|
||||
|
||||
// two registers needs a SIB
|
||||
if( !info.Base.IsEmpty() ) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Conditionally generates Sib encoding information!
|
||||
//
|
||||
// regfield - register field to be written to the ModRm. This is either a register specifier
|
||||
// or an opcode extension. In either case, the instruction determines the value for us.
|
||||
//
|
||||
__noinline void EmitSibMagic( uint regfield, const ModSibBase& info )
|
||||
{
|
||||
pxAssertDev( regfield < 8, "Invalid x86 register identifier." );
|
||||
|
||||
int displacement_size = (info.Displacement == 0) ? 0 :
|
||||
( ( info.IsByteSizeDisp() ) ? 1 : 2 );
|
||||
|
||||
if( !NeedsSibMagic( info ) )
|
||||
{
|
||||
// Use ModRm-only encoding, with the rm field holding an index/base register, if
|
||||
// one has been specified. If neither register is specified then use Disp32 form,
|
||||
// which is encoded as "EBP w/o displacement" (which is why EBP must always be
|
||||
// encoded *with* a displacement of 0, if it would otherwise not have one).
|
||||
|
||||
if( info.Index.IsEmpty() )
|
||||
{
|
||||
EmitSibMagic( regfield, (void*)info.Displacement );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( info.Index == ebp && displacement_size == 0 )
|
||||
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
|
||||
|
||||
ModRM( displacement_size, regfield, info.Index.Id );
|
||||
}
|
||||
EmitSibMagic( regfield, (void*)info.Displacement );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In order to encode "just" index*scale (and no base), we have to encode
|
||||
// it as a special [index*scale + displacement] form, which is done by
|
||||
// specifying EBP as the base register and setting the displacement field
|
||||
// to zero. (same as ModRm w/o SIB form above, basically, except the
|
||||
// ModRm_UseDisp flag is specified in the SIB instead of the ModRM field).
|
||||
if( info.Index == ebp && displacement_size == 0 )
|
||||
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
|
||||
|
||||
if( info.Base.IsEmpty() )
|
||||
{
|
||||
ModRM( 0, regfield, ModRm_UseSib );
|
||||
SibSB( info.Scale, info.Index.Id, ModRm_UseDisp32 );
|
||||
xWrite<s32>( info.Displacement );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( info.Base == ebp && displacement_size == 0 )
|
||||
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
|
||||
|
||||
ModRM( displacement_size, regfield, ModRm_UseSib );
|
||||
SibSB( info.Scale, info.Index.Id, info.Base.Id );
|
||||
}
|
||||
ModRM( displacement_size, regfield, info.Index.Id );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// In order to encode "just" index*scale (and no base), we have to encode
|
||||
// it as a special [index*scale + displacement] form, which is done by
|
||||
// specifying EBP as the base register and setting the displacement field
|
||||
// to zero. (same as ModRm w/o SIB form above, basically, except the
|
||||
// ModRm_UseDisp flag is specified in the SIB instead of the ModRM field).
|
||||
|
||||
if( displacement_size != 0 )
|
||||
if( info.Base.IsEmpty() )
|
||||
{
|
||||
if( displacement_size == 1 )
|
||||
xWrite<s8>( info.Displacement );
|
||||
else
|
||||
xWrite<s32>( info.Displacement );
|
||||
ModRM( 0, regfield, ModRm_UseSib );
|
||||
SibSB( info.Scale, info.Index.Id, ModRm_UseDisp32 );
|
||||
xWrite<s32>( info.Displacement );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( info.Base == ebp && displacement_size == 0 )
|
||||
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
|
||||
|
||||
ModRM( displacement_size, regfield, ModRm_UseSib );
|
||||
SibSB( info.Scale, info.Index.Id, info.Base.Id );
|
||||
}
|
||||
}
|
||||
|
||||
if( displacement_size != 0 )
|
||||
{
|
||||
if( displacement_size == 1 )
|
||||
xWrite<s8>( info.Displacement );
|
||||
else
|
||||
xWrite<s32>( info.Displacement );
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Internal;
|
||||
// Writes a ModRM byte for "Direct" register access forms, which is used for all
|
||||
// instructions taking a form of [reg,reg].
|
||||
void EmitSibMagic( uint reg1, const xRegisterBase& reg2 )
|
||||
{
|
||||
xWrite8( (Mod_Direct << 6) | (reg1 << 3) | reg2.Id );
|
||||
}
|
||||
|
||||
const MovImplAll xMOV;
|
||||
const xImpl_Test xTEST;
|
||||
void EmitSibMagic( const xRegisterBase& reg1, const xRegisterBase& reg2 )
|
||||
{
|
||||
xWrite8( (Mod_Direct << 6) | (reg1.Id << 3) | reg2.Id );
|
||||
}
|
||||
|
||||
const xImpl_G1Logic<G1Type_AND,0x54> xAND;
|
||||
const xImpl_G1Logic<G1Type_OR,0x56> xOR;
|
||||
const xImpl_G1Logic<G1Type_XOR,0x57> xXOR;
|
||||
void EmitSibMagic( const xRegisterBase& reg1, const void* src )
|
||||
{
|
||||
EmitSibMagic( reg1.Id, src );
|
||||
}
|
||||
|
||||
const xImpl_G1Arith<G1Type_ADD,0x58> xADD;
|
||||
const xImpl_G1Arith<G1Type_SUB,0x5c> xSUB;
|
||||
void EmitSibMagic( const xRegisterBase& reg1, const ModSibBase& sib )
|
||||
{
|
||||
EmitSibMagic( reg1.Id, sib );
|
||||
}
|
||||
|
||||
const xImpl_Group1<G1Type_ADC> xADC;
|
||||
const xImpl_Group1<G1Type_SBB> xSBB;
|
||||
const xImpl_G1Compare xCMP;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xSetPtr / xAlignPtr / xGetPtr / xAdvancePtr
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
const Group2ImplAll<G2Type_ROL> xROL;
|
||||
const Group2ImplAll<G2Type_ROR> xROR;
|
||||
const Group2ImplAll<G2Type_RCL> xRCL;
|
||||
const Group2ImplAll<G2Type_RCR> xRCR;
|
||||
const Group2ImplAll<G2Type_SHL> xSHL;
|
||||
const Group2ImplAll<G2Type_SHR> xSHR;
|
||||
const Group2ImplAll<G2Type_SAR> xSAR;
|
||||
|
||||
const xImpl_Group3<G3Type_NOT> xNOT;
|
||||
const xImpl_Group3<G3Type_NEG> xNEG;
|
||||
const xImpl_Group3<G3Type_MUL> xUMUL;
|
||||
const xImpl_Group3<G3Type_DIV> xUDIV;
|
||||
const xImpl_iDiv xDIV;
|
||||
const xImpl_iMul xMUL;
|
||||
|
||||
const xImpl_IncDec<false> xINC;
|
||||
const xImpl_IncDec<true> xDEC;
|
||||
|
||||
const MovExtendImplAll<false> xMOVZX;
|
||||
const MovExtendImplAll<true> xMOVSX;
|
||||
|
||||
const DwordShiftImplAll<false> xSHLD;
|
||||
const DwordShiftImplAll<true> xSHRD;
|
||||
|
||||
const xImpl_Group8<G8Type_BT> xBT;
|
||||
const xImpl_Group8<G8Type_BTR> xBTR;
|
||||
const xImpl_Group8<G8Type_BTS> xBTS;
|
||||
const xImpl_Group8<G8Type_BTC> xBTC;
|
||||
|
||||
const xImpl_BitScan<0xbc> xBSF;
|
||||
const xImpl_BitScan<0xbd> xBSR;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
const CMovImplGeneric xCMOV;
|
||||
|
||||
const CMovImplAll<Jcc_Above> xCMOVA;
|
||||
const CMovImplAll<Jcc_AboveOrEqual> xCMOVAE;
|
||||
const CMovImplAll<Jcc_Below> xCMOVB;
|
||||
const CMovImplAll<Jcc_BelowOrEqual> xCMOVBE;
|
||||
|
||||
const CMovImplAll<Jcc_Greater> xCMOVG;
|
||||
const CMovImplAll<Jcc_GreaterOrEqual> xCMOVGE;
|
||||
const CMovImplAll<Jcc_Less> xCMOVL;
|
||||
const CMovImplAll<Jcc_LessOrEqual> xCMOVLE;
|
||||
|
||||
const CMovImplAll<Jcc_Zero> xCMOVZ;
|
||||
const CMovImplAll<Jcc_Equal> xCMOVE;
|
||||
const CMovImplAll<Jcc_NotZero> xCMOVNZ;
|
||||
const CMovImplAll<Jcc_NotEqual> xCMOVNE;
|
||||
|
||||
const CMovImplAll<Jcc_Overflow> xCMOVO;
|
||||
const CMovImplAll<Jcc_NotOverflow> xCMOVNO;
|
||||
const CMovImplAll<Jcc_Carry> xCMOVC;
|
||||
const CMovImplAll<Jcc_NotCarry> xCMOVNC;
|
||||
|
||||
const CMovImplAll<Jcc_Signed> xCMOVS;
|
||||
const CMovImplAll<Jcc_Unsigned> xCMOVNS;
|
||||
const CMovImplAll<Jcc_ParityEven> xCMOVPE;
|
||||
const CMovImplAll<Jcc_ParityOdd> xCMOVPO;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
const SetImplGeneric xSET;
|
||||
|
||||
const SetImplAll<Jcc_Above> xSETA;
|
||||
const SetImplAll<Jcc_AboveOrEqual> xSETAE;
|
||||
const SetImplAll<Jcc_Below> xSETB;
|
||||
const SetImplAll<Jcc_BelowOrEqual> xSETBE;
|
||||
|
||||
const SetImplAll<Jcc_Greater> xSETG;
|
||||
const SetImplAll<Jcc_GreaterOrEqual> xSETGE;
|
||||
const SetImplAll<Jcc_Less> xSETL;
|
||||
const SetImplAll<Jcc_LessOrEqual> xSETLE;
|
||||
|
||||
const SetImplAll<Jcc_Zero> xSETZ;
|
||||
const SetImplAll<Jcc_Equal> xSETE;
|
||||
const SetImplAll<Jcc_NotZero> xSETNZ;
|
||||
const SetImplAll<Jcc_NotEqual> xSETNE;
|
||||
|
||||
const SetImplAll<Jcc_Overflow> xSETO;
|
||||
const SetImplAll<Jcc_NotOverflow> xSETNO;
|
||||
const SetImplAll<Jcc_Carry> xSETC;
|
||||
const SetImplAll<Jcc_NotCarry> xSETNC;
|
||||
|
||||
const SetImplAll<Jcc_Signed> xSETS;
|
||||
const SetImplAll<Jcc_Unsigned> xSETNS;
|
||||
const SetImplAll<Jcc_ParityEven> xSETPE;
|
||||
const SetImplAll<Jcc_ParityOdd> xSETPO;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Assigns the current emitter buffer target address.
|
||||
// This is provided instead of using x86Ptr directly, since we may in the future find
|
||||
// a need to change the storage class system for the x86Ptr 'under the hood.'
|
||||
|
@ -451,7 +384,6 @@ __emitinline void xSetPtr( void* ptr )
|
|||
x86Ptr = (u8*)ptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Retrieves the current emitter buffer target address.
|
||||
// This is provided instead of using x86Ptr directly, since we may in the future find
|
||||
// a need to change the storage class system for the x86Ptr 'under the hood.'
|
||||
|
@ -460,14 +392,12 @@ __emitinline u8* xGetPtr()
|
|||
return x86Ptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
__emitinline void xAlignPtr( uint bytes )
|
||||
{
|
||||
// forward align
|
||||
x86Ptr = (u8*)( ( (uptr)x86Ptr + bytes - 1) & ~(bytes - 1) );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
__emitinline void xAdvancePtr( uint bytes )
|
||||
{
|
||||
if( IsDevBuild )
|
||||
|
@ -480,6 +410,66 @@ __emitinline void xAdvancePtr( uint bytes )
|
|||
x86Ptr += bytes;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// xAddressInfo Method Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
xAddressInfo& xAddressInfo::Add( const xAddressReg& src )
|
||||
{
|
||||
if( src == Index )
|
||||
{
|
||||
Factor++;
|
||||
}
|
||||
else if( src == Base )
|
||||
{
|
||||
// Compound the existing register reference into the Index/Scale pair.
|
||||
Base = xEmptyReg;
|
||||
|
||||
if( src == Index )
|
||||
Factor++;
|
||||
else
|
||||
{
|
||||
pxAssertDev( Index.IsEmpty(), "x86Emitter: Only one scaled index register is allowed in an address modifier." );
|
||||
Index = src;
|
||||
Factor = 2;
|
||||
}
|
||||
}
|
||||
else if( Base.IsEmpty() )
|
||||
Base = src;
|
||||
else if( Index.IsEmpty() )
|
||||
Index = src;
|
||||
else
|
||||
pxFailDev( L"x86Emitter: address modifiers cannot have more than two index registers." ); // oops, only 2 regs allowed per ModRm!
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
xAddressInfo& xAddressInfo::Add( const xAddressInfo& src )
|
||||
{
|
||||
Add( src.Base );
|
||||
Add( src.Displacement );
|
||||
|
||||
// If the factor is 1, we can just treat index like a base register also.
|
||||
if( src.Factor == 1 )
|
||||
{
|
||||
Add( src.Index );
|
||||
}
|
||||
else if( Index.IsEmpty() )
|
||||
{
|
||||
Index = src.Index;
|
||||
Factor = src.Factor;
|
||||
}
|
||||
else if( Index == src.Index )
|
||||
{
|
||||
Factor += src.Factor;
|
||||
}
|
||||
else
|
||||
pxFailDev( L"x86Emitter: address modifiers cannot have more than two index registers." ); // oops, only 2 regs allowed per ModRm!
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Generates a 'reduced' ModSib form, which has valid Base, Index, and Scale values.
|
||||
// Necessary because by default ModSib compounds registers into Index when possible.
|
||||
|
@ -515,7 +505,7 @@ void ModSibBase::Reduce()
|
|||
Index = Base;
|
||||
Scale = 0;
|
||||
if( !Base.IsStackPointer() ) // prevent ESP from being encoded 'alone'
|
||||
Base = xAddressReg::Empty;
|
||||
Base = xEmptyReg;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -567,11 +557,8 @@ void ModSibBase::Reduce()
|
|||
// preserve_flags - set to ture to disable use of SHL on [Index*Base] forms
|
||||
// of LEA, which alters flags states.
|
||||
//
|
||||
template< typename OperandType >
|
||||
static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool preserve_flags )
|
||||
static void EmitLeaMagic( const xRegisterInt& to, const ModSibBase& src, bool preserve_flags )
|
||||
{
|
||||
typedef xRegister<OperandType> ToReg;
|
||||
|
||||
int displacement_size = (src.Displacement == 0) ? 0 :
|
||||
( ( src.IsByteSizeDisp() ) ? 1 : 2 );
|
||||
|
||||
|
@ -590,7 +577,7 @@ static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool
|
|||
}
|
||||
else if( displacement_size == 0 )
|
||||
{
|
||||
xMOV( to, ToReg( src.Index.Id ) );
|
||||
_xMovRtoR( to, src.Index );
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -600,7 +587,7 @@ static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool
|
|||
// 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.
|
||||
|
||||
xMOV( to, ToReg( src.Index.Id ) );
|
||||
_xMovRtoR( to, src.Index );
|
||||
xADD( to, src.Displacement );
|
||||
return;
|
||||
}
|
||||
|
@ -627,7 +614,7 @@ static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool
|
|||
// (this does not apply to older model P4s with the broken barrel shifter,
|
||||
// but we currently aren't optimizing for that target anyway).
|
||||
|
||||
xMOV( to, ToReg( src.Index.Id ) );
|
||||
_xMovRtoR( to, src.Index );
|
||||
xSHL( to, src.Scale );
|
||||
return;
|
||||
}
|
||||
|
@ -646,14 +633,14 @@ static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool
|
|||
if( src.Index == esp )
|
||||
{
|
||||
// ESP is not encodable as an index (ix86 ignores it), thus:
|
||||
xMOV( to, ToReg( src.Base.Id ) ); // will do the trick!
|
||||
_xMovRtoR( to, src.Base ); // will do the trick!
|
||||
if( src.Displacement ) xADD( to, src.Displacement );
|
||||
return;
|
||||
}
|
||||
else if( src.Displacement == 0 )
|
||||
{
|
||||
xMOV( to, ToReg( src.Base.Id ) );
|
||||
xADD( to, ToReg( src.Index.Id ) );
|
||||
_xMovRtoR( to, src.Base );
|
||||
_g1_EmitOp( G1Type_ADD, to, src.Index );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -662,7 +649,7 @@ static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool
|
|||
// special case handling of ESP as Index, which is replaceable with
|
||||
// a single MOV even when preserve_flags is set! :D
|
||||
|
||||
xMOV( to, ToReg( src.Base.Id ) );
|
||||
_xMovRtoR( to, src.Base );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -697,6 +684,112 @@ __emitinline void xLEA( xRegister16 to, const ModSibBase& src, bool preserve_fla
|
|||
EmitLeaMagic( to, src, preserve_flags );
|
||||
}
|
||||
|
||||
// =====================================================================================================
|
||||
// TEST / INC / DEC
|
||||
// =====================================================================================================
|
||||
void xImpl_Test::operator()( const xRegister8& to, const xRegister8& from ) const
|
||||
{
|
||||
xWrite8( 0x84 );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
|
||||
void xImpl_Test::operator()( const xRegister16& to, const xRegister16& from ) const
|
||||
{
|
||||
to.prefix16();
|
||||
xWrite8( 0x85 );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
|
||||
void xImpl_Test::operator()( const xRegister32& to, const xRegister32& from ) const
|
||||
{
|
||||
xWrite8( 0x85 );
|
||||
EmitSibMagic( from, to );
|
||||
}
|
||||
|
||||
void xImpl_Test::operator()( const ModSib32orLess& dest, int imm ) const
|
||||
{
|
||||
dest.prefix16();
|
||||
xWrite8( dest.Is8BitOp() ? 0xf6 : 0xf7 );
|
||||
EmitSibMagic( 0, dest );
|
||||
dest.xWriteImm( imm );
|
||||
}
|
||||
|
||||
void xImpl_Test::operator()( const xRegisterInt& to, int imm ) const
|
||||
{
|
||||
to.prefix16();
|
||||
|
||||
if( to.IsAccumulator() )
|
||||
xWrite8( to.Is8BitOp() ? 0xa8 : 0xa9 );
|
||||
else
|
||||
{
|
||||
xWrite8( to.Is8BitOp() ? 0xf6 : 0xf7 );
|
||||
EmitSibMagic( 0, to );
|
||||
}
|
||||
to.xWriteImm( imm );
|
||||
}
|
||||
|
||||
void xImpl_BitScan::operator()( const xRegister32& to, const xRegister32& from ) const { xOpWrite0F( Opcode, to, from ); }
|
||||
void xImpl_BitScan::operator()( const xRegister16& to, const xRegister16& from ) const { xOpWrite0F( 0x66, Opcode, to, from ); }
|
||||
void xImpl_BitScan::operator()( const xRegister16or32& to, const ModSibBase& sibsrc ) const
|
||||
{
|
||||
xOpWrite0F( (to->GetOperandSize() == 2) ? 0x66 : 0x00, Opcode, to, sibsrc );
|
||||
}
|
||||
|
||||
void xImpl_IncDec::operator()( const xRegisterInt& to ) const
|
||||
{
|
||||
if( to.Is8BitOp() )
|
||||
{
|
||||
xWrite8( 0xfe );
|
||||
EmitSibMagic( isDec ? 1 : 0, to );
|
||||
}
|
||||
else
|
||||
{
|
||||
to.prefix16();
|
||||
xWrite8( (isDec ? 0x48 : 0x40) | to.Id );
|
||||
}
|
||||
}
|
||||
|
||||
void xImpl_IncDec::operator()( const ModSib32orLess& to ) const
|
||||
{
|
||||
to.prefix16();
|
||||
xWrite8( to.Is8BitOp() ? 0xfe : 0xff );
|
||||
EmitSibMagic( isDec ? 1 : 0, to );
|
||||
}
|
||||
|
||||
void xImpl_DwordShift::operator()( const xRegister32& to, const xRegister32& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( OpcodeBase+1, to, from ); }
|
||||
void xImpl_DwordShift::operator()( const xRegister16& to, const xRegister16& from, const xRegisterCL& /* clreg */ ) const { xOpWrite0F( 0x66, OpcodeBase+1, to, from ); }
|
||||
void xImpl_DwordShift::operator()( const xRegister32& to, const xRegister32& from, u8 shiftcnt ) const
|
||||
{
|
||||
if( shiftcnt != 0 )
|
||||
xOpWrite0F( OpcodeBase, to, from );
|
||||
}
|
||||
void xImpl_DwordShift::operator()( const xRegister16& to, const xRegister16& from, u8 shiftcnt ) const
|
||||
{
|
||||
if( shiftcnt != 0 )
|
||||
xOpWrite0F( 0x66, OpcodeBase, to, from );
|
||||
}
|
||||
|
||||
void xImpl_DwordShift::operator()( const ModSibBase& dest, const xRegister16or32& from, const xRegisterCL& /* clreg */ ) const
|
||||
{
|
||||
xOpWrite0F( (from->GetOperandSize() == 2) ? 0x66 : 0x00, OpcodeBase, from, dest );
|
||||
}
|
||||
|
||||
void xImpl_DwordShift::operator()( const ModSibBase& dest, const xRegister16or32& from, u8 shiftcnt ) const
|
||||
{
|
||||
if( shiftcnt != 0 )
|
||||
xOpWrite0F( (from->GetOperandSize() == 2) ? 0x66 : 0x00, OpcodeBase, from, dest, shiftcnt );
|
||||
}
|
||||
|
||||
const xImpl_Test xTEST;
|
||||
|
||||
const xImpl_BitScan xBSF = { 0xbc };
|
||||
const xImpl_BitScan xBSR = { 0xbd };
|
||||
|
||||
const xImpl_IncDec xINC = { false };
|
||||
const xImpl_IncDec xDEC = { true };
|
||||
|
||||
const xImpl_DwordShift xSHLD = { 0xa4 };
|
||||
const xImpl_DwordShift xSHRD = { 0xac };
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Push / Pop Emitters
|
||||
|
|
Loading…
Reference in New Issue