Merge pull request #1123 from PCSX2/emitter-Trex

Emitter trex
This commit is contained in:
Gregory Hainaut 2016-01-21 22:32:37 +01:00
commit 9e773ff980
5 changed files with 153 additions and 167 deletions

View File

@ -31,11 +31,12 @@ namespace x86Emitter {
extern void EmitSibMagic( const xRegisterBase& reg1, const void* src );
extern void EmitSibMagic( const xRegisterBase& reg1, const xIndirectVoid& sib );
void EmitRex( const xRegisterBase& reg1, const xRegisterBase& reg2 );
void EmitRex( const xRegisterBase& reg1, const void* src );
void EmitRex( const xRegisterBase& reg1, const xIndirectVoid& sib );
void EmitRex( const xRegisterBase& reg1 );
void EmitRex( const xIndirectVoid& sib );
extern void EmitRex( uint regfield, const void* address );
extern void EmitRex( uint regfield, const xIndirectVoid& info );
extern void EmitRex( uint reg1, const xRegisterBase& reg2 );
extern void EmitRex( const xRegisterBase& reg1, const xRegisterBase& reg2 );
extern void EmitRex( const xRegisterBase& reg1, const void* src );
extern void EmitRex( const xRegisterBase& reg1, const xIndirectVoid& sib );
extern void _xMovRtoR( const xRegisterInt& to, const xRegisterInt& from );
@ -49,18 +50,42 @@ namespace x86Emitter {
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 );
if( prefix != 0 ) xWrite8( prefix );
EmitRex( param1, param2 );
xWrite8( opcode );
EmitSibMagic( param1, param2 );
}
template< typename T1, typename T2 > __emitinline
void xOpAccWrite( u8 prefix, u8 opcode, const T1& param1, const T2& param2 )
{
if( prefix != 0 ) xWrite8( prefix );
EmitRex( param1, param2 );
xWrite8( opcode );
}
//////////////////////////////////////////////////////////////////////////////////////////
// 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].
//
template< typename T1, typename T2 > __emitinline
void xOpWrite0F( u8 prefix, u16 opcode, const T1& param1, const T2& param2 )
{
SimdPrefix( prefix, opcode );
if( prefix != 0 ) xWrite8( prefix );
EmitRex( param1, param2 );
SimdPrefix( 0, opcode );
EmitSibMagic( param1, param2 );
}

View File

@ -45,15 +45,15 @@ static void _g1_IndirectImm( G1Type InstType, const xIndirect64orLess& sibdest,
{
if( sibdest.Is8BitOp() )
{
xWrite8( 0x80 );
EmitSibMagic( InstType, sibdest );
xOpWrite( sibdest.GetPrefix16(), 0x80, InstType, sibdest );
xWrite<s8>( imm );
}
else
{
sibdest.prefix16();
xWrite8( is_s8( imm ) ? 0x83 : 0x81 );
EmitSibMagic( InstType, sibdest );
u8 opcode = is_s8( imm ) ? 0x83 : 0x81;
xOpWrite( sibdest.GetPrefix16(), opcode, InstType, sibdest );
if( is_s8( imm ) )
xWrite<s8>( imm );
else
@ -64,42 +64,40 @@ static void _g1_IndirectImm( G1Type InstType, const xIndirect64orLess& sibdest,
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 );
u8 opcode = (to.Is8BitOp() ? 0 : 1) | (InstType<<3);
xOpWrite( to.GetPrefix16(), opcode, from, to );
}
static void _g1_EmitOp( G1Type InstType, const xIndirectVoid& sibdest, const xRegisterInt& from )
{
from.prefix16();
xWrite8( (from.Is8BitOp() ? 0 : 1) | (InstType<<3) );
EmitSibMagic( from, sibdest );
u8 opcode = (from.Is8BitOp() ? 0 : 1) | (InstType<<3);
xOpWrite( from.GetPrefix16(), opcode, from, sibdest );
}
static void _g1_EmitOp( G1Type InstType, const xRegisterInt& to, const xIndirectVoid& sibsrc )
{
to.prefix16();
xWrite8( (to.Is8BitOp() ? 2 : 3) | (InstType<<3) );
EmitSibMagic( to, sibsrc );
u8 opcode = (to.Is8BitOp() ? 2 : 3) | (InstType<<3);
xOpWrite( to.GetPrefix16(), opcode, 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 );
xOpWrite( to.GetPrefix16(), 0x83, InstType, to );
xWrite<s8>( imm );
}
else
{
if( to.IsAccumulator() )
xWrite8( (to.Is8BitOp() ? 4 : 5) | (InstType<<3) );
if( to.IsAccumulator() ) {
u8 opcode = (to.Is8BitOp() ? 4 : 5) | (InstType<<3);
xOpAccWrite( to.GetPrefix16(), opcode, InstType, to );
}
else
{
xWrite8( to.Is8BitOp() ? 0x80 : 0x81 );
EmitSibMagic( InstType, to );
u8 opcode = to.Is8BitOp() ? 0x80 : 0x81;
xOpWrite( to.GetPrefix16(), opcode, InstType, to );
}
to.xWriteImm( imm );
}
@ -134,52 +132,42 @@ const xImpl_Group1 xSBB = { G1Type_SBB };
void xImpl_Group2::operator()( const xRegisterInt& to, const xRegisterCL& /* from */ ) const
{
to.prefix16();
xWrite8( to.Is8BitOp() ? 0xd2 : 0xd3 );
EmitSibMagic( InstType, to );
xOpWrite( to.GetPrefix16(), to.Is8BitOp() ? 0xd2 : 0xd3, 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 );
xOpWrite( to.GetPrefix16(), to.Is8BitOp() ? 0xd0 : 0xd1, InstType, to );
}
else
{
xWrite8( to.Is8BitOp() ? 0xc0 : 0xc1 );
EmitSibMagic( InstType, to );
xOpWrite( to.GetPrefix16(), to.Is8BitOp() ? 0xc0 : 0xc1, InstType, to );
xWrite8( imm );
}
}
void xImpl_Group2::operator()( const xIndirect64orLess& sibdest, const xRegisterCL& /* from */ ) const
{
sibdest.prefix16();
xWrite8( sibdest.Is8BitOp() ? 0xd2 : 0xd3 );
EmitSibMagic( InstType, sibdest );
xOpWrite( sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd2 : 0xd3, InstType, sibdest );
}
void xImpl_Group2::operator()( const xIndirect64orLess& 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 );
xOpWrite( sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xd0 : 0xd1, InstType, sibdest );
}
else
{
xWrite8( sibdest.Is8BitOp() ? 0xc0 : 0xc1 );
EmitSibMagic( InstType, sibdest );
xOpWrite( sibdest.GetPrefix16(), sibdest.Is8BitOp() ? 0xc0 : 0xc1, InstType, sibdest );
xWrite8( imm );
}
}
@ -199,16 +187,12 @@ const xImpl_Group2 xSAR = { G2Type_SAR };
static void _g3_EmitOp( G3Type InstType, const xRegisterInt& from )
{
from.prefix16();
xWrite8(from.Is8BitOp() ? 0xf6 : 0xf7 );
EmitSibMagic( InstType, from );
xOpWrite( from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from );
}
static void _g3_EmitOp( G3Type InstType, const xIndirect64orLess& from )
{
from.prefix16();
xWrite8( from.Is8BitOp() ? 0xf6 : 0xf7 );
EmitSibMagic( InstType, from );
xOpWrite( from.GetPrefix16(), from.Is8BitOp() ? 0xf6 : 0xf7, InstType, from );
}
void xImpl_Group3::operator()( const xRegisterInt& from ) const { _g3_EmitOp( InstType, from ); }
@ -220,13 +204,9 @@ void xImpl_iDiv::operator()( const xIndirect64orLess& from ) const { _g3_EmitO
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 uint OpSize = param1.GetOperandSize();
pxAssert( param1.GetOperandSize() == param2.GetOperandSize() );
pxAssert( OpSize == param2.GetOperandSize() );
pxAssert( OpSize > 1 );
xOpWrite0F( (OpSize == 2) ? 0x66 : 0, is_s8( imm ) ? 0x6b : 0x69, param1, param2 );
xOpWrite0F( param1.GetPrefix16(), is_s8( imm ) ? 0x6b : 0x69, param1, param2 );
if( is_s8( imm ) )
xWrite8( (u8)imm );

View File

@ -40,9 +40,7 @@ void _xMovRtoR( const xRegisterInt& to, const xRegisterInt& from )
if( to == from ) return; // ignore redundant MOVs.
from.prefix16();
xWrite8( from.Is8BitOp() ? 0x88 : 0x89 );
EmitSibMagic( from, to );
xOpWrite( from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, to );
}
void xImpl_Mov::operator()( const xRegisterInt& to, const xRegisterInt& from ) const
@ -53,47 +51,47 @@ void xImpl_Mov::operator()( const xRegisterInt& to, const xRegisterInt& from ) c
void xImpl_Mov::operator()( const xIndirectVoid& 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 );
// FIXME: in 64 bits, it could be 8B whereas Displacement is limited to 4B normally
#ifdef __x86_64__
pxAssert(0);
#endif
xOpAccWrite( from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from.Id, dest );
xWrite32( dest.Displacement );
}
else
{
xWrite8( from.Is8BitOp() ? 0x88 : 0x89 );
EmitSibMagic( from.Id, dest );
xOpWrite( from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from.Id, dest );
}
}
void xImpl_Mov::operator()( const xRegisterInt& to, const xIndirectVoid& 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 );
// FIXME: in 64 bits, it could be 8B whereas Displacement is limited to 4B normally
#ifdef __x86_64__
pxAssert(0);
#endif
xOpAccWrite( to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src );
xWrite32( src.Displacement );
}
else
{
xWrite8( to.Is8BitOp() ? 0x8a : 0x8b );
EmitSibMagic( to, src );
xOpWrite( to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src );
}
}
void xImpl_Mov::operator()( const xIndirect64orLess& dest, int imm ) const
{
dest.prefix16();
xWrite8( dest.Is8BitOp() ? 0xc6 : 0xc7 );
EmitSibMagic( 0, dest );
xOpWrite( dest.GetPrefix16(), dest.Is8BitOp() ? 0xc6 : 0xc7, 0, dest );
dest.xWriteImm( imm );
}
@ -106,9 +104,8 @@ void xImpl_Mov::operator()( const xRegisterInt& to, int imm, bool preserve_flags
else
{
// Note: MOV does not have (reg16/32,imm8) forms.
to.prefix16();
xWrite8( (to.Is8BitOp() ? 0xb0 : 0xb8) | to.Id );
u8 opcode = (to.Is8BitOp() ? 0xb0 : 0xb8) | to.Id;
xOpAccWrite( to.GetPrefix16(), opcode, 0, to);
to.xWriteImm( imm );
}
}

View File

@ -90,6 +90,9 @@ namespace x86Emitter {
//
__emitinline void SimdPrefix( u8 prefix, u16 opcode )
{
#ifdef __x86_64__
pxAssertMsg(prefix == 0, "REX prefix must be just before the opcode");
#endif
const bool is16BitOpcode = ((opcode & 0xff) == 0x38) || ((opcode & 0xff) == 0x3a);
// If the lower byte is not a valid prefix and the upper byte is non-zero it
@ -220,15 +223,13 @@ void _SimdShiftHelper::operator()( const xRegisterMMX& to, const xIndirectVoid&
void _SimdShiftHelper::operator()( const xRegisterSSE& to, u8 imm8 ) const
{
SimdPrefix( 0x66, OpcodeImm );
EmitSibMagic( (int)Modcode, to );
xOpWrite0F( 0x66, OpcodeImm, (int)Modcode, to );
xWrite8( imm8 );
}
void _SimdShiftHelper::operator()( const xRegisterMMX& to, u8 imm8 ) const
{
SimdPrefix( 0x00, OpcodeImm );
EmitSibMagic( (int)Modcode, to );
xOpWrite0F( 0x00, OpcodeImm, (int)Modcode, to );
xWrite8( imm8 );
}
@ -747,8 +748,7 @@ IMPLEMENT_xMOVS( SD, 0xf2 )
__fi void xMOVNTDQA( const xRegisterSSE& to, const xIndirectVoid& from )
{
xWrite32( 0x2A380f66 );
EmitSibMagic( to.Id, from );
xOpWrite0F( 0x66, 0x2a38, to.Id, from);
}
__fi void xMOVNTDQA( const xIndirectVoid& to, const xRegisterSSE& from ) { xOpWrite0F( 0x66, 0xe7, from, to ); }
@ -833,31 +833,27 @@ __fi void xEMMS() { xWrite16( 0x770F ); }
// Store Streaming SIMD Extension Control/Status to Mem32.
__emitinline void xSTMXCSR( const xIndirect32& dest )
{
SimdPrefix( 0, 0xae );
EmitSibMagic( 3, dest );
xOpWrite0F( 0, 0xae, 3, dest );
}
// Load Streaming SIMD Extension Control/Status from Mem32.
__emitinline void xLDMXCSR( const xIndirect32& src )
{
SimdPrefix( 0, 0xae );
EmitSibMagic( 2, src );
xOpWrite0F( 0, 0xae, 2, src );
}
// Save x87 FPU, MMX Technology, and SSE State to buffer
// Target buffer must be at least 512 bytes in length to hold the result.
__emitinline void xFXSAVE( const xIndirectVoid& dest )
{
SimdPrefix( 0, 0xae );
EmitSibMagic( 0, dest );
xOpWrite0F( 0, 0xae, 0, dest );
}
// Restore x87 FPU, MMX , XMM, and MXCSR State.
// Source buffer should be 512 bytes in length.
__emitinline void xFXRSTOR( const xIndirectVoid& src )
{
SimdPrefix( 0, 0xae );
EmitSibMagic( 1, src );
xOpWrite0F( 0, 0xae, 1, src );
}
}

View File

@ -266,34 +266,6 @@ void EmitSibMagic( uint regfield, const void* address )
xWrite<s32>( (s32)displacement );
}
//////////////////////////////////////////////////////////////////////////////////////////
// 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 xIndirectVoid& 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 xIndirectVoid& 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.
@ -406,51 +378,71 @@ void EmitSibMagic( const xRegisterBase& reg1, const xIndirectVoid& sib )
}
//////////////////////////////////////////////////////////////////////////////////////////
__emitinline static void EmitRex(bool w, bool r, bool x, bool b)
{
#ifdef __x86_64__
u8 rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
if (rex != 0x40)
xWrite8(rex);
#endif
}
void EmitRex( uint regfield, const void* address )
{
pxAssert(0);
bool w = false;
bool r = false;
bool x = false;
bool b = false;
EmitRex(w, r, x, b);
}
void EmitRex( uint regfield, const xIndirectVoid& info )
{
bool w = info.Base.IsWide();
bool r = false;
bool x = false;
bool b = info.IsExtended();
EmitRex(w, r, x, b);
}
void EmitRex( uint reg1, const xRegisterBase& reg2 )
{
bool w = reg2.IsWide();
bool r = false;
bool x = false;
bool b = reg2.IsExtended();
EmitRex(w, r, x, b);
}
void EmitRex( const xRegisterBase& reg1, const xRegisterBase& reg2 )
{
u8 w = reg1.IsWide() << 3;
u8 r = reg1.IsExtended() << 2;
u8 x = 0;
u8 b = reg2.IsExtended();
xWrite8( 0x40 | w | r | x | b );
bool w = reg1.IsWide();
bool r = reg1.IsExtended();
bool x = false;
bool b = reg2.IsExtended();
EmitRex(w, r, x, b);
}
void EmitRex( const xRegisterBase& reg1, const void* src )
{
pxAssert(0); //see fixme
u8 w = reg1.IsWide() << 3;
u8 r = reg1.IsExtended() << 2;
u8 x = 0;
u8 b = 0; // FIXME src.IsExtended();
xWrite8( 0x40 | w | r | x | b );
bool w = reg1.IsWide();
bool r = reg1.IsExtended();
bool x = false;
bool b = false; // FIXME src.IsExtended();
EmitRex(w, r, x, b);
}
void EmitRex( const xRegisterBase& reg1, const xIndirectVoid& sib )
{
u8 w = reg1.IsWide() << 3;
u8 r = reg1.IsExtended() << 2;
u8 x = sib.Index.IsExtended() << 1;
u8 w = reg1.IsWide();
u8 r = reg1.IsExtended();
u8 x = sib.Index.IsExtended();
u8 b = sib.Base.IsExtended();
xWrite8( 0x40 | w | r | x | b );
EmitRex(w, r, x, b);
}
void EmitRex( const xRegisterBase& reg1)
{
u8 w = reg1.IsWide() << 3;
u8 r = 0;
u8 x = 0;
u8 b = reg1.IsExtended();
xWrite8( 0x40 | w | r | x | b );
}
void EmitRex( const xIndirectVoid& sib)
{
u8 w = sib.Base.IsWide() << 3;
u8 r = 0;
u8 x = 0;
u8 b = sib.IsExtended();
xWrite8( 0x40 | w | r | x | b );
}
// --------------------------------------------------------------------------------------
// xSetPtr / xAlignPtr / xGetPtr / xAdvancePtr
@ -929,29 +921,21 @@ __emitinline void xLEA( xRegister16 to, const xIndirectVoid& src, bool preserve_
void xImpl_Test::operator()( const xRegisterInt& to, const xRegisterInt& from ) const
{
pxAssert( to.GetOperandSize() == from.GetOperandSize() );
to.prefix16();
xWrite8( to.Is8BitOp() ? 0x84 : 0x85 );
EmitSibMagic( from, to );
xOpWrite( to.GetPrefix16(), to.Is8BitOp() ? 0x84 : 0x85, from, to );
}
void xImpl_Test::operator()( const xIndirect64orLess& dest, int imm ) const
{
dest.prefix16();
xWrite8( dest.Is8BitOp() ? 0xf6 : 0xf7 );
EmitSibMagic( 0, dest );
xOpWrite( dest.GetPrefix16(), dest.Is8BitOp() ? 0xf6 : 0xf7, 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 );
if( to.IsAccumulator() ) {
xOpAccWrite( to.GetPrefix16(), to.Is8BitOp() ? 0xa8 : 0xa9, 0, to );
} else {
xOpWrite( to.GetPrefix16(), to.Is8BitOp() ? 0xf6 : 0xf7, 0, to );
}
to.xWriteImm( imm );
}
@ -969,11 +953,15 @@ void xImpl_IncDec::operator()( const xRegisterInt& to ) const
{
if( to.Is8BitOp() )
{
xWrite8( 0xfe );
EmitSibMagic( isDec ? 1 : 0, to );
u8 regfield = isDec ? 1 : 0;
xOpWrite( to.GetPrefix16(), 0xfe, regfield, to);
}
else
{
#ifdef __x86_64__
pxAssertMsg(0, "Single Byte INC/DEC aren't valid in 64 bits."
"You need to use the ModR/M form (FF/0 FF/1 opcodes)");
#endif
to.prefix16();
xWrite8( (isDec ? 0x48 : 0x40) | to.Id );
}