Ok, I lied -- more work on the emitter. I forgot to fix up the Jump/Call api yesterday and, along the way, did lots of major cleanups. :)

(and broke linux, probably!)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1054 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-04-24 11:25:10 +00:00
parent 286c405ce9
commit 7394e99ef6
27 changed files with 769 additions and 1059 deletions

View File

@ -2989,13 +2989,13 @@
RelativePath="..\..\x86\ix86\ix86_types.h" RelativePath="..\..\x86\ix86\ix86_types.h"
> >
</File> </File>
<File
RelativePath="..\..\x86\ix86\ix86_writers.inl"
>
</File>
<Filter <Filter
Name="Implement" Name="Implement"
> >
<File
RelativePath="..\..\x86\ix86\implement\bittest.h"
>
</File>
<File <File
RelativePath="..\..\x86\ix86\implement\dwshift.h" RelativePath="..\..\x86\ix86\implement\dwshift.h"
> >

View File

@ -1644,7 +1644,7 @@ StartRecomp:
} }
if (startpc != 0x81fc0) { if (startpc != 0x81fc0) {
xADD(ptr16[&manual_page[inpage_ptr >> 12]], 1); xADD(ptr16[&manual_page[inpage_ptr >> 12]], 1);
iJccKnownTarget(Jcc_Carry, dyna_block_reset); xJC( dyna_block_reset );
} }
DbgCon::WriteLn("Manual block @ %08X : %08X %d %d %d %d", params DbgCon::WriteLn("Manual block @ %08X : %08X %d %d %d %d", params

View File

@ -1,70 +0,0 @@
/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2009 Pcsx2 Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#pragma once
// Implementations found here: BTS/BT/BTC/BTR plus BSF/BSR!
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
// These instructions are in the 'Group8' as per Intel's manual, but since they all have
// a unified purpose, I've named them for that instead.
enum G8Type
{
G8Type_BT = 4,
G8Type_BTS,
G8Type_BTR,
G8Type_BTC,
};
//////////////////////////////////////////////////////////////////////////////////////////
// BSF / BSR -- 16/32 operands supported only.
//
// 0xbc [fwd] / 0xbd [rev]
//
template< u16 Opcode >
class BitScanImpl
{
public:
BitScanImpl() {}
__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 void* src ) const { xOpWrite0F( Opcode, to, src ); }
__forceinline void operator()( const xRegister16& to, const void* src ) const { xOpWrite0F( 0x66, Opcode, to, src ); }
__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 ); }
};
//////////////////////////////////////////////////////////////////////////////////////////
// Bit Test Instructions - Valid on 16/32 bit instructions only.
//
template< G8Type InstType >
class Group8Impl : public BitScanImpl<0xa3 | (InstType << 2)>
{
public:
using BitScanImpl<0xa3 | (InstType << 2)>::operator();
__forceinline void operator()( const ModSibStrict<u32>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0xba, InstType, bitbase ); xWrite<u8>( bitoffset ); }
__forceinline void operator()( const ModSibStrict<u16>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0x66, 0xba, InstType, bitbase ); xWrite<u8>( bitoffset ); }
void operator()( const xRegister<u32>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0xba, InstType, bitbase ); xWrite<u8>( bitoffset ); }
void operator()( const xRegister<u16>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0x66, 0xba, InstType, bitbase ); xWrite<u8>( bitoffset ); }
Group8Impl() {}
};

View File

@ -21,109 +21,34 @@
// Implementations here cover SHLD and SHRD. // Implementations here cover SHLD and SHRD.
// Note: This header is meant to be included from within the x86Emitter::Internal namespace. // Note: This header is meant to be included from within the x86Emitter::Internal namespace.
//////////////////////////////////////////////////////////////////////////////////////////
// -------------------------------------------------------------------
// 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.
template< typename ImmType, bool isShiftRight >
class DwordShiftImpl
{
protected:
static const uint OperandSize = sizeof(ImmType);
static bool Is8BitOperand() { return OperandSize == 1; }
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); }
static void basesibform( bool isCL )
{
prefix16();
write8( 0x0f );
write8( (isCL ? 0xa5 : 0xa4) | (isShiftRight ? 0x8 : 0) );
}
public:
DwordShiftImpl() {} // because GCC doesn't like static classes
// ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, const xRegister<ImmType>& from )
{
prefix16();
write16( 0xa50f | (isShiftRight ? 0x800 : 0) );
ModRM_Direct( from.Id, to.Id );
}
// ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, const xRegister<ImmType>& from, u8 shiftcnt )
{
if( shiftcnt == 0 ) return;
prefix16();
write16( 0xa40f | (isShiftRight ? 0x800 : 0) );
ModRM_Direct( from.Id, to.Id );
write8( shiftcnt );
}
// ------------------------------------------------------------------------
static __emitinline void Emit( const ModSibBase& sibdest, const xRegister<ImmType>& from, __unused const xRegisterCL& clreg )
{
basesibform();
EmitSibMagic( from.Id, sibdest );
}
// ------------------------------------------------------------------------
static __emitinline void Emit( const ModSibBase& sibdest, const xRegister<ImmType>& from, u8 shiftcnt )
{
basesibform();
EmitSibMagic( from.Id, sibdest );
write8( shiftcnt );
}
// ------------------------------------------------------------------------
// dest data type is inferred from the 'from' register, so we can do void* resolution :)
static __emitinline void Emit( void* dest, const xRegister<ImmType>& from, __unused const xRegisterCL& clreg )
{
basesibform();
xWriteDisp( from.Id, dest );
}
// ------------------------------------------------------------------------
// dest data type is inferred from the 'from' register, so we can do void* resolution :)
static __emitinline void Emit( void* dest, const xRegister<ImmType>& from, u8 shiftcnt )
{
basesibform();
xWriteDisp( from.Id, dest );
write8( shiftcnt );
}
};
// -------------------------------------------------------------------
// I use explicit method declarations here instead of templates, in order to provide // 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). // *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.
//
template< bool isShiftRight > template< bool isShiftRight >
class DwordShiftImplAll class DwordShiftImplAll
{ {
protected: static const u8 m_shiftop = isShiftRight ? 0x8 : 0;
typedef DwordShiftImpl<u32, isShiftRight> m_32;
typedef DwordShiftImpl<u16, isShiftRight> m_16;
public: public:
// ---------- 32 Bit Interface ----------- // ---------- 32 Bit Interface -----------
__forceinline void operator()( const xRegister32& to, const xRegister32& from, __unused const xRegisterCL& clreg ) const { m_32::Emit( to, from ); } __forceinline void operator()( const xRegister32& to, const xRegister32& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0xa5 | m_shiftop, to, from ); }
__forceinline void operator()( void* dest, const xRegister32& from, __unused const xRegisterCL& clreg ) const { m_32::Emit( dest, from ); } __forceinline void operator()( void* dest, const xRegister32& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0xa5 | m_shiftop, from, dest ); }
__noinline void operator()( const ModSibBase& sibdest, const xRegister32& from, __unused const xRegisterCL& clreg ) const { m_32::Emit( sibdest, from ); } __forceinline void operator()( const ModSibBase& dest, const xRegister32& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0xa5 | m_shiftop, from, dest ); }
__forceinline void operator()( const xRegister32& to, const xRegister32& from, u8 shiftcnt ) const { m_32::Emit( to, from, shiftcnt ); } __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 { m_32::Emit( dest, from, shiftcnt ); } __forceinline void operator()( void* dest, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, from, dest, shiftcnt ); }
__noinline void operator()( const ModSibBase& sibdest, const xRegister32& from, u8 shiftcnt ) const { m_32::Emit( sibdest, shiftcnt ); } __forceinline void operator()( const ModSibBase& dest, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, from, dest, shiftcnt ); }
// ---------- 16 Bit Interface ----------- // ---------- 16 Bit Interface -----------
__forceinline void operator()( const xRegister16& to, const xRegister16& from, __unused const xRegisterCL& clreg ) const { m_16::Emit( to, from ); } __forceinline void operator()( const xRegister16& to, const xRegister16& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, to, from ); }
__forceinline void operator()( void* dest, const xRegister16& from, __unused const xRegisterCL& clreg ) const { m_16::Emit( dest, from ); } __forceinline void operator()( void* dest, const xRegister16& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, from, dest ); }
__noinline void operator()( const ModSibBase& sibdest, const xRegister16& from, __unused const xRegisterCL& clreg ) const { m_16::Emit( sibdest, from ); } __forceinline void operator()( const ModSibBase& dest, const xRegister16& from, __unused const xRegisterCL& clreg ) const { xOpWrite0F( 0x66, 0xa5 | m_shiftop, from, dest ); }
__forceinline void operator()( const xRegister16& to, const xRegister16& from, u8 shiftcnt ) const { m_16::Emit( to, from, shiftcnt ); } __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 { m_16::Emit( dest, from, shiftcnt ); } __forceinline void operator()( void* dest, const xRegister16& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, from, dest, shiftcnt ); }
__noinline void operator()( const ModSibBase& sibdest, const xRegister16& from, u8 shiftcnt ) const { m_16::Emit( sibdest, 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? DwordShiftImplAll() {} // Why does GCC need these?
}; };

View File

@ -43,40 +43,40 @@ public:
template< typename T > __forceinline void operator()( const xRegister<T>& to, const xRegister<T>& from ) const template< typename T > __forceinline void operator()( const xRegister<T>& to, const xRegister<T>& from ) const
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>( (Is8BitOp<T>() ? 0 : 1) | (InstType<<3) ); xWrite8( (Is8BitOp<T>() ? 0 : 1) | (InstType<<3) );
ModRM_Direct( from.Id, to.Id ); EmitSibMagic( from, to );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
template< typename T > __forceinline void operator()( const xRegister<T>& to, const void* src ) const template< typename T > __forceinline void operator()( const xRegister<T>& to, const void* src ) const
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>( (Is8BitOp<T>() ? 2 : 3) | (InstType<<3) ); xWrite8( (Is8BitOp<T>() ? 2 : 3) | (InstType<<3) );
xWriteDisp( to.Id, src ); EmitSibMagic( to, src );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
template< typename T > __forceinline void operator()( void* dest, const xRegister<T>& from ) const template< typename T > __forceinline void operator()( void* dest, const xRegister<T>& from ) const
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>( (Is8BitOp<T>() ? 0 : 1) | (InstType<<3) ); xWrite8( (Is8BitOp<T>() ? 0 : 1) | (InstType<<3) );
xWriteDisp( from.Id, dest ); EmitSibMagic( from, dest );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
template< typename T > __noinline void operator()( const ModSibBase& sibdest, const xRegister<T>& from ) const template< typename T > __noinline void operator()( const ModSibBase& sibdest, const xRegister<T>& from ) const
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>( (Is8BitOp<T>() ? 0 : 1) | (InstType<<3) ); xWrite8( (Is8BitOp<T>() ? 0 : 1) | (InstType<<3) );
EmitSibMagic( from.Id, sibdest ); EmitSibMagic( from, sibdest );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
template< typename T > __noinline void operator()( const xRegister<T>& to, const ModSibBase& sibsrc ) const template< typename T > __noinline void operator()( const xRegister<T>& to, const ModSibBase& sibsrc ) const
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>( (Is8BitOp<T>() ? 2 : 3) | (InstType<<3) ); xWrite8( (Is8BitOp<T>() ? 2 : 3) | (InstType<<3) );
EmitSibMagic( to.Id, sibsrc ); EmitSibMagic( to, sibsrc );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -88,14 +88,14 @@ public:
{ {
if( Is8BitOp<T>() ) if( Is8BitOp<T>() )
{ {
xWrite<u8>( 0x80 ); xWrite8( 0x80 );
EmitSibMagic( InstType, sibdest ); EmitSibMagic( InstType, sibdest );
xWrite<s8>( imm ); xWrite<s8>( imm );
} }
else else
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>( is_s8( imm ) ? 0x83 : 0x81 ); xWrite8( is_s8( imm ) ? 0x83 : 0x81 );
EmitSibMagic( InstType, sibdest ); EmitSibMagic( InstType, sibdest );
if( is_s8( imm ) ) if( is_s8( imm ) )
xWrite<s8>( imm ); xWrite<s8>( imm );
@ -110,18 +110,18 @@ public:
prefix16<T>(); prefix16<T>();
if( !Is8BitOp<T>() && is_s8( imm ) ) if( !Is8BitOp<T>() && is_s8( imm ) )
{ {
xWrite<u8>( 0x83 ); xWrite8( 0x83 );
ModRM_Direct( InstType, to.Id ); EmitSibMagic( InstType, to );
xWrite<s8>( imm ); xWrite<s8>( imm );
} }
else else
{ {
if( to.IsAccumulator() ) if( to.IsAccumulator() )
xWrite<u8>( (Is8BitOp<T>() ? 4 : 5) | (InstType<<3) ); xWrite8( (Is8BitOp<T>() ? 4 : 5) | (InstType<<3) );
else else
{ {
xWrite<u8>( Is8BitOp<T>() ? 0x80 : 0x81 ); xWrite8( Is8BitOp<T>() ? 0x80 : 0x81 );
ModRM_Direct( InstType, to.Id ); EmitSibMagic( InstType, to );
} }
xWrite<T>( imm ); xWrite<T>( imm );
} }
@ -167,14 +167,14 @@ class xImpl_G1Compare : xImpl_Group1< G1Type_CMP >
protected: protected:
template< u8 Prefix > struct Woot template< u8 Prefix > struct Woot
{ {
__forceinline void operator()( const xRegisterSSE& to, const xRegisterSSE& from, SSE2_ComparisonType cmptype ) const{ xOpWrite0F( Prefix, 0xc2, to, from ); xWrite<u8>( cmptype ); } __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 void* from, SSE2_ComparisonType cmptype ) const { xOpWrite0F( Prefix, 0xc2, to, from ); xWrite<u8>( cmptype ); } __forceinline void operator()( const xRegisterSSE& to, const void* 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 ); xWrite<u8>( cmptype ); } __forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from, SSE2_ComparisonType cmptype ) const { xOpWrite0F( Prefix, 0xc2, to, from, (u8)cmptype ); }
Woot() {} Woot() {}
}; };
public: public:
using xImpl_Group1< G1Type_CMP >::operator(); using xImpl_Group1<G1Type_CMP>::operator();
const Woot<0x00> PS; const Woot<0x00> PS;
const Woot<0x66> PD; const Woot<0x66> PD;

View File

@ -45,14 +45,14 @@ public:
template< typename T > __forceinline void operator()( const xRegister<T>& to, __unused const xRegisterCL& from ) const template< typename T > __forceinline void operator()( const xRegister<T>& to, __unused const xRegisterCL& from ) const
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>( Is8BitOp<T>() ? 0xd2 : 0xd3 ); xWrite8( Is8BitOp<T>() ? 0xd2 : 0xd3 );
ModRM_Direct( InstType, to.Id ); EmitSibMagic( InstType, to );
} }
template< typename T > __noinline void operator()( const ModSibStrict<T>& sibdest, __unused const xRegisterCL& from ) const template< typename T > __noinline void operator()( const ModSibStrict<T>& sibdest, __unused const xRegisterCL& from ) const
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>( Is8BitOp<T>() ? 0xd2 : 0xd3 ); xWrite8( Is8BitOp<T>() ? 0xd2 : 0xd3 );
EmitSibMagic( InstType, sibdest ); EmitSibMagic( InstType, sibdest );
} }
@ -64,14 +64,14 @@ public:
if( imm == 1 ) if( imm == 1 )
{ {
// special encoding of 1's // special encoding of 1's
xWrite<u8>( Is8BitOp<T>() ? 0xd0 : 0xd1 ); xWrite8( Is8BitOp<T>() ? 0xd0 : 0xd1 );
EmitSibMagic( InstType, sibdest ); EmitSibMagic( InstType, sibdest );
} }
else else
{ {
xWrite<u8>( Is8BitOp<T>() ? 0xc0 : 0xc1 ); xWrite8( Is8BitOp<T>() ? 0xc0 : 0xc1 );
EmitSibMagic( InstType, sibdest ); EmitSibMagic( InstType, sibdest );
xWrite<u8>( imm ); xWrite8( imm );
} }
} }
@ -83,14 +83,14 @@ public:
if( imm == 1 ) if( imm == 1 )
{ {
// special encoding of 1's // special encoding of 1's
xWrite<u8>( Is8BitOp<T>() ? 0xd0 : 0xd1 ); xWrite8( Is8BitOp<T>() ? 0xd0 : 0xd1 );
ModRM_Direct( InstType, to.Id ); EmitSibMagic( InstType, to );
} }
else else
{ {
xWrite<u8>( Is8BitOp<T>() ? 0xc0 : 0xc1 ); xWrite8( Is8BitOp<T>() ? 0xc0 : 0xc1 );
ModRM_Direct( InstType, to.Id ); EmitSibMagic( InstType, to );
xWrite<u8>( imm ); xWrite8( imm );
} }
} }

View File

@ -34,136 +34,79 @@ enum G3Type
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// //
template< G3Type InstType > template< G3Type InstType >
class Group3ImplAll class xImpl_Group3
{ {
public: public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
template< typename T > __forceinline void operator()( const xRegister<T>& from ) const template< typename T > __emitinline void operator()( const xRegister<T>& from ) const
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>(Is8BitOp<T>() ? 0xf6 : 0xf7 ); xWrite8(Is8BitOp<T>() ? 0xf6 : 0xf7 );
ModRM_Direct( InstType, from.Id ); EmitSibMagic( InstType, from );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
template< typename T > __noinline void operator()( const ModSibStrict<T>& from ) const template< typename T > __emitinline void operator()( const ModSibStrict<T>& from ) const
{ {
prefix16<T>(); prefix16<T>();
xWrite<u8>( Is8BitOp<T>() ? 0xf6 : 0xf7 ); xWrite8( Is8BitOp<T>() ? 0xf6 : 0xf7 );
EmitSibMagic( InstType, from ); EmitSibMagic( InstType, from );
} }
Group3ImplAll() {} xImpl_Group3() {}
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV. // This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV.
// //
template< G3Type InstType, u16 OpcodeSSE > template< G3Type InstType, u16 OpcodeSSE >
class xImpl_Group3 : public Group3ImplAll<InstType> class ImplMulDivBase : public xImpl_Group3<InstType>
{ {
public: public:
ImplMulDivBase() {}
const SimdImpl_DestRegSSE<0x00,OpcodeSSE> PS; const SimdImpl_DestRegSSE<0x00,OpcodeSSE> PS;
const SimdImpl_DestRegSSE<0x66,OpcodeSSE> PD; const SimdImpl_DestRegSSE<0x66,OpcodeSSE> PD;
const SimdImpl_DestRegSSE<0xf3,OpcodeSSE> SS; const SimdImpl_DestRegSSE<0xf3,OpcodeSSE> SS;
const SimdImpl_DestRegSSE<0xf2,OpcodeSSE> SD; const SimdImpl_DestRegSSE<0xf2,OpcodeSSE> SD;
};
xImpl_Group3() {} //////////////////////////////////////////////////////////////////////////////////////////
//
class xImpl_iDiv : public ImplMulDivBase<G3Type_iDIV,0x5e>
{
public:
using ImplMulDivBase<G3Type_iDIV,0x5e>::operator();
}; };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// The following iMul-specific forms are valid for 16 and 32 bit register operands only! // The following iMul-specific forms are valid for 16 and 32 bit register operands only!
//
template< typename ImmType > class xImpl_iMul : public ImplMulDivBase<G3Type_iMUL,0x59>
class iMulImpl
{ {
protected: template< typename T1, typename T2, typename ImmType >
static const uint OperandSize = sizeof(ImmType); static __forceinline void ImmStyle( const T1& param1, const T2& param2, ImmType imm8 )
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); } {
xOpWrite0F( (sizeof(ImmType) == 2) ? 0x66 : 0, is_s8( imm8 ) ? 0x6b : 0x69, param1, param2 );
if( is_s8( imm8 ) )
xWrite8( imm8 );
else
xWrite<ImmType>( imm8 );
}
public: public:
// ------------------------------------------------------------------------ using ImplMulDivBase<G3Type_iMUL,0x59>::operator();
static __emitinline void Emit( const xRegister<ImmType>& to, const xRegister<ImmType>& from )
{
prefix16();
write16( 0xaf0f );
ModRM_Direct( to.Id, from.Id );
}
// ------------------------------------------------------------------------ __forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { xOpWrite0F( 0xaf, to, from ); }
static __emitinline void Emit( const xRegister<ImmType>& to, const void* src ) __forceinline void operator()( const xRegister32& to, const void* src ) const { xOpWrite0F( 0xaf, to, src ); }
{ __forceinline void operator()( const xRegister32& to, const ModSibBase& src ) const { xOpWrite0F( 0xaf, to, src ); }
prefix16(); __forceinline void operator()( const xRegister32& to, const xRegister32& from, s32 imm ) const{ ImmStyle( to, from, imm ); }
write16( 0xaf0f ); __forceinline void operator()( const xRegister32& to, const ModSibBase& from, s32 imm ) const { ImmStyle( to, from, imm ); }
xWriteDisp( to.Id, src );
}
// ------------------------------------------------------------------------ __forceinline void operator()( const xRegister16& to, const xRegister16& from ) const { xOpWrite0F( 0x66, 0xaf, to, from ); }
static __emitinline void Emit( const xRegister<ImmType>& to, const ModSibBase& src ) __forceinline void operator()( const xRegister16& to, const void* src ) const { xOpWrite0F( 0x66, 0xaf, to, src ); }
{ __forceinline void operator()( const xRegister16& to, const ModSibBase& src ) const { xOpWrite0F( 0x66, 0xaf, to, src ); }
prefix16(); __forceinline void operator()( const xRegister16& to, const xRegister16& from, s16 imm ) const{ ImmStyle( to, from, imm ); }
write16( 0xaf0f ); __forceinline void operator()( const xRegister16& to, const ModSibBase& from, s16 imm ) const { ImmStyle( to, from, imm ); }
EmitSibMagic( to.Id, src );
}
// ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, const xRegister<ImmType>& from, ImmType imm )
{
prefix16();
write16( is_s8( imm ) ? 0x6b : 0x69 );
ModRM_Direct( to.Id, from.Id );
if( is_s8( imm ) )
write8( imm );
else
xWrite<ImmType>( imm );
}
// ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, const void* src, ImmType imm )
{
prefix16();
write16( is_s8( imm ) ? 0x6b : 0x69 );
xWriteDisp( to.Id, src );
if( is_s8( imm ) )
write8( imm );
else
xWrite<ImmType>( imm );
}
// ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, const ModSibBase& src, ImmType imm )
{
prefix16();
write16( is_s8( imm ) ? 0x6b : 0x69 );
EmitSibMagic( to.Id, src );
if( is_s8( imm ) )
write8( imm );
else
xWrite<ImmType>( imm );
}
};
// ------------------------------------------------------------------------
class xImpl_iMul : public xImpl_Group3<G3Type_iMUL,0x59>
{
protected:
typedef iMulImpl<u32> iMUL32;
typedef iMulImpl<u16> iMUL16;
public:
using xImpl_Group3<G3Type_iMUL,0x59>::operator();
__forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { iMUL32::Emit( to, from ); }
__forceinline void operator()( const xRegister32& to, const void* src ) const { iMUL32::Emit( to, src ); }
__forceinline void operator()( const xRegister32& to, const xRegister32& from, s32 imm ) const{ iMUL32::Emit( to, from, imm ); }
__noinline void operator()( const xRegister32& to, const ModSibBase& src ) const { iMUL32::Emit( to, src ); }
__noinline void operator()( const xRegister32& to, const ModSibBase& from, s32 imm ) const { iMUL32::Emit( to, from, imm ); }
__forceinline void operator()( const xRegister16& to, const xRegister16& from ) const { iMUL16::Emit( to, from ); }
__forceinline void operator()( const xRegister16& to, const void* src ) const { iMUL16::Emit( to, src ); }
__forceinline void operator()( const xRegister16& to, const xRegister16& from, s16 imm ) const{ iMUL16::Emit( to, from, imm ); }
__noinline void operator()( const xRegister16& to, const ModSibBase& src ) const { iMUL16::Emit( to, src ); }
__noinline void operator()( const xRegister16& to, const ModSibBase& from, s16 imm ) const { iMUL16::Emit( to, from, imm ); }
xImpl_iMul() {} xImpl_iMul() {}
}; };

View File

@ -21,62 +21,33 @@
// Implementations found here: Increment and Decrement Instructions! // Implementations found here: Increment and Decrement Instructions!
// Note: This header is meant to be included from within the x86Emitter::Internal namespace. // Note: This header is meant to be included from within the x86Emitter::Internal namespace.
// ------------------------------------------------------------------------
// template< bool isDec >
template< typename ImmType > class xImpl_IncDec
class IncDecImpl
{ {
protected: public:
static const uint OperandSize = sizeof(ImmType); template< typename T >
__forceinline void operator()( const xRegister<T>& to ) const
static bool Is8BitOperand() { return OperandSize == 1; }
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); }
public:
IncDecImpl() {} // For the love of GCC.
static __emitinline void Emit( bool isDec, const xRegister<ImmType>& to )
{ {
// There is no valid 8-bit form of direct register inc/dec, so fall if( Is8BitOp<T>() )
// back on Mod/RM format instead:
if (Is8BitOperand() )
{ {
write8( 0xfe ); xWrite8( 0xfe );
ModRM_Direct( isDec ? 1 : 0, to.Id ); EmitSibMagic( isDec ? 1 : 0, to );
} }
else else
{ {
prefix16(); prefix16<T>();
write8( (isDec ? 0x48 : 0x40) | to.Id ); xWrite8( (isDec ? 0x48 : 0x40) | to.Id );
} }
} }
static __emitinline void Emit( bool isDec, const ModSibStrict<ImmType>& dest ) template< typename T >
__forceinline void operator()( const ModSibStrict<T>& sibdest ) const
{ {
prefix16(); prefix16<T>();
write8( Is8BitOperand() ? 0xfe : 0xff ); xWrite8( Is8BitOp<T>() ? 0xfe : 0xff );
EmitSibMagic( isDec ? 1 : 0, dest ); EmitSibMagic( isDec ? 1 : 0, sibdest );
} }
};
xImpl_IncDec() {} // don't ask.
// ------------------------------------------------------------------------
template< bool isDec >
class IncDecImplAll
{
protected:
typedef IncDecImpl<u32> m_32;
typedef IncDecImpl<u16> m_16;
typedef IncDecImpl<u8> m_8;
public:
__forceinline void operator()( const xRegister32& to ) const { m_32::Emit( isDec, to ); }
__noinline void operator()( const ModSibStrict<u32>& sibdest ) const{ m_32::Emit( isDec, sibdest ); }
__forceinline void operator()( const xRegister16& to ) const { m_16::Emit( isDec, to ); }
__noinline void operator()( const ModSibStrict<u16>& sibdest ) const{ m_16::Emit( isDec, sibdest ); }
__forceinline void operator()( const xRegister8& to ) const { m_8::Emit( isDec, to ); }
__noinline void operator()( const ModSibStrict<u8>& sibdest ) const { m_8::Emit( isDec, sibdest ); }
IncDecImplAll() {} // don't ask.
}; };

View File

@ -21,48 +21,18 @@
// Implementations found here: CALL and JMP! (unconditional only) // Implementations found here: CALL and JMP! (unconditional only)
// Note: This header is meant to be included from within the x86Emitter::Internal namespace. // Note: This header is meant to be included from within the x86Emitter::Internal namespace.
template< typename ImmType >
class JmpCallImpl
{
protected:
static const uint OperandSize = sizeof(ImmType);
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); }
public:
JmpCallImpl() {} // For the love of GCC.
static __emitinline void Emit( bool isJmp, const xRegister<ImmType>& absreg )
{
prefix16();
xWrite<u8>( 0xff );
ModRM_Direct( isJmp ? 4 : 2, absreg.Id );
}
static __emitinline void Emit( bool isJmp, const ModSibStrict<ImmType>& src )
{
prefix16();
xWrite<u8>( 0xff );
EmitSibMagic( isJmp ? 4 : 2, src );
}
};
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
template< bool isJmp > template< bool isJmp >
class JmpCallImplAll class xImpl_JmpCall
{ {
protected:
typedef JmpCallImpl<u32> m_32;
typedef JmpCallImpl<u16> m_16;
public: public:
JmpCallImplAll() {} xImpl_JmpCall() {}
__forceinline void operator()( const xRegister32& absreg ) const { m_32::Emit( isJmp, absreg ); } __forceinline void operator()( const xRegister32& absreg ) const { xOpWrite( 0x00, 0xff, isJmp ? 4 : 2, absreg ); }
__forceinline void operator()( const ModSibStrict<u32>& src ) const { m_32::Emit( isJmp, src ); } __forceinline void operator()( const ModSibStrict<u32>& src ) const { xOpWrite( 0x00, 0xff, isJmp ? 4 : 2, src ); }
__forceinline void operator()( const xRegister16& absreg ) const { m_16::Emit( isJmp, absreg ); } __forceinline void operator()( const xRegister16& absreg ) const { xOpWrite( 0x66, 0xff, isJmp ? 4 : 2, absreg ); }
__forceinline void operator()( const ModSibStrict<u16>& src ) const { m_16::Emit( isJmp, src ); } __forceinline void operator()( const ModSibStrict<u16>& src ) const { xOpWrite( 0x66, 0xff, isJmp ? 4 : 2, src ); }
// Special form for calling functions. This form automatically resolves the // Special form for calling functions. This form automatically resolves the
// correct displacement based on the size of the instruction being generated. // correct displacement based on the size of the instruction being generated.
@ -70,16 +40,16 @@ public:
__forceinline void operator()( const T* func ) const __forceinline void operator()( const T* func ) const
{ {
if( isJmp ) if( isJmp )
iJccKnownTarget( Jcc_Unconditional, (void*)(uptr)func ); iJcc( Jcc_Unconditional, (void*)(uptr)func ); // double cast to/from (uptr) needed to appease GCC
else else
{ {
// calls are relative to the instruction after this one, and length is // calls are relative to the instruction after this one, and length is
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic). // always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic).
sptr dest = (sptr)func - ((sptr)iGetPtr() + 5); sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
xWrite<u8>( 0xe8 ); xWrite8( 0xe8 );
xWrite<u32>( dest ); xWrite32( dest );
} }
} }
}; };

View File

@ -32,7 +32,7 @@ class MovImpl
protected: protected:
static const uint OperandSize = sizeof(ImmType); static const uint OperandSize = sizeof(ImmType);
static bool Is8BitOperand() { return OperandSize == 1; } static bool Is8BitOperand() { return OperandSize == 1; }
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); } static void prefix16() { if( OperandSize == 2 ) xWrite8( 0x66 ); }
public: public:
MovImpl() {} MovImpl() {}
@ -43,8 +43,8 @@ public:
if( to == from ) return; // ignore redundant MOVs. if( to == from ) return; // ignore redundant MOVs.
prefix16(); prefix16();
xWrite<u8>( Is8BitOperand() ? 0x88 : 0x89 ); xWrite8( Is8BitOperand() ? 0x88 : 0x89 );
ModRM_Direct( from.Id, to.Id ); EmitSibMagic( from, to );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -57,12 +57,12 @@ public:
if( from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty() ) if( from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty() )
{ {
xWrite<u8>( Is8BitOperand() ? 0xa2 : 0xa3 ); xWrite8( Is8BitOperand() ? 0xa2 : 0xa3 );
xWrite<u32>( dest.Displacement ); xWrite32( dest.Displacement );
} }
else else
{ {
xWrite<u8>( Is8BitOperand() ? 0x88 : 0x89 ); xWrite8( Is8BitOperand() ? 0x88 : 0x89 );
EmitSibMagic( from.Id, dest ); EmitSibMagic( from.Id, dest );
} }
} }
@ -77,13 +77,13 @@ public:
if( to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty() ) if( to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty() )
{ {
xWrite<u8>( Is8BitOperand() ? 0xa0 : 0xa1 ); xWrite8( Is8BitOperand() ? 0xa0 : 0xa1 );
xWrite<u32>( src.Displacement ); xWrite32( src.Displacement );
} }
else else
{ {
xWrite<u8>( Is8BitOperand() ? 0x8a : 0x8b ); xWrite8( Is8BitOperand() ? 0x8a : 0x8b );
EmitSibMagic( to.Id, src ); EmitSibMagic( to, src );
} }
} }
@ -96,13 +96,13 @@ public:
if( from.IsAccumulator() ) if( from.IsAccumulator() )
{ {
xWrite<u8>( Is8BitOperand() ? 0xa2 : 0xa3 ); xWrite8( Is8BitOperand() ? 0xa2 : 0xa3 );
xWrite<s32>( (s32)dest ); xWrite<s32>( (s32)dest );
} }
else else
{ {
xWrite<u8>( Is8BitOperand() ? 0x88 : 0x89 ); xWrite8( Is8BitOperand() ? 0x88 : 0x89 );
xWriteDisp( from.Id, dest ); EmitSibMagic( from, dest );
} }
} }
@ -115,13 +115,13 @@ public:
if( to.IsAccumulator() ) if( to.IsAccumulator() )
{ {
xWrite<u8>( Is8BitOperand() ? 0xa0 : 0xa1 ); xWrite8( Is8BitOperand() ? 0xa0 : 0xa1 );
xWrite<s32>( (s32)src ); xWrite<s32>( (s32)src );
} }
else else
{ {
xWrite<u8>( Is8BitOperand() ? 0x8a : 0x8b ); xWrite8( Is8BitOperand() ? 0x8a : 0x8b );
xWriteDisp( to.Id, src ); EmitSibMagic( to, src );
} }
} }
@ -131,7 +131,7 @@ public:
// Note: MOV does not have (reg16/32,imm8) forms. // Note: MOV does not have (reg16/32,imm8) forms.
prefix16(); prefix16();
xWrite<u8>( (Is8BitOperand() ? 0xb0 : 0xb8) | to.Id ); xWrite8( (Is8BitOperand() ? 0xb0 : 0xb8) | to.Id );
xWrite<ImmType>( imm ); xWrite<ImmType>( imm );
} }
@ -139,7 +139,7 @@ public:
static __emitinline void Emit( ModSibStrict<ImmType> dest, ImmType imm ) static __emitinline void Emit( ModSibStrict<ImmType> dest, ImmType imm )
{ {
prefix16(); prefix16();
xWrite<u8>( Is8BitOperand() ? 0xc6 : 0xc7 ); xWrite8( Is8BitOperand() ? 0xc6 : 0xc7 );
EmitSibMagic( 0, dest ); EmitSibMagic( 0, dest );
xWrite<ImmType>( imm ); xWrite<ImmType>( imm );
} }
@ -178,6 +178,7 @@ public:
MovImplAll() {} // Satisfy GCC's whims. MovImplAll() {} // Satisfy GCC's whims.
}; };
#define ccSane() jASSUME( ccType >= 0 && ccType <= 0x0f )
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// CMOV !! [in all of it's disappointing lack-of glory] .. and .. // CMOV !! [in all of it's disappointing lack-of glory] .. and ..
@ -186,85 +187,19 @@ public:
// CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you // CMOV Disclaimer: Caution! This instruction can look exciting and cool, until you
// realize that it cannot load immediate values into registers. -_- // realize that it cannot load immediate values into registers. -_-
// //
template< typename ImmType, int InstBaseVal >
class CMovSetImpl
{
protected:
static const uint OperandSize = sizeof(ImmType);
static bool Is8BitOperand() { return OperandSize == 1; }
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); }
static __forceinline void emit_base( JccComparisonType cc )
{
jASSUME( cc >= 0 && cc <= 0x0f );
prefix16();
write8( 0x0f );
write8( InstBaseVal | cc );
}
public:
CMovSetImpl() {}
static __emitinline void Emit( JccComparisonType cc, const xRegister<ImmType>& to, const xRegister<ImmType>& from )
{
if( to == from ) return;
emit_base( cc );
ModRM_Direct( to.Id, from.Id );
}
static __emitinline void Emit( JccComparisonType cc, const xRegister<ImmType>& to, const void* src )
{
emit_base( cc );
xWriteDisp( to.Id, src );
}
static __emitinline void Emit( JccComparisonType cc, const xRegister<ImmType>& to, const ModSibBase& sibsrc )
{
emit_base( cc );
EmitSibMagic( to.Id, sibsrc );
}
// This form is provided for SETcc only (not available in CMOV)
static __emitinline void EmitSet( JccComparisonType cc, const xRegister<ImmType>& to )
{
emit_base( cc );
ModRM_Direct( 0, to.Id );
}
// This form is provided for SETcc only (not available in CMOV)
static __emitinline void EmitSet( JccComparisonType cc, const void* src )
{
emit_base( cc );
xWriteDisp( 0, src );
}
// This form is provided for SETcc only (not available in CMOV)
static __emitinline void EmitSet( JccComparisonType cc, const ModSibStrict<ImmType>& sibsrc )
{
emit_base( cc );
EmitSibMagic( 0, sibsrc );
}
};
// ------------------------------------------------------------------------
// I use explicit method declarations here instead of templates, in order to provide // 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). // *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV).
// //
class CMovImplGeneric class CMovImplGeneric
{ {
protected:
typedef CMovSetImpl<u32, 0x40> m_32; // 0x40 is the cmov base instruction id
typedef CMovSetImpl<u16, 0x40> m_16; // 0x40 is the cmov base instruction id
public: public:
__forceinline void operator()( JccComparisonType ccType, const xRegister32& to, const xRegister32& from ) const { m_32::Emit( ccType, to, from ); } __forceinline void operator()( JccComparisonType ccType, const xRegister32& to, const xRegister32& from ) const { ccSane(); xOpWrite0F( 0x40 | ccType, to, from ); }
__forceinline void operator()( JccComparisonType ccType, const xRegister32& to, const void* src ) const { m_32::Emit( ccType, to, src ); } __forceinline void operator()( JccComparisonType ccType, const xRegister32& to, const void* src ) const { ccSane(); xOpWrite0F( 0x40 | ccType, to, src ); }
__noinline void operator()( JccComparisonType ccType, const xRegister32& to, const ModSibBase& sibsrc ) const { m_32::Emit( ccType, to, sibsrc ); } __forceinline void operator()( JccComparisonType ccType, const xRegister32& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x40 | ccType, to, sibsrc ); }
__forceinline void operator()( JccComparisonType ccType, const xRegister16& to, const xRegister16& from ) const { m_16::Emit( ccType, to, from ); } __forceinline void operator()( JccComparisonType ccType, const xRegister16& to, const xRegister16& from ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, from ); }
__forceinline void operator()( JccComparisonType ccType, const xRegister16& to, const void* src ) const { m_16::Emit( ccType, to, src ); } __forceinline void operator()( JccComparisonType ccType, const xRegister16& to, const void* src ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, src ); }
__noinline void operator()( JccComparisonType ccType, const xRegister16& to, const ModSibBase& sibsrc ) const { m_16::Emit( ccType, to, sibsrc ); } __forceinline void operator()( JccComparisonType ccType, const xRegister16& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, sibsrc ); }
CMovImplGeneric() {} // don't ask. CMovImplGeneric() {} // don't ask.
}; };
@ -273,18 +208,16 @@ public:
template< JccComparisonType ccType > template< JccComparisonType ccType >
class CMovImplAll class CMovImplAll
{ {
protected: static const u16 Opcode = 0x40 | ccType;
typedef CMovSetImpl<u32, 0x40> m_32;
typedef CMovSetImpl<u16, 0x40> m_16;
public: public:
__forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { m_32::Emit( ccType, to, from ); } __forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { ccSane(); xOpWrite0F( Opcode, to, from ); }
__forceinline void operator()( const xRegister32& to, const void* src ) const { m_32::Emit( ccType, to, src ); } __forceinline void operator()( const xRegister32& to, const void* src ) const { ccSane(); xOpWrite0F( Opcode, to, src ); }
__noinline void operator()( const xRegister32& to, const ModSibBase& sibsrc ) const { m_32::Emit( ccType, to, sibsrc ); } __forceinline void operator()( const xRegister32& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( Opcode, to, sibsrc ); }
__forceinline void operator()( const xRegister16& to, const xRegister16& from ) const { m_16::Emit( ccType, to, from ); } __forceinline void operator()( const xRegister16& to, const xRegister16& from ) const { ccSane(); xOpWrite0F( 0x66, Opcode, to, from ); }
__forceinline void operator()( const xRegister16& to, const void* src ) const { m_16::Emit( ccType, to, src ); } __forceinline void operator()( const xRegister16& to, const void* src ) const { ccSane(); xOpWrite0F( 0x66, Opcode, to, src ); }
__noinline void operator()( const xRegister16& to, const ModSibBase& sibsrc ) const { m_16::Emit( ccType, to, sibsrc ); } __forceinline void operator()( const xRegister16& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x66, Opcode, to, sibsrc ); }
CMovImplAll() {} // don't ask. CMovImplAll() {} // don't ask.
}; };
@ -292,13 +225,11 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
class SetImplGeneric class SetImplGeneric
{ {
protected: // note: SETcc are 0x90, with 0 in the Reg field of ModRM.
typedef CMovSetImpl<u8, 0x90> Impl; // 0x90 is the SETcc base instruction id
public: public:
__forceinline void operator()( JccComparisonType cc, const xRegister8& to ) const { Impl::EmitSet( cc, to ); } __forceinline void operator()( JccComparisonType ccType, const xRegister8& to ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, to ); }
__forceinline void operator()( JccComparisonType cc, void* dest ) const { Impl::EmitSet( cc, dest ); } __forceinline void operator()( JccComparisonType ccType, void* dest ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, dest ); }
__noinline void operator()( JccComparisonType cc, const ModSibStrict<u8>& dest ) const { Impl::EmitSet( cc, dest ); } __noinline void operator()( JccComparisonType ccType, const ModSibStrict<u8>& dest ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, dest ); }
SetImplGeneric() {} // if you do, ask GCC. SetImplGeneric() {} // if you do, ask GCC.
}; };
@ -307,13 +238,12 @@ public:
template< JccComparisonType ccType > template< JccComparisonType ccType >
class SetImplAll class SetImplAll
{ {
protected: static const u16 Opcode = 0x90 | ccType; // SETcc are 0x90 base opcode, with 0 in the Reg field of ModRM.
typedef CMovSetImpl<u8, 0x90> Impl; // 0x90 is the SETcc base instruction id
public: public:
__forceinline void operator()( const xRegister8& to ) const { Impl::EmitSet( ccType, to ); } __forceinline void operator()( const xRegister8& to ) const { ccSane(); xOpWrite0F( Opcode, 0, to ); }
__forceinline void operator()( void* dest ) const { Impl::EmitSet( ccType, dest ); } __forceinline void operator()( void* dest ) const { ccSane(); xOpWrite0F( Opcode, 0, dest ); }
__noinline void operator()( const ModSibStrict<u8>& dest ) const { Impl::EmitSet( ccType, dest ); } __noinline void operator()( const ModSibStrict<u8>& dest ) const { ccSane(); xOpWrite0F( Opcode, 0, dest ); }
SetImplAll() {} // if you do, ask GCC. SetImplAll() {} // if you do, ask GCC.
}; };
@ -330,12 +260,12 @@ protected:
static const uint SrcOperandSize = sizeof( SrcImmType ); static const uint SrcOperandSize = sizeof( SrcImmType );
static bool Is8BitOperand() { return SrcOperandSize == 1; } static bool Is8BitOperand() { return SrcOperandSize == 1; }
static void prefix16() { if( DestOperandSize == 2 ) xWrite<u8>( 0x66 ); } static void prefix16() { if( DestOperandSize == 2 ) xWrite8( 0x66 ); }
static __forceinline void emit_base( bool SignExtend ) static __forceinline void emit_base( bool SignExtend )
{ {
prefix16(); prefix16();
xWrite<u8>( 0x0f ); xWrite8( 0x0f );
xWrite<u8>( 0xb6 | (Is8BitOperand() ? 0 : 1) | (SignExtend ? 8 : 0 ) ); xWrite8( 0xb6 | (Is8BitOperand() ? 0 : 1) | (SignExtend ? 8 : 0 ) );
} }
public: public:
@ -344,13 +274,13 @@ public:
static __emitinline void Emit( const xRegister<DestImmType>& to, const xRegister<SrcImmType>& from, bool SignExtend ) static __emitinline void Emit( const xRegister<DestImmType>& to, const xRegister<SrcImmType>& from, bool SignExtend )
{ {
emit_base( SignExtend ); emit_base( SignExtend );
ModRM_Direct( to.Id, from.Id ); EmitSibMagic( to, from );
} }
static __emitinline void Emit( const xRegister<DestImmType>& to, const ModSibStrict<SrcImmType>& sibsrc, bool SignExtend ) static __emitinline void Emit( const xRegister<DestImmType>& to, const ModSibStrict<SrcImmType>& sibsrc, bool SignExtend )
{ {
emit_base( SignExtend ); emit_base( SignExtend );
EmitSibMagic( to.Id, sibsrc ); EmitSibMagic( to, sibsrc );
} }
}; };

View File

@ -18,66 +18,93 @@
#pragma once #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 // TEST instruction Implementation
//
template< typename ImmType > class xImpl_Test
class TestImpl
{ {
protected:
static const uint OperandSize = sizeof(ImmType);
static bool Is8BitOperand() { return OperandSize == 1; }
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); }
public: public:
TestImpl() {}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, const xRegister<ImmType>& from ) template< typename T > __forceinline
void operator()( const xRegister<T>& to, const xRegister<T>& from ) const
{ {
prefix16(); prefix16<T>();
xWrite<u8>( Is8BitOperand() ? 0x84 : 0x85 ); xWrite8( Is8BitOp<T>() ? 0x84 : 0x85 );
ModRM_Direct( from.Id, to.Id ); EmitSibMagic( from, to );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, ImmType imm ) template< typename T > __forceinline
void operator()( const ModSibStrict<T>& dest, int imm ) const
{ {
prefix16(); 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() ) if( to.IsAccumulator() )
xWrite<u8>( Is8BitOperand() ? 0xa8 : 0xa9 ); xWrite8( Is8BitOp<T>() ? 0xa8 : 0xa9 );
else else
{ {
xWrite<u8>( Is8BitOperand() ? 0xf6 : 0xf7 ); xWrite8( Is8BitOp<T>() ? 0xf6 : 0xf7 );
ModRM_Direct( 0, to.Id ); EmitSibMagic( 0, to );
} }
xWrite<ImmType>( imm ); xWrite<T>( imm );
} }
// ------------------------------------------------------------------------ xImpl_Test() {} // Why does GCC need these?
static __emitinline void Emit( ModSibStrict<ImmType> dest, ImmType imm )
{
prefix16();
xWrite<u8>( Is8BitOperand() ? 0xf6 : 0xf7 );
EmitSibMagic( 0, dest );
xWrite<ImmType>( imm );
}
}; };
// ------------------------------------------------------------------- enum G8Type
{
G8Type_BT = 4,
G8Type_BTS,
G8Type_BTR,
G8Type_BTC,
};
//////////////////////////////////////////////////////////////////////////////////////////
// BSF / BSR -- 16/32 operands supported only.
// //
class TestImplAll // 0xbc [fwd] / 0xbd [rev]
//
template< u16 Opcode >
class xImpl_BitScan
{ {
public: public:
template< typename T > xImpl_BitScan() {}
__forceinline void operator()( const xRegister<T>& to, const xRegister<T>& from ) const { TestImpl<T>::Emit( to, from ); }
template< typename T > __forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { xOpWrite0F( Opcode, to, from ); }
__noinline void operator()( const ModSibStrict<T>& sibdest, T imm ) const { TestImpl<T>::Emit( sibdest, imm ); } __forceinline void operator()( const xRegister16& to, const xRegister16& from ) const { xOpWrite0F( 0x66, Opcode, to, from ); }
template< typename T > __forceinline void operator()( const xRegister32& to, const void* src ) const { xOpWrite0F( Opcode, to, src ); }
void operator()( const xRegister<T>& to, T imm ) const { TestImpl<T>::Emit( to, imm ); } __forceinline void operator()( const xRegister16& to, const void* src ) const { xOpWrite0F( 0x66, Opcode, to, src ); }
__forceinline void operator()( const xRegister32& to, const ModSibBase& sibsrc ) const { xOpWrite0F( Opcode, to, sibsrc ); }
TestImplAll() {} // Why does GCC need these? __forceinline void operator()( const xRegister16& to, const ModSibBase& sibsrc ) const { xOpWrite0F( 0x66, Opcode, to, sibsrc ); }
}; };
//////////////////////////////////////////////////////////////////////////////////////////
// Bit Test Instructions - Valid on 16/32 bit instructions only.
//
template< G8Type InstType >
class xImpl_Group8 : public xImpl_BitScan<0xa3 | (InstType << 2)>
{
public:
using xImpl_BitScan<0xa3 | (InstType << 2)>::operator();
__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 ); }
void operator()( const xRegister<u32>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0xba, InstType, bitbase, bitoffset ); }
void operator()( const xRegister<u16>& bitbase, u8 bitoffset ) const { xOpWrite0F( 0x66, 0xba, InstType, bitbase, bitoffset ); }
xImpl_Group8() {}
};

View File

@ -40,15 +40,15 @@ public:
__emitinline void operator()( const xRegisterSSE& to, u8 imm8 ) const __emitinline void operator()( const xRegisterSSE& to, u8 imm8 ) const
{ {
SimdPrefix( 0x66, OpcodeImm ); SimdPrefix( 0x66, OpcodeImm );
ModRM( 3, (int)Modcode, to.Id ); EmitSibMagic( (int)Modcode, to );
xWrite<u8>( imm8 ); xWrite8( imm8 );
} }
__emitinline void operator()( const xRegisterMMX& to, u8 imm8 ) const __emitinline void operator()( const xRegisterMMX& to, u8 imm8 ) const
{ {
SimdPrefix( 0x00, OpcodeImm ); SimdPrefix( 0x00, OpcodeImm );
ModRM( 3, (int)Modcode, to.Id ); EmitSibMagic( (int)Modcode, to );
xWrite<u8>( imm8 ); xWrite8( imm8 );
} }
}; };
@ -78,7 +78,7 @@ public:
{ {
SimdPrefix( 0x66, 0x73 ); SimdPrefix( 0x66, 0x73 );
ModRM( 3, (int)Modcode+1, to.Id ); ModRM( 3, (int)Modcode+1, to.Id );
xWrite<u8>( imm8 ); xWrite8( imm8 );
} }
SimdImpl_Shift() {} SimdImpl_Shift() {}

View File

@ -21,110 +21,6 @@
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// MMX / SSE Helper Functions! // MMX / SSE Helper Functions!
extern void SimdPrefix( u8 prefix, u16 opcode );
extern void xOpWrite0F( u8 prefix, u16 opcode, int instId, const ModSibBase& sib );
extern void xOpWrite0F( u8 prefix, u16 opcode, int instId, const void* data );
extern void xOpWrite0F( u16 opcode, int instId, const ModSibBase& sib );
extern void xOpWrite0F( u16 opcode, int instId, const void* data );
template< typename T2 > __emitinline
void xOpWrite0F( u8 prefix, u16 opcode, int instId, const xRegister<T2>& from )
{
SimdPrefix( prefix, opcode );
ModRM_Direct( instId, from.Id );
}
template< typename T2 > __emitinline
void xOpWrite0F( u16 opcode, int instId, const xRegister<T2>& from )
{
xOpWrite0F( 0, opcode, instId, from );
}
template< typename T, typename T2 > __emitinline
void xOpWrite0F( u8 prefix, u16 opcode, const xRegister<T>& to, const xRegister<T2>& from, bool forcePrefix=false )
{
xOpWrite0F( prefix, opcode, to.Id, from );
}
template< typename T > __noinline
void xOpWrite0F( u8 prefix, u16 opcode, const xRegister<T>& reg, const ModSibBase& sib, bool forcePrefix=false )
{
xOpWrite0F( prefix, opcode, reg.Id, sib );
}
template< typename T > __emitinline
void xOpWrite0F( u8 prefix, u16 opcode, const xRegister<T>& reg, const void* data, bool forcePrefix=false )
{
xOpWrite0F( prefix, opcode, reg.Id, data );
}
// ------------------------------------------------------------------------
//
template< typename T, typename T2 > __emitinline
void xOpWrite0F( u8 prefix, u16 opcode, const xRegister<T>& to, const xRegister<T2>& from, u8 imm8 )
{
xOpWrite0F( prefix, opcode, to, from );
xWrite<u8>( imm8 );
}
template< typename T > __noinline
void xOpWrite0F( u8 prefix, u16 opcode, const xRegister<T>& reg, const ModSibBase& sib, u8 imm8 )
{
xOpWrite0F( prefix, opcode, reg, sib );
xWrite<u8>( imm8 );
}
template< typename T > __emitinline
void xOpWrite0F( u8 prefix, u16 opcode, const xRegister<T>& reg, const void* data, u8 imm8 )
{
xOpWrite0F( prefix, opcode, reg, data );
xWrite<u8>( imm8 );
}
// ------------------------------------------------------------------------
template< typename T, typename T2 > __emitinline
void xOpWrite0F( u16 opcode, const xRegister<T>& to, const xRegister<T2>& from )
{
xOpWrite0F( 0, opcode, to, from );
}
template< typename T > __noinline
void xOpWrite0F( u16 opcode, const xRegister<T>& reg, const ModSibBase& sib )
{
xOpWrite0F( 0, opcode, reg, sib );
}
template< typename T > __emitinline
void xOpWrite0F( u16 opcode, const xRegister<T>& reg, const void* data )
{
xOpWrite0F( 0, opcode, reg, data );
}
// ------------------------------------------------------------------------
template< typename T, typename T2 > __emitinline
void xOpWrite0F( u16 opcode, const xRegister<T>& to, const xRegister<T2>& from, u8 imm8 )
{
xOpWrite0F( opcode, to, from );
xWrite<u8>( imm8 );
}
template< typename T > __noinline
void xOpWrite0F( u16 opcode, const xRegister<T>& reg, const ModSibBase& sib, u8 imm8 )
{
xOpWrite0F( opcode, reg, sib );
xWrite<u8>( imm8 );
}
template< typename T > __emitinline
void xOpWrite0F( u16 opcode, const xRegister<T>& reg, const void* data, u8 imm8 )
{
xOpWrite0F( opcode, reg, data );
xWrite<u8>( imm8 );
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only, // For implementing SSE-only logic operations that have xmmreg,xmmreg/rm forms only,
// like ANDPS/ANDPD // like ANDPS/ANDPD

View File

@ -41,9 +41,9 @@ class SimdImpl_Compare
protected: protected:
template< u8 Prefix > struct Woot template< u8 Prefix > struct Woot
{ {
__forceinline void operator()( const xRegisterSSE& to, const xRegisterSSE& from ) const { xOpWrite0F( Prefix, 0xc2, to, from ); xWrite<u8>( CType ); } __forceinline void operator()( const xRegisterSSE& to, const xRegisterSSE& from ) const { xOpWrite0F( Prefix, 0xc2, to, from ); xWrite8( CType ); }
__forceinline void operator()( const xRegisterSSE& to, const void* from ) const { xOpWrite0F( Prefix, 0xc2, to, from ); xWrite<u8>( CType ); } __forceinline void operator()( const xRegisterSSE& to, const void* from ) const { xOpWrite0F( Prefix, 0xc2, to, from ); xWrite8( CType ); }
__forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( Prefix, 0xc2, to, from ); xWrite<u8>( CType ); } __forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( Prefix, 0xc2, to, from ); xWrite8( CType ); }
Woot() {} Woot() {}
}; };

View File

@ -122,17 +122,17 @@ public:
{ {
if( to != from ) xOpWrite0F( PrefixA, Opcode, to, from ); if( to != from ) xOpWrite0F( PrefixA, Opcode, to, from );
} }
#ifndef __LINUX__ // Ifdef till Jake fixes; you can't use & on a const void*!
__forceinline void operator()( const xRegisterSSE& to, const void* from ) const __forceinline void operator()( const xRegisterSSE& to, const void* from ) const
{ {
xOpWrite0F( (isAligned || (from & 0x0f) == 0) ? PrefixA : PrefixU, Opcode, to, from ); xOpWrite0F( (isAligned || ((uptr)from & 0x0f) == 0) ? PrefixA : PrefixU, Opcode, to, from );
} }
__forceinline void operator()( const void* to, const xRegisterSSE& from ) const __forceinline void operator()( const void* to, const xRegisterSSE& from ) const
{ {
xOpWrite0F( (isAligned || (from & 0x0f) == 0) ? PrefixA : PrefixU, Opcode_Alt, to, from ); xOpWrite0F( (isAligned || ((uptr)from & 0x0f) == 0) ? PrefixA : PrefixU, Opcode_Alt, to, from );
} }
#endif
__forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from ) const __forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from ) const
{ {
// ModSib form is aligned if it's displacement-only and the displacement is aligned: // ModSib form is aligned if it's displacement-only and the displacement is aligned:
@ -140,14 +140,12 @@ public:
xOpWrite0F( isReallyAligned ? PrefixA : PrefixU, Opcode, to, from ); xOpWrite0F( isReallyAligned ? PrefixA : PrefixU, Opcode, to, from );
} }
#ifndef __LINUX__ // II'll ifdef this one, too. xOpWrite0F doesn't take ModSibBase & xRegisterSSE in that order.
__forceinline void operator()( const ModSibBase& to, const xRegisterSSE& from ) const __forceinline void operator()( const ModSibBase& to, const xRegisterSSE& from ) const
{ {
// ModSib form is aligned if it's displacement-only and the displacement is aligned: // ModSib form is aligned if it's displacement-only and the displacement is aligned:
bool isReallyAligned = isAligned || ( (to.Displacement & 0x0f) == 0 && to.Index.IsEmpty() && to.Base.IsEmpty() ); bool isReallyAligned = isAligned || ( (to.Displacement & 0x0f) == 0 && to.Index.IsEmpty() && to.Base.IsEmpty() );
xOpWrite0F( isReallyAligned ? PrefixA : PrefixU, Opcode_Alt, to, from ); xOpWrite0F( isReallyAligned ? PrefixA : PrefixU, Opcode_Alt, from, to );
} }
#endif
}; };

View File

@ -26,9 +26,9 @@ class SimdImpl_Shuffle
protected: protected:
template< u8 Prefix > struct Woot template< u8 Prefix > struct Woot
{ {
__forceinline void operator()( const xRegisterSSE& to, const xRegisterSSE& from, u8 cmptype ) const { xOpWrite0F( Prefix, OpcodeSSE, to, from ); xWrite<u8>( cmptype ); } __forceinline void operator()( const xRegisterSSE& to, const xRegisterSSE& from, u8 cmptype ) const { xOpWrite0F( Prefix, OpcodeSSE, to, from ); xWrite8( cmptype ); }
__forceinline void operator()( const xRegisterSSE& to, const void* from, u8 cmptype ) const { xOpWrite0F( Prefix, OpcodeSSE, to, from ); xWrite<u8>( cmptype ); } __forceinline void operator()( const xRegisterSSE& to, const void* from, u8 cmptype ) const { xOpWrite0F( Prefix, OpcodeSSE, to, from ); xWrite8( cmptype ); }
__forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from, u8 cmptype ) const { xOpWrite0F( Prefix, OpcodeSSE, to, from ); xWrite<u8>( cmptype ); } __forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from, u8 cmptype ) const { xOpWrite0F( Prefix, OpcodeSSE, to, from ); xWrite8( cmptype ); }
Woot() {} Woot() {}
}; };

View File

@ -66,6 +66,26 @@ __threadlocal XMMSSEType g_xmmtypes[iREGCNT_XMM] = { XMMT_INT };
namespace x86Emitter { namespace x86Emitter {
__forceinline void xWrite8( u8 val )
{
xWrite( val );
}
__forceinline void xWrite16( u16 val )
{
xWrite( val );
}
__forceinline void xWrite32( u32 val )
{
xWrite( val );
}
__forceinline void xWrite64( u64 val )
{
xWrite( val );
}
const xAddressIndexerBase ptr; const xAddressIndexerBase ptr;
const xAddressIndexer<u128> ptr128; const xAddressIndexer<u128> ptr128;
const xAddressIndexer<u64> ptr64; const xAddressIndexer<u64> ptr64;
@ -75,7 +95,7 @@ const xAddressIndexer<u8> ptr8;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
template< typename OperandType > const xRegister<OperandType> xRegister<OperandType>::Empty; template< typename OperandType > const xRegisterBase<OperandType> xRegisterBase<OperandType>::Empty;
const xAddressReg xAddressReg::Empty; const xAddressReg xAddressReg::Empty;
const xRegisterSSE const xRegisterSSE
@ -110,8 +130,11 @@ const xRegister8
const xRegisterCL cl; const xRegisterCL cl;
//////////////////////////////////////////////////////////////////////////////////////////
namespace Internal namespace Internal
{ {
//////////////////////////////////////////////////////////////////////////////////////////
// Performance note: VC++ wants to use byte/word register form for the following // 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 // ModRM/SibSB constructors when we use xWrite<u8>, and furthermore unrolls the
// the shift using a series of ADDs for the following results: // the shift using a series of ADDs for the following results:
@ -135,32 +158,22 @@ namespace Internal
// (btw, I know this isn't a critical performance item by any means, but it's // (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) // annoying simply because it *should* be an easy thing to optimize)
__forceinline void ModRM( uint mod, uint reg, uint rm ) static __forceinline void ModRM( uint mod, uint reg, uint rm )
{ {
xWrite<u8>( (mod << 6) | (reg << 3) | rm ); xWrite8( (mod << 6) | (reg << 3) | rm );
} }
__forceinline void ModRM_Direct( uint reg, uint rm ) static __forceinline void SibSB( u32 ss, u32 index, u32 base )
{ {
ModRM( Mod_Direct, reg, rm ); xWrite8( (ss << 6) | (index << 3) | base );
} }
__forceinline void SibSB( u32 ss, u32 index, u32 base ) __forceinline void EmitSibMagic( uint regfield, const void* address )
{
xWrite<u8>( (ss << 6) | (index << 3) | base );
}
__forceinline void xWriteDisp( int regfield, s32 displacement )
{ {
ModRM( 0, regfield, ModRm_UseDisp32 ); ModRM( 0, regfield, ModRm_UseDisp32 );
xWrite<s32>( displacement ); xWrite<s32>( (s32)address );
} }
__forceinline void xWriteDisp( int regfield, const void* address )
{
xWriteDisp( regfield, (s32)address );
}
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// emitter helpers for xmm instruction with prefixes, most of which are using // emitter helpers for xmm instruction with prefixes, most of which are using
// the basic opcode format (items inside braces denote optional or conditional // the basic opcode format (items inside braces denote optional or conditional
@ -180,7 +193,7 @@ namespace Internal
__emitinline void xOpWrite0F( u8 prefix, u16 opcode, int instId, const void* data ) __emitinline void xOpWrite0F( u8 prefix, u16 opcode, int instId, const void* data )
{ {
SimdPrefix( prefix, opcode ); SimdPrefix( prefix, opcode );
xWriteDisp( instId, data ); EmitSibMagic( instId, data );
} }
__emitinline void xOpWrite0F( u16 opcode, int instId, const ModSibBase& sib ) __emitinline void xOpWrite0F( u16 opcode, int instId, const ModSibBase& sib )
@ -219,7 +232,7 @@ namespace Internal
// regfield - register field to be written to the ModRm. This is either a register specifier // 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. // or an opcode extension. In either case, the instruction determines the value for us.
// //
void EmitSibMagic( uint regfield, const ModSibBase& info ) __noinline void EmitSibMagic( uint regfield, const ModSibBase& info )
{ {
jASSUME( regfield < 8 ); jASSUME( regfield < 8 );
@ -235,7 +248,7 @@ namespace Internal
if( info.Index.IsEmpty() ) if( info.Index.IsEmpty() )
{ {
xWriteDisp( regfield, info.Displacement ); EmitSibMagic( regfield, (void*)info.Displacement );
return; return;
} }
else else
@ -284,7 +297,7 @@ namespace Internal
using namespace Internal; using namespace Internal;
const MovImplAll xMOV; const MovImplAll xMOV;
const TestImplAll xTEST; const xImpl_Test xTEST;
const xImpl_G1Logic<G1Type_AND,0x54> xAND; const xImpl_G1Logic<G1Type_AND,0x54> xAND;
const xImpl_G1Logic<G1Type_OR,0x56> xOR; const xImpl_G1Logic<G1Type_OR,0x56> xOR;
@ -305,15 +318,15 @@ const Group2ImplAll<G2Type_SHL> xSHL;
const Group2ImplAll<G2Type_SHR> xSHR; const Group2ImplAll<G2Type_SHR> xSHR;
const Group2ImplAll<G2Type_SAR> xSAR; const Group2ImplAll<G2Type_SAR> xSAR;
const Group3ImplAll<G3Type_NOT> xNOT; const xImpl_Group3<G3Type_NOT> xNOT;
const Group3ImplAll<G3Type_NEG> xNEG; const xImpl_Group3<G3Type_NEG> xNEG;
const Group3ImplAll<G3Type_MUL> xUMUL; const xImpl_Group3<G3Type_MUL> xUMUL;
const Group3ImplAll<G3Type_DIV> xUDIV; const xImpl_Group3<G3Type_DIV> xUDIV;
const xImpl_Group3<G3Type_iDIV,0x5e> xDIV; const xImpl_iDiv xDIV;
const xImpl_iMul xMUL; const xImpl_iMul xMUL;
const IncDecImplAll<false> xINC; const xImpl_IncDec<false> xINC;
const IncDecImplAll<true> xDEC; const xImpl_IncDec<true> xDEC;
const MovExtendImplAll<false> xMOVZX; const MovExtendImplAll<false> xMOVZX;
const MovExtendImplAll<true> xMOVSX; const MovExtendImplAll<true> xMOVSX;
@ -321,13 +334,13 @@ const MovExtendImplAll<true> xMOVSX;
const DwordShiftImplAll<false> xSHLD; const DwordShiftImplAll<false> xSHLD;
const DwordShiftImplAll<true> xSHRD; const DwordShiftImplAll<true> xSHRD;
const Group8Impl<G8Type_BT> xBT; const xImpl_Group8<G8Type_BT> xBT;
const Group8Impl<G8Type_BTR> xBTR; const xImpl_Group8<G8Type_BTR> xBTR;
const Group8Impl<G8Type_BTS> xBTS; const xImpl_Group8<G8Type_BTS> xBTS;
const Group8Impl<G8Type_BTC> xBTC; const xImpl_Group8<G8Type_BTC> xBTC;
const BitScanImpl<0xbc> xBSF; const xImpl_BitScan<0xbc> xBSF;
const BitScanImpl<0xbd> xBSR; const xImpl_BitScan<0xbd> xBSR;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
const CMovImplGeneric xCMOV; const CMovImplGeneric xCMOV;
@ -390,7 +403,7 @@ const SetImplAll<Jcc_ParityOdd> xSETPO;
// Assigns the current emitter buffer target address. // Assigns the current emitter buffer target address.
// This is provided instead of using x86Ptr directly, since we may in the future find // 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.' // a need to change the storage class system for the x86Ptr 'under the hood.'
__emitinline void iSetPtr( void* ptr ) __emitinline void xSetPtr( void* ptr )
{ {
x86Ptr = (u8*)ptr; x86Ptr = (u8*)ptr;
} }
@ -399,26 +412,26 @@ __emitinline void iSetPtr( void* ptr )
// Retrieves the current emitter buffer target address. // Retrieves the current emitter buffer target address.
// This is provided instead of using x86Ptr directly, since we may in the future find // 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.' // a need to change the storage class system for the x86Ptr 'under the hood.'
__emitinline u8* iGetPtr() __emitinline u8* xGetPtr()
{ {
return x86Ptr; return x86Ptr;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
__emitinline void iAlignPtr( uint bytes ) __emitinline void xAlignPtr( uint bytes )
{ {
// forward align // forward align
x86Ptr = (u8*)( ( (uptr)x86Ptr + bytes - 1) & ~(bytes - 1) ); x86Ptr = (u8*)( ( (uptr)x86Ptr + bytes - 1) & ~(bytes - 1) );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
__emitinline void iAdvancePtr( uint bytes ) __emitinline void xAdvancePtr( uint bytes )
{ {
if( IsDevBuild ) if( IsDevBuild )
{ {
// common debugger courtesy: advance with INT3 as filler. // common debugger courtesy: advance with INT3 as filler.
for( uint i=0; i<bytes; i++ ) for( uint i=0; i<bytes; i++ )
xWrite<u8>( 0xcc ); xWrite8( 0xcc );
} }
else else
x86Ptr += bytes; x86Ptr += bytes;
@ -553,7 +566,7 @@ static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool
// note: no need to do ebp+0 check since we encode all 0 displacements as // note: no need to do ebp+0 check since we encode all 0 displacements as
// register assignments above (via MOV) // register assignments above (via MOV)
xWrite<u8>( 0x8d ); xWrite8( 0x8d );
ModRM( displacement_size, to.Id, src.Index.Id ); ModRM( displacement_size, to.Id, src.Index.Id );
} }
} }
@ -575,10 +588,10 @@ static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool
xSHL( to, src.Scale ); xSHL( to, src.Scale );
return; return;
} }
xWrite<u8>( 0x8d ); xWrite8( 0x8d );
ModRM( 0, to.Id, ModRm_UseSib ); ModRM( 0, to.Id, ModRm_UseSib );
SibSB( src.Scale, src.Index.Id, ModRm_UseDisp32 ); SibSB( src.Scale, src.Index.Id, ModRm_UseDisp32 );
xWrite<u32>( src.Displacement ); xWrite32( src.Displacement );
return; return;
} }
else else
@ -614,7 +627,7 @@ static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool
if( src.Base == ebp && displacement_size == 0 ) if( src.Base == ebp && displacement_size == 0 )
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]! displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
xWrite<u8>( 0x8d ); xWrite8( 0x8d );
ModRM( displacement_size, to.Id, ModRm_UseSib ); ModRM( displacement_size, to.Id, ModRm_UseSib );
SibSB( src.Scale, src.Index.Id, src.Base.Id ); SibSB( src.Scale, src.Index.Id, src.Base.Id );
} }
@ -637,7 +650,7 @@ __emitinline void xLEA( xRegister32 to, const ModSibBase& src, bool preserve_fla
__emitinline void xLEA( xRegister16 to, const ModSibBase& src, bool preserve_flags ) __emitinline void xLEA( xRegister16 to, const ModSibBase& src, bool preserve_flags )
{ {
write8( 0x66 ); xWrite8( 0x66 );
EmitLeaMagic( to, src, preserve_flags ); EmitLeaMagic( to, src, preserve_flags );
} }
@ -650,22 +663,51 @@ __emitinline void xLEA( xRegister16 to, const ModSibBase& src, bool preserve_fla
__emitinline void xPOP( const ModSibBase& from ) __emitinline void xPOP( const ModSibBase& from )
{ {
xWrite<u8>( 0x8f ); xWrite8( 0x8f );
EmitSibMagic( 0, from ); EmitSibMagic( 0, from );
} }
__emitinline void xPUSH( const ModSibBase& from ) __emitinline void xPUSH( const ModSibBase& from )
{ {
xWrite<u8>( 0xff ); xWrite8( 0xff );
EmitSibMagic( 6, from ); EmitSibMagic( 6, from );
} }
__forceinline void xPOP( xRegister32 from ) { xWrite8( 0x58 | from.Id ); }
__forceinline void xPOP( void* from ) { xPOP( ptr[from] ); }
__forceinline void xPUSH( u32 imm ) { xWrite8( 0x68 ); xWrite32( imm ); }
__forceinline void xPUSH( xRegister32 from ) { xWrite8( 0x50 | from.Id ); }
__forceinline void xPUSH( void* from ) { xPUSH( ptr[from] ); }
// pushes the EFLAGS register onto the stack
__forceinline void xPUSHFD() { xWrite8( 0x9C ); }
// pops the EFLAGS register from the stack
__forceinline void xPOPFD() { xWrite8( 0x9D ); }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// //
__forceinline void xRET() { xWrite8( 0xC3 ); }
__forceinline void xCBW() { xWrite16( 0x9866 ); }
__forceinline void xCWD() { xWrite8( 0x98 ); }
__forceinline void xCDQ() { xWrite8( 0x99 ); }
__forceinline void xCWDE() { xWrite8( 0x98 ); }
__forceinline void xLAHF() { xWrite8( 0x9f ); }
__forceinline void xSAHF() { xWrite8( 0x9e ); }
__forceinline void xSTC() { xWrite8( 0xF9 ); }
__forceinline void xCLC() { xWrite8( 0xF8 ); }
// NOP 1-byte
__forceinline void xNOP() { xWrite8(0x90); }
__emitinline void xBSWAP( const xRegister32& to ) __emitinline void xBSWAP( const xRegister32& to )
{ {
write8( 0x0F ); xWrite8( 0x0F );
write8( 0xC8 | to.Id ); xWrite8( 0xC8 | to.Id );
} }
} }

View File

@ -20,183 +20,183 @@
#include "ix86_legacy_internal.h" #include "ix86_legacy_internal.h"
//------------------------------------------------------------------ //------------------------------------------------------------------
// 3DNOW instructions // 3DNOW instructions [Anyone caught dead using these will be re-killed]
//------------------------------------------------------------------ //------------------------------------------------------------------
/* femms */ /* femms */
emitterT void FEMMS( void ) emitterT void FEMMS( void )
{ {
write16( 0x0E0F ); xWrite16( 0x0E0F );
} }
emitterT void PFCMPEQMtoR( x86IntRegType to, uptr from ) emitterT void PFCMPEQMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0xB0 ); xWrite8( 0xB0 );
} }
emitterT void PFCMPGTMtoR( x86IntRegType to, uptr from ) emitterT void PFCMPGTMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0xA0 ); xWrite8( 0xA0 );
} }
emitterT void PFCMPGEMtoR( x86IntRegType to, uptr from ) emitterT void PFCMPGEMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0x90 ); xWrite8( 0x90 );
} }
emitterT void PFADDMtoR( x86IntRegType to, uptr from ) emitterT void PFADDMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0x9E ); xWrite8( 0x9E );
} }
emitterT void PFADDRtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFADDRtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0x9E ); xWrite8( 0x9E );
} }
emitterT void PFSUBMtoR( x86IntRegType to, uptr from ) emitterT void PFSUBMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0x9A ); xWrite8( 0x9A );
} }
emitterT void PFSUBRtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFSUBRtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0x9A ); xWrite8( 0x9A );
} }
emitterT void PFMULMtoR( x86IntRegType to, uptr from ) emitterT void PFMULMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0xB4 ); xWrite8( 0xB4 );
} }
emitterT void PFMULRtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFMULRtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0xB4 ); xWrite8( 0xB4 );
} }
emitterT void PFRCPMtoR( x86IntRegType to, uptr from ) emitterT void PFRCPMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0x96 ); xWrite8( 0x96 );
} }
emitterT void PFRCPRtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFRCPRtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0x96 ); xWrite8( 0x96 );
} }
emitterT void PFRCPIT1RtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFRCPIT1RtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0xA6 ); xWrite8( 0xA6 );
} }
emitterT void PFRCPIT2RtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFRCPIT2RtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0xB6 ); xWrite8( 0xB6 );
} }
emitterT void PFRSQRTRtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFRSQRTRtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0x97 ); xWrite8( 0x97 );
} }
emitterT void PFRSQIT1RtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFRSQIT1RtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0xA7 ); xWrite8( 0xA7 );
} }
emitterT void PF2IDMtoR( x86IntRegType to, uptr from ) emitterT void PF2IDMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0x1D ); xWrite8( 0x1D );
} }
emitterT void PF2IDRtoR( x86IntRegType to, x86IntRegType from ) emitterT void PF2IDRtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0x1D ); xWrite8( 0x1D );
} }
emitterT void PI2FDMtoR( x86IntRegType to, uptr from ) emitterT void PI2FDMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0x0D ); xWrite8( 0x0D );
} }
emitterT void PI2FDRtoR( x86IntRegType to, x86IntRegType from ) emitterT void PI2FDRtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0x0D ); xWrite8( 0x0D );
} }
emitterT void PFMAXMtoR( x86IntRegType to, uptr from ) emitterT void PFMAXMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0xA4 ); xWrite8( 0xA4 );
} }
emitterT void PFMAXRtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFMAXRtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0xA4 ); xWrite8( 0xA4 );
} }
emitterT void PFMINMtoR( x86IntRegType to, uptr from ) emitterT void PFMINMtoR( x86IntRegType to, uptr from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 0, to, DISP32 ); ModRM( 0, to, DISP32 );
write32( from ); xWrite32( from );
write8( 0x94 ); xWrite8( 0x94 );
} }
emitterT void PFMINRtoR( x86IntRegType to, x86IntRegType from ) emitterT void PFMINRtoR( x86IntRegType to, x86IntRegType from )
{ {
write16( 0x0F0F ); xWrite16( 0x0F0F );
ModRM( 3, to, from ); ModRM( 3, to, from );
write8( 0x94 ); xWrite8( 0x94 );
} }

View File

@ -26,244 +26,244 @@
/* fild m32 to fpu reg stack */ /* fild m32 to fpu reg stack */
emitterT void FILD32( u32 from ) emitterT void FILD32( u32 from )
{ {
write8( 0xDB ); xWrite8( 0xDB );
ModRM( 0, 0x0, DISP32 ); ModRM( 0, 0x0, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
/* fistp m32 from fpu reg stack */ /* fistp m32 from fpu reg stack */
emitterT void FISTP32( u32 from ) emitterT void FISTP32( u32 from )
{ {
write8( 0xDB ); xWrite8( 0xDB );
ModRM( 0, 0x3, DISP32 ); ModRM( 0, 0x3, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
/* fld m32 to fpu reg stack */ /* fld m32 to fpu reg stack */
emitterT void FLD32( u32 from ) emitterT void FLD32( u32 from )
{ {
write8( 0xD9 ); xWrite8( 0xD9 );
ModRM( 0, 0x0, DISP32 ); ModRM( 0, 0x0, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
// fld st(i) // fld st(i)
emitterT void FLD(int st) { write16(0xc0d9+(st<<8)); } emitterT void FLD(int st) { xWrite16(0xc0d9+(st<<8)); }
emitterT void FLD1() { write16(0xe8d9); } emitterT void FLD1() { xWrite16(0xe8d9); }
emitterT void FLDL2E() { write16(0xead9); } emitterT void FLDL2E() { xWrite16(0xead9); }
/* fst m32 from fpu reg stack */ /* fst m32 from fpu reg stack */
emitterT void FST32( u32 to ) emitterT void FST32( u32 to )
{ {
write8( 0xD9 ); xWrite8( 0xD9 );
ModRM( 0, 0x2, DISP32 ); ModRM( 0, 0x2, DISP32 );
write32( MEMADDR(to, 4) ); xWrite32( MEMADDR(to, 4) );
} }
/* fstp m32 from fpu reg stack */ /* fstp m32 from fpu reg stack */
emitterT void FSTP32( u32 to ) emitterT void FSTP32( u32 to )
{ {
write8( 0xD9 ); xWrite8( 0xD9 );
ModRM( 0, 0x3, DISP32 ); ModRM( 0, 0x3, DISP32 );
write32( MEMADDR(to, 4) ); xWrite32( MEMADDR(to, 4) );
} }
// fstp st(i) // fstp st(i)
emitterT void FSTP(int st) { write16(0xd8dd+(st<<8)); } emitterT void FSTP(int st) { xWrite16(0xd8dd+(st<<8)); }
/* fldcw fpu control word from m16 */ /* fldcw fpu control word from m16 */
emitterT void FLDCW( u32 from ) emitterT void FLDCW( u32 from )
{ {
write8( 0xD9 ); xWrite8( 0xD9 );
ModRM( 0, 0x5, DISP32 ); ModRM( 0, 0x5, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
/* fnstcw fpu control word to m16 */ /* fnstcw fpu control word to m16 */
emitterT void FNSTCW( u32 to ) emitterT void FNSTCW( u32 to )
{ {
write8( 0xD9 ); xWrite8( 0xD9 );
ModRM( 0, 0x7, DISP32 ); ModRM( 0, 0x7, DISP32 );
write32( MEMADDR(to, 4) ); xWrite32( MEMADDR(to, 4) );
} }
emitterT void FNSTSWtoAX() { write16(0xE0DF); } emitterT void FNSTSWtoAX() { xWrite16(0xE0DF); }
emitterT void FXAM() { write16(0xe5d9); } emitterT void FXAM() { xWrite16(0xe5d9); }
emitterT void FDECSTP() { write16(0xf6d9); } emitterT void FDECSTP() { xWrite16(0xf6d9); }
emitterT void FRNDINT() { write16(0xfcd9); } emitterT void FRNDINT() { xWrite16(0xfcd9); }
emitterT void FXCH(int st) { write16(0xc8d9+(st<<8)); } emitterT void FXCH(int st) { xWrite16(0xc8d9+(st<<8)); }
emitterT void F2XM1() { write16(0xf0d9); } emitterT void F2XM1() { xWrite16(0xf0d9); }
emitterT void FSCALE() { write16(0xfdd9); } emitterT void FSCALE() { xWrite16(0xfdd9); }
emitterT void FPATAN(void) { write16(0xf3d9); } emitterT void FPATAN(void) { xWrite16(0xf3d9); }
emitterT void FSIN(void) { write16(0xfed9); } emitterT void FSIN(void) { xWrite16(0xfed9); }
/* fadd ST(src) to fpu reg stack ST(0) */ /* fadd ST(src) to fpu reg stack ST(0) */
emitterT void FADD32Rto0( x86IntRegType src ) emitterT void FADD32Rto0( x86IntRegType src )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
write8( 0xC0 + src ); xWrite8( 0xC0 + src );
} }
/* fadd ST(0) to fpu reg stack ST(src) */ /* fadd ST(0) to fpu reg stack ST(src) */
emitterT void FADD320toR( x86IntRegType src ) emitterT void FADD320toR( x86IntRegType src )
{ {
write8( 0xDC ); xWrite8( 0xDC );
write8( 0xC0 + src ); xWrite8( 0xC0 + src );
} }
/* fsub ST(src) to fpu reg stack ST(0) */ /* fsub ST(src) to fpu reg stack ST(0) */
emitterT void FSUB32Rto0( x86IntRegType src ) emitterT void FSUB32Rto0( x86IntRegType src )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
write8( 0xE0 + src ); xWrite8( 0xE0 + src );
} }
/* fsub ST(0) to fpu reg stack ST(src) */ /* fsub ST(0) to fpu reg stack ST(src) */
emitterT void FSUB320toR( x86IntRegType src ) emitterT void FSUB320toR( x86IntRegType src )
{ {
write8( 0xDC ); xWrite8( 0xDC );
write8( 0xE8 + src ); xWrite8( 0xE8 + src );
} }
/* fsubp -> substract ST(0) from ST(1), store in ST(1) and POP stack */ /* fsubp -> substract ST(0) from ST(1), store in ST(1) and POP stack */
emitterT void FSUBP( void ) emitterT void FSUBP( void )
{ {
write8( 0xDE ); xWrite8( 0xDE );
write8( 0xE9 ); xWrite8( 0xE9 );
} }
/* fmul ST(src) to fpu reg stack ST(0) */ /* fmul ST(src) to fpu reg stack ST(0) */
emitterT void FMUL32Rto0( x86IntRegType src ) emitterT void FMUL32Rto0( x86IntRegType src )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
write8( 0xC8 + src ); xWrite8( 0xC8 + src );
} }
/* fmul ST(0) to fpu reg stack ST(src) */ /* fmul ST(0) to fpu reg stack ST(src) */
emitterT void FMUL320toR( x86IntRegType src ) emitterT void FMUL320toR( x86IntRegType src )
{ {
write8( 0xDC ); xWrite8( 0xDC );
write8( 0xC8 + src ); xWrite8( 0xC8 + src );
} }
/* fdiv ST(src) to fpu reg stack ST(0) */ /* fdiv ST(src) to fpu reg stack ST(0) */
emitterT void FDIV32Rto0( x86IntRegType src ) emitterT void FDIV32Rto0( x86IntRegType src )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
write8( 0xF0 + src ); xWrite8( 0xF0 + src );
} }
/* fdiv ST(0) to fpu reg stack ST(src) */ /* fdiv ST(0) to fpu reg stack ST(src) */
emitterT void FDIV320toR( x86IntRegType src ) emitterT void FDIV320toR( x86IntRegType src )
{ {
write8( 0xDC ); xWrite8( 0xDC );
write8( 0xF8 + src ); xWrite8( 0xF8 + src );
} }
emitterT void FDIV320toRP( x86IntRegType src ) emitterT void FDIV320toRP( x86IntRegType src )
{ {
write8( 0xDE ); xWrite8( 0xDE );
write8( 0xF8 + src ); xWrite8( 0xF8 + src );
} }
/* fadd m32 to fpu reg stack */ /* fadd m32 to fpu reg stack */
emitterT void FADD32( u32 from ) emitterT void FADD32( u32 from )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
ModRM( 0, 0x0, DISP32 ); ModRM( 0, 0x0, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
/* fsub m32 to fpu reg stack */ /* fsub m32 to fpu reg stack */
emitterT void FSUB32( u32 from ) emitterT void FSUB32( u32 from )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
ModRM( 0, 0x4, DISP32 ); ModRM( 0, 0x4, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
/* fmul m32 to fpu reg stack */ /* fmul m32 to fpu reg stack */
emitterT void FMUL32( u32 from ) emitterT void FMUL32( u32 from )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
ModRM( 0, 0x1, DISP32 ); ModRM( 0, 0x1, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
/* fdiv m32 to fpu reg stack */ /* fdiv m32 to fpu reg stack */
emitterT void FDIV32( u32 from ) emitterT void FDIV32( u32 from )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
ModRM( 0, 0x6, DISP32 ); ModRM( 0, 0x6, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
/* fabs fpu reg stack */ /* fabs fpu reg stack */
emitterT void FABS( void ) emitterT void FABS( void )
{ {
write16( 0xE1D9 ); xWrite16( 0xE1D9 );
} }
/* fsqrt fpu reg stack */ /* fsqrt fpu reg stack */
emitterT void FSQRT( void ) emitterT void FSQRT( void )
{ {
write16( 0xFAD9 ); xWrite16( 0xFAD9 );
} }
/* fchs fpu reg stack */ /* fchs fpu reg stack */
emitterT void FCHS( void ) emitterT void FCHS( void )
{ {
write16( 0xE0D9 ); xWrite16( 0xE0D9 );
} }
/* fcomi st, st(i) */ /* fcomi st, st(i) */
emitterT void FCOMI( x86IntRegType src ) emitterT void FCOMI( x86IntRegType src )
{ {
write8( 0xDB ); xWrite8( 0xDB );
write8( 0xF0 + src ); xWrite8( 0xF0 + src );
} }
/* fcomip st, st(i) */ /* fcomip st, st(i) */
emitterT void FCOMIP( x86IntRegType src ) emitterT void FCOMIP( x86IntRegType src )
{ {
write8( 0xDF ); xWrite8( 0xDF );
write8( 0xF0 + src ); xWrite8( 0xF0 + src );
} }
/* fucomi st, st(i) */ /* fucomi st, st(i) */
emitterT void FUCOMI( x86IntRegType src ) emitterT void FUCOMI( x86IntRegType src )
{ {
write8( 0xDB ); xWrite8( 0xDB );
write8( 0xE8 + src ); xWrite8( 0xE8 + src );
} }
/* fucomip st, st(i) */ /* fucomip st, st(i) */
emitterT void FUCOMIP( x86IntRegType src ) emitterT void FUCOMIP( x86IntRegType src )
{ {
write8( 0xDF ); xWrite8( 0xDF );
write8( 0xE8 + src ); xWrite8( 0xE8 + src );
} }
/* fcom m32 to fpu reg stack */ /* fcom m32 to fpu reg stack */
emitterT void FCOM32( u32 from ) emitterT void FCOM32( u32 from )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
ModRM( 0, 0x2, DISP32 ); ModRM( 0, 0x2, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
/* fcomp m32 to fpu reg stack */ /* fcomp m32 to fpu reg stack */
emitterT void FCOMP32( u32 from ) emitterT void FCOMP32( u32 from )
{ {
write8( 0xD8 ); xWrite8( 0xD8 );
ModRM( 0, 0x3, DISP32 ); ModRM( 0, 0x3, DISP32 );
write32( MEMADDR(from, 4) ); xWrite32( MEMADDR(from, 4) );
} }
#define FCMOV32( low, high ) \ #define FCMOV32( low, high ) \
{ \ { \
write8( low ); \ xWrite8( low ); \
write8( high + from ); \ xWrite8( high + from ); \
} }
emitterT void FCMOVB32( x86IntRegType from ) { FCMOV32( 0xDA, 0xC0 ); } emitterT void FCMOVB32( x86IntRegType from ) { FCMOV32( 0xDA, 0xC0 ); }

View File

@ -175,7 +175,7 @@ namespace x86Emitter
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
template< typename OperandType > template< typename OperandType >
xForwardJump<OperandType>::xForwardJump( JccComparisonType cctype ) : xForwardJump<OperandType>::xForwardJump( JccComparisonType cctype ) :
BasePtr( (s8*)iGetPtr() + BasePtr( (s8*)xGetPtr() +
((OperandSize == 1) ? 2 : // j8's are always 2 bytes. ((OperandSize == 1) ? 2 : // j8's are always 2 bytes.
((cctype==Jcc_Unconditional) ? 5 : 6 )) // j32's are either 5 or 6 bytes ((cctype==Jcc_Unconditional) ? 5 : 6 )) // j32's are either 5 or 6 bytes
) )
@ -184,19 +184,19 @@ namespace x86Emitter
jASSUME( OperandSize == 1 || OperandSize == 4 ); jASSUME( OperandSize == 1 || OperandSize == 4 );
if( OperandSize == 1 ) if( OperandSize == 1 )
xWrite<u8>( (cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype) ); xWrite8( (cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype) );
else else
{ {
if( cctype == Jcc_Unconditional ) if( cctype == Jcc_Unconditional )
xWrite<u8>( 0xe9 ); xWrite8( 0xe9 );
else else
{ {
xWrite<u8>( 0x0f ); xWrite8( 0x0f );
xWrite<u8>( 0x80 | cctype ); xWrite8( 0x80 | cctype );
} }
} }
iAdvancePtr( OperandSize ); xAdvancePtr( OperandSize );
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -205,7 +205,7 @@ namespace x86Emitter
{ {
jASSUME( BasePtr != NULL ); jASSUME( BasePtr != NULL );
sptr displacement = (sptr)iGetPtr() - (sptr)BasePtr; sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr;
if( OperandSize == 1 ) if( OperandSize == 1 )
{ {
if( !is_s8( displacement ) ) if( !is_s8( displacement ) )

View File

@ -57,7 +57,7 @@ namespace x86Emitter
// flags. // flags.
extern const Internal::MovImplAll xMOV; extern const Internal::MovImplAll xMOV;
extern const Internal::TestImplAll xTEST; extern const Internal::xImpl_Test xTEST;
extern const Internal::Group2ImplAll<Internal::G2Type_ROL> xROL; extern const Internal::Group2ImplAll<Internal::G2Type_ROL> xROL;
extern const Internal::Group2ImplAll<Internal::G2Type_ROR> xROR; extern const Internal::Group2ImplAll<Internal::G2Type_ROR> xROR;
@ -70,15 +70,15 @@ namespace x86Emitter
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Group 3 Instruction Class // Group 3 Instruction Class
extern const Internal::Group3ImplAll<Internal::G3Type_NOT> xNOT; extern const Internal::xImpl_Group3<Internal::G3Type_NOT> xNOT;
extern const Internal::Group3ImplAll<Internal::G3Type_NEG> xNEG; extern const Internal::xImpl_Group3<Internal::G3Type_NEG> xNEG;
extern const Internal::Group3ImplAll<Internal::G3Type_MUL> xUMUL; extern const Internal::xImpl_Group3<Internal::G3Type_MUL> xUMUL;
extern const Internal::Group3ImplAll<Internal::G3Type_DIV> xUDIV; extern const Internal::xImpl_Group3<Internal::G3Type_DIV> xUDIV;
extern const Internal::xImpl_Group3<Internal::G3Type_iDIV,0x5e> xDIV; extern const Internal::xImpl_iDiv xDIV;
extern const Internal::xImpl_iMul xMUL; extern const Internal::xImpl_iMul xMUL;
extern const Internal::IncDecImplAll<false> xINC; extern const Internal::xImpl_IncDec<false> xINC;
extern const Internal::IncDecImplAll<true> xDEC; extern const Internal::xImpl_IncDec<true> xDEC;
extern const Internal::MovExtendImplAll<false> xMOVZX; extern const Internal::MovExtendImplAll<false> xMOVZX;
extern const Internal::MovExtendImplAll<true> xMOVSX; extern const Internal::MovExtendImplAll<true> xMOVSX;
@ -86,16 +86,16 @@ namespace x86Emitter
extern const Internal::DwordShiftImplAll<false> xSHLD; extern const Internal::DwordShiftImplAll<false> xSHLD;
extern const Internal::DwordShiftImplAll<true> xSHRD; extern const Internal::DwordShiftImplAll<true> xSHRD;
extern const Internal::Group8Impl<Internal::G8Type_BT> xBT; extern const Internal::xImpl_Group8<Internal::G8Type_BT> xBT;
extern const Internal::Group8Impl<Internal::G8Type_BTR> xBTR; extern const Internal::xImpl_Group8<Internal::G8Type_BTR> xBTR;
extern const Internal::Group8Impl<Internal::G8Type_BTS> xBTS; extern const Internal::xImpl_Group8<Internal::G8Type_BTS> xBTS;
extern const Internal::Group8Impl<Internal::G8Type_BTC> xBTC; extern const Internal::xImpl_Group8<Internal::G8Type_BTC> xBTC;
extern const Internal::JmpCallImplAll<true> xJMP; extern const Internal::xImpl_JmpCall<true> xJMP;
extern const Internal::JmpCallImplAll<false> xCALL; extern const Internal::xImpl_JmpCall<false> xCALL;
extern const Internal::BitScanImpl<0xbc> xBSF; extern const Internal::xImpl_BitScan<0xbc> xBSF;
extern const Internal::BitScanImpl<0xbd> xBSR; extern const Internal::xImpl_BitScan<0xbd> xBSR;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
extern const Internal::CMovImplGeneric xCMOV; extern const Internal::CMovImplGeneric xCMOV;
@ -175,41 +175,76 @@ namespace x86Emitter
extern void xPOP( const ModSibBase& from ); extern void xPOP( const ModSibBase& from );
extern void xPUSH( const ModSibBase& from ); extern void xPUSH( const ModSibBase& from );
static __forceinline void xPOP( xRegister32 from ) { write8( 0x58 | from.Id ); } extern void xPOP( xRegister32 from );
static __forceinline void xPOP( void* from ) { xPOP( ptr[from] ); } extern void xPOP( void* from );
static __forceinline void xPUSH( u32 imm ) { write8( 0x68 ); write32( imm ); } extern void xPUSH( u32 imm );
static __forceinline void xPUSH( xRegister32 from ) { write8( 0x50 | from.Id ); } extern void xPUSH( xRegister32 from );
static __forceinline void xPUSH( void* from ) { xPUSH( ptr[from] ); } extern void xPUSH( void* from );
// pushes the EFLAGS register onto the stack // pushes the EFLAGS register onto the stack
static __forceinline void xPUSHFD() { write8( 0x9C ); } extern void xPUSHFD();
// pops the EFLAGS register from the stack // pops the EFLAGS register from the stack
static __forceinline void xPOPFD() { write8( 0x9D ); } extern void xPOPFD();
// ----- Miscellaneous Instructions ----- // ----- Miscellaneous Instructions -----
// Various Instructions with no parameter and no special encoding logic. // Various Instructions with no parameter and no special encoding logic.
__forceinline void xRET() { write8( 0xC3 ); } extern void xRET();
__forceinline void xCBW() { write16( 0x9866 ); } extern void xCBW();
__forceinline void xCWD() { write8( 0x98 ); } extern void xCWD();
__forceinline void xCDQ() { write8( 0x99 ); } extern void xCDQ();
__forceinline void xCWDE() { write8( 0x98 ); } extern void xCWDE();
__forceinline void xLAHF() { write8( 0x9f ); } extern void xLAHF();
__forceinline void xSAHF() { write8( 0x9e ); } extern void xSAHF();
__forceinline void xSTC() { write8( 0xF9 ); } extern void xSTC();
__forceinline void xCLC() { write8( 0xF8 ); } extern void xCLC();
// NOP 1-byte // NOP 1-byte
__forceinline void xNOP() { write8(0x90); } extern void xNOP();
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// JMP / Jcc Instructions! // JMP / Jcc Instructions!
extern void iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward=false ); extern void iJcc( JccComparisonType comparison, void* target );
// ------------------------------------------------------------------------
// Conditional jumps to fixed targets.
// Jumps accept any pointer as a valid target (function or data), and will generate either
// 8 or 32 bit displacement versions of the jump, depending on relative displacement of
// the target (efficient!)
//
template< typename T > __forceinline void xJE( const T* func ) { iJcc( Jcc_Equal, (void*)(uptr)func ); }
template< typename T > __forceinline void xJZ( const T* func ) { iJcc( Jcc_Zero, (void*)(uptr)func ); }
template< typename T > __forceinline void xJNE( const T* func ) { iJcc( Jcc_NotEqual, (void*)(uptr)func ); }
template< typename T > __forceinline void xJNZ( const T* func ) { iJcc( Jcc_NotZero, (void*)(uptr)func ); }
template< typename T > __forceinline void xJO( const T* func ) { iJcc( Jcc_Overflow, (void*)(uptr)func ); }
template< typename T > __forceinline void xJNO( const T* func ) { iJcc( Jcc_NotOverflow, (void*)(uptr)func ); }
template< typename T > __forceinline void xJC( const T* func ) { iJcc( Jcc_Carry, (void*)(uptr)func ); }
template< typename T > __forceinline void xJNC( const T* func ) { iJcc( Jcc_NotCarry, (void*)(uptr)func ); }
template< typename T > __forceinline void xJS( const T* func ) { iJcc( Jcc_Signed, (void*)(uptr)func ); }
template< typename T > __forceinline void xJNS( const T* func ) { iJcc( Jcc_Unsigned, (void*)(uptr)func ); }
template< typename T > __forceinline void xJPE( const T* func ) { iJcc( Jcc_ParityEven, (void*)(uptr)func ); }
template< typename T > __forceinline void xJPO( const T* func ) { iJcc( Jcc_ParityOdd, (void*)(uptr)func ); }
template< typename T > __forceinline void xJL( const T* func ) { iJcc( Jcc_Less, (void*)(uptr)func ); }
template< typename T > __forceinline void xJLE( const T* func ) { iJcc( Jcc_LessOrEqual, (void*)(uptr)func ); }
template< typename T > __forceinline void xJG( const T* func ) { iJcc( Jcc_Greater, (void*)(uptr)func ); }
template< typename T > __forceinline void xJGE( const T* func ) { iJcc( Jcc_GreaterOrEqual, (void*)(uptr)func ); }
template< typename T > __forceinline void xJB( const T* func ) { iJcc( Jcc_Below, (void*)(uptr)func ); }
template< typename T > __forceinline void xJBE( const T* func ) { iJcc( Jcc_BelowOrEqual, (void*)(uptr)func ); }
template< typename T > __forceinline void xJA( const T* func ) { iJcc( Jcc_Above, (void*)(uptr)func ); }
template< typename T > __forceinline void xJAE( const T* func ) { iJcc( Jcc_AboveOrEqual, (void*)(uptr)func ); }
// ------------------------------------------------------------------------
// Forward Jump Helpers (act as labels!)
#define DEFINE_FORWARD_JUMP( label, cond ) \ #define DEFINE_FORWARD_JUMP( label, cond ) \
template< typename OperandType > \ template< typename OperandType > \
class xForward##label : public xForwardJump<OperandType> \ class xForward##label : public xForwardJump<OperandType> \

View File

@ -40,30 +40,30 @@ namespace x86Emitter {
using namespace Internal; using namespace Internal;
const JmpCallImplAll<true> xJMP; const xImpl_JmpCall<true> xJMP;
const JmpCallImplAll<false> xCALL; const xImpl_JmpCall<false> xCALL;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void xSmartJump::SetTarget() void xSmartJump::SetTarget()
{ {
u8* target = iGetPtr(); u8* target = xGetPtr();
if( m_baseptr == NULL ) return; if( m_baseptr == NULL ) return;
iSetPtr( m_baseptr ); xSetPtr( m_baseptr );
u8* const saveme = m_baseptr + GetMaxInstructionSize(); u8* const saveme = m_baseptr + GetMaxInstructionSize();
iJccKnownTarget( m_cc, target, true ); iJccKnownTarget( m_cc, target, true );
// Copy recompiled data inward if the jump instruction didn't fill the // Copy recompiled data inward if the jump instruction didn't fill the
// alloted buffer (means that we optimized things to a j8!) // alloted buffer (means that we optimized things to a j8!)
const int spacer = (sptr)saveme - (sptr)iGetPtr(); const int spacer = (sptr)saveme - (sptr)xGetPtr();
if( spacer != 0 ) if( spacer != 0 )
{ {
u8* destpos = iGetPtr(); u8* destpos = xGetPtr();
const int copylen = (sptr)target - (sptr)saveme; const int copylen = (sptr)target - (sptr)saveme;
memcpy_fast( destpos, saveme, copylen ); memcpy_fast( destpos, saveme, copylen );
iSetPtr( target - spacer ); xSetPtr( target - spacer );
} }
} }
@ -81,11 +81,10 @@ xSmartJump::~xSmartJump()
// slideForward - used internally by xSmartJump to indicate that the jump target is going // slideForward - used internally by xSmartJump to indicate that the jump target is going
// to slide forward in the event of an 8 bit displacement. // to slide forward in the event of an 8 bit displacement.
// //
// Using this __emitinline void Internal::iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward )
__emitinline void iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward )
{ {
// Calculate the potential j8 displacement first, assuming an instruction length of 2: // Calculate the potential j8 displacement first, assuming an instruction length of 2:
sptr displacement8 = (sptr)target - ((sptr)iGetPtr() + 2); sptr displacement8 = (sptr)target - ((sptr)xGetPtr() + 2);
const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0; const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0;
displacement8 -= slideVal; displacement8 -= slideVal;
@ -96,7 +95,7 @@ __emitinline void iJccKnownTarget( JccComparisonType comparison, void* target, b
if( is_s8( displacement8 ) ) if( is_s8( displacement8 ) )
{ {
xWrite<u8>( (comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison) ); xWrite8( (comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison) );
xWrite<s8>( displacement8 ); xWrite<s8>( displacement8 );
} }
else else
@ -104,14 +103,21 @@ __emitinline void iJccKnownTarget( JccComparisonType comparison, void* target, b
// Perform a 32 bit jump instead. :( // Perform a 32 bit jump instead. :(
if( comparison == Jcc_Unconditional ) if( comparison == Jcc_Unconditional )
xWrite<u8>( 0xe9 ); xWrite8( 0xe9 );
else else
{ {
xWrite<u8>( 0x0f ); xWrite8( 0x0f );
xWrite<u8>( 0x80 | comparison ); xWrite8( 0x80 | comparison );
} }
xWrite<s32>( (sptr)target - ((sptr)iGetPtr() + 4) ); xWrite<s32>( (sptr)target - ((sptr)xGetPtr() + 4) );
} }
} }
// Low-level jump instruction! Specify a comparison type and a target in void* form, and
// a jump (either 8 or 32 bit) is generated.
__emitinline void iJcc( JccComparisonType comparison, void* target )
{
iJccKnownTarget( comparison, target, false );
}
} }

View File

@ -32,6 +32,30 @@
#include "System.h" #include "System.h"
#include "ix86_legacy_internal.h" #include "ix86_legacy_internal.h"
//////////////////////////////////////////////////////////////////////////////////////////
//
emitterT void ModRM( uint mod, uint reg, uint rm )
{
// Note: Following ASSUMEs 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.
jASSUME( mod < 4 );
jASSUME( reg < 8 );
jASSUME( rm < 8 );
xWrite8( (mod << 6) | (reg << 3) | rm );
}
emitterT void SibSB( uint ss, uint index, uint base )
{
// Note: Following ASSUMEs 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.
jASSUME( ss < 4 );
jASSUME( index < 8 );
jASSUME( base < 8 );
xWrite8( (ss << 6) | (index << 3) | base );
}
using namespace x86Emitter; using namespace x86Emitter;
template< typename ImmType > template< typename ImmType >
@ -310,63 +334,26 @@ emitterT void SAHF() { xSAHF(); }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Note: the 'to' field can either be a register or a special opcode extension specifier
// depending on the opcode's encoding.
emitterT void WriteRmOffsetFrom(x86IntRegType to, x86IntRegType from, int offset)
{
if ((from&7) == ESP) {
if( offset == 0 ) {
ModRM( 0, to, 0x4 );
SibSB( 0, 0x4, 0x4 );
}
else if( is_s8( offset ) ) {
ModRM( 1, to, 0x4 );
SibSB( 0, 0x4, 0x4 );
write8(offset);
}
else {
ModRM( 2, to, 0x4 );
SibSB( 0, 0x4, 0x4 );
write32(offset);
}
}
else {
if( offset == 0 ) {
ModRM( 0, to, from );
}
else if( is_s8( offset ) ) {
ModRM( 1, to, from );
write8(offset);
}
else {
ModRM( 2, to, from );
write32(offset);
}
}
}
emitterT u8* J8Rel( int cc, int to ) emitterT u8* J8Rel( int cc, int to )
{ {
write8( cc ); xWrite8( cc );
write8( to ); xWrite8( to );
return (u8*)(x86Ptr - 1); return (u8*)(x86Ptr - 1);
} }
emitterT u16* J16Rel( int cc, u32 to ) emitterT u16* J16Rel( int cc, u32 to )
{ {
write16( 0x0F66 ); xWrite16( 0x0F66 );
write8( cc ); xWrite8( cc );
write16( to ); xWrite16( to );
return (u16*)( x86Ptr - 2 ); return (u16*)( x86Ptr - 2 );
} }
emitterT u32* J32Rel( int cc, u32 to ) emitterT u32* J32Rel( int cc, u32 to )
{ {
write8( 0x0F ); xWrite8( 0x0F );
write8( cc ); xWrite8( cc );
write32( to ); xWrite32( to );
return (u32*)( x86Ptr - 4 ); return (u32*)( x86Ptr - 4 );
} }
@ -448,8 +435,8 @@ emitterT void NOP( void ) { xNOP(); }
/* jmp rel8 */ /* jmp rel8 */
emitterT u8* JMP8( u8 to ) emitterT u8* JMP8( u8 to )
{ {
write8( 0xEB ); xWrite8( 0xEB );
write8( to ); xWrite8( to );
return x86Ptr - 1; return x86Ptr - 1;
} }
@ -457,8 +444,8 @@ emitterT u8* JMP8( u8 to )
emitterT u32* JMP32( uptr to ) emitterT u32* JMP32( uptr to )
{ {
assert( (sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff ); assert( (sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff );
write8( 0xE9 ); xWrite8( 0xE9 );
write32( to ); xWrite32( to );
return (u32*)(x86Ptr - 4 ); return (u32*)(x86Ptr - 4 );
} }

View File

@ -18,17 +18,6 @@
#pragma once #pragma once
//------------------------------------------------------------------
// legacy write functions (depreciated, use x86Emitter::EmitPtrCache instead)
//------------------------------------------------------------------
#define emitterT __forceinline
using x86Emitter::write8;
using x86Emitter::write16;
using x86Emitter::write24;
using x86Emitter::write32;
using x86Emitter::write64;
//------------------------------------------------------------------ //------------------------------------------------------------------
// legacy jump/align functions // legacy jump/align functions
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -24,6 +24,13 @@
// Legacy Helper Macros and Functions (depreciated) // Legacy Helper Macros and Functions (depreciated)
//------------------------------------------------------------------ //------------------------------------------------------------------
#define emitterT __forceinline
using x86Emitter::xWrite8;
using x86Emitter::xWrite16;
using x86Emitter::xWrite32;
using x86Emitter::xWrite64;
#include "ix86_legacy_types.h" #include "ix86_legacy_types.h"
#include "ix86_legacy_instructions.h" #include "ix86_legacy_instructions.h"
@ -37,7 +44,6 @@
#define _MM_MK_INSERTPS_NDX(srcField, dstField, zeroMask) (((srcField)<<6) | ((dstField)<<4) | (zeroMask)) #define _MM_MK_INSERTPS_NDX(srcField, dstField, zeroMask) (((srcField)<<6) | ((dstField)<<4) | (zeroMask))
extern void WriteRmOffsetFrom(x86IntRegType to, x86IntRegType from, int offset);
extern void ModRM( uint mod, uint reg, uint rm ); extern void ModRM( uint mod, uint reg, uint rm );
extern void SibSB( uint ss, uint index, uint base ); extern void SibSB( uint ss, uint index, uint base );
extern void SET8R( int cc, int to ); extern void SET8R( int cc, int to );
@ -45,27 +51,3 @@ extern u8* J8Rel( int cc, int to );
extern u32* J32Rel( int cc, u32 to ); extern u32* J32Rel( int cc, u32 to );
extern u64 GetCPUTick( void ); extern u64 GetCPUTick( void );
//////////////////////////////////////////////////////////////////////////////////////////
//
emitterT void ModRM( uint mod, uint reg, uint rm )
{
// Note: Following ASSUMEs 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.
jASSUME( mod < 4 );
jASSUME( reg < 8 );
jASSUME( rm < 8 );
write8( (mod << 6) | (reg << 3) | rm );
}
emitterT void SibSB( uint ss, uint index, uint base )
{
// Note: Following ASSUMEs 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.
jASSUME( ss < 4 );
jASSUME( index < 8 );
jASSUME( base < 8 );
write8( (ss << 6) | (index << 3) | base );
}

View File

@ -36,29 +36,29 @@ __emitinline void Internal::SimdPrefix( u8 prefix, u16 opcode )
{ {
const bool is16BitOpcode = ((opcode & 0xff) == 0x38) || ((opcode & 0xff) == 0x3a); const bool is16BitOpcode = ((opcode & 0xff) == 0x38) || ((opcode & 0xff) == 0x3a);
// If the lower byte is not a valid previx and the upper byte is non-zero it // If the lower byte is not a valid prefix and the upper byte is non-zero it
// means we made a mistake! // means we made a mistake!
if( !is16BitOpcode ) jASSUME( (opcode >> 8) == 0 ); if( !is16BitOpcode ) jASSUME( (opcode >> 8) == 0 );
if( prefix != 0 ) if( prefix != 0 )
{ {
if( is16BitOpcode ) if( is16BitOpcode )
xWrite<u32>( (opcode<<16) | 0x0f00 | prefix ); xWrite32( (opcode<<16) | 0x0f00 | prefix );
else else
{ {
xWrite<u16>( 0x0f00 | prefix ); xWrite16( 0x0f00 | prefix );
xWrite<u8>( opcode ); xWrite8( opcode );
} }
} }
else else
{ {
if( is16BitOpcode ) if( is16BitOpcode )
{ {
xWrite<u8>( 0x0f ); xWrite8( 0x0f );
xWrite<u16>( opcode ); xWrite16( opcode );
} }
else else
xWrite<u16>( (opcode<<8) | 0x0f ); xWrite16( (opcode<<8) | 0x0f );
} }
} }
@ -199,23 +199,31 @@ const SimdImpl_PMove<false> xPMOVZX;
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// //
__emitinline void xEMMS() // Converts from MMX register mode to FPU register mode. The cpu enters MMX register mode
{ // when ever MMX instructions are run, and if FPU instructions are run without using EMMS,
xWrite<u16>( 0x770F ); // the FPU results will be invalid.
} __forceinline void xEMMS() { xWrite16( 0x770F ); }
// [3DNow] Same as EMMS, but an AMD special version which may (or may not) leave MMX regs
// in an undefined state (which is fine, since presumably you're done using them anyway).
// This instruction is thus faster than EMMS on K8s, but all newer AMD cpus use the same
// logic for either EMMS or FEMMS.
// Conclusion: Obsolete. Just use EMMS instead.
__forceinline void xFEMMS() { xWrite16( 0x0E0F ); }
// Store Streaming SIMD Extension Control/Status to Mem32. // Store Streaming SIMD Extension Control/Status to Mem32.
__emitinline void xSTMXCSR( u32* dest ) __emitinline void xSTMXCSR( u32* dest )
{ {
SimdPrefix( 0, 0xae ); SimdPrefix( 0, 0xae );
xWriteDisp( 3, dest ); EmitSibMagic( 3, dest );
} }
// Load Streaming SIMD Extension Control/Status from Mem32. // Load Streaming SIMD Extension Control/Status from Mem32.
__emitinline void xLDMXCSR( const u32* src ) __emitinline void xLDMXCSR( const u32* src )
{ {
SimdPrefix( 0, 0xae ); SimdPrefix( 0, 0xae );
xWriteDisp( 2, src ); EmitSibMagic( 2, src );
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
@ -279,7 +287,7 @@ __forceinline void xMOVQ( const xRegisterMMX& to, const xRegisterSSE& from )
// that breaks the template inference of writeXMMop(); // that breaks the template inference of writeXMMop();
SimdPrefix( 0xf2, 0xd6 ); SimdPrefix( 0xf2, 0xd6 );
ModRM_Direct( to.Id, from.Id ); EmitSibMagic( to, from );
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
@ -301,13 +309,13 @@ IMPLEMENT_xMOVS( SD, 0xf2 )
__forceinline void xMOVNTDQA( const xRegisterSSE& to, const void* from ) __forceinline void xMOVNTDQA( const xRegisterSSE& to, const void* from )
{ {
xWrite<u32>( 0x2A380f66 ); xWrite32( 0x2A380f66 );
xWriteDisp( to.Id, from ); EmitSibMagic( to.Id, from );
} }
__forceinline void xMOVNTDQA( const xRegisterSSE& to, const ModSibBase& from ) __forceinline void xMOVNTDQA( const xRegisterSSE& to, const ModSibBase& from )
{ {
xWrite<u32>( 0x2A380f66 ); xWrite32( 0x2A380f66 );
EmitSibMagic( to.Id, from ); EmitSibMagic( to.Id, from );
} }

View File

@ -21,7 +21,8 @@
extern void cpudetectInit();//this is all that needs to be called and will fill up the below structs extern void cpudetectInit();//this is all that needs to be called and will fill up the below structs
//cpu capabilities structure //cpu capabilities structure
struct CAPABILITIES { struct CAPABILITIES
{
u32 hasFloatingPointUnit; u32 hasFloatingPointUnit;
u32 hasVirtual8086ModeEnhancements; u32 hasVirtual8086ModeEnhancements;
u32 hasDebuggingExtensions; u32 hasDebuggingExtensions;
@ -63,8 +64,8 @@ struct CAPABILITIES {
extern CAPABILITIES cpucaps; extern CAPABILITIES cpucaps;
struct CPUINFO{ struct CPUINFO
{
u32 x86Family; // Processor Family u32 x86Family; // Processor Family
u32 x86Model; // Processor Model u32 x86Model; // Processor Model
u32 x86PType; // Processor Type u32 x86PType; // Processor Type
@ -109,20 +110,26 @@ extern __threadlocal u32 *j32Ptr[32]; // depreciated item. use local u32* vars
extern __threadlocal XMMSSEType g_xmmtypes[iREGCNT_XMM]; extern __threadlocal XMMSSEType g_xmmtypes[iREGCNT_XMM];
namespace x86Emitter
{
extern void xWrite8( u8 val );
extern void xWrite16( u16 val );
extern void xWrite32( u32 val );
extern void xWrite64( u64 val );
//------------------------------------------------------------------ //------------------------------------------------------------------
// templated version of is_s8 is required, so that u16's get correct sign extension treatment. // templated version of is_s8 is required, so that u16's get correct sign extension treatment.
template< typename T > template< typename T >
static __forceinline bool is_s8( T imm ) { return (s8)imm == (s32)imm; } static __forceinline bool is_s8( T imm ) { return (s8)imm == (s32)imm; }
template< typename T > template< typename T >
static __forceinline void xWrite( T val ) __forceinline void xWrite( T val )
{ {
*(T*)x86Ptr = val; *(T*)x86Ptr = val;
x86Ptr += sizeof(T); x86Ptr += sizeof(T);
} }
namespace x86Emitter
{
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// ALWAYS_USE_MOVAPS [define] / AlwaysUseMovaps [const] // ALWAYS_USE_MOVAPS [define] / AlwaysUseMovaps [const]
@ -178,54 +185,27 @@ namespace x86Emitter
class xAddressInfo; class xAddressInfo;
class ModSibBase; class ModSibBase;
extern void iSetPtr( void* ptr ); extern void xSetPtr( void* ptr );
extern u8* iGetPtr(); extern u8* xGetPtr();
extern void iAlignPtr( uint bytes ); extern void xAlignPtr( uint bytes );
extern void iAdvancePtr( uint bytes ); extern void xAdvancePtr( uint bytes );
static __forceinline void write8( u8 val )
{
xWrite( val );
}
static __forceinline void write16( u16 val )
{
xWrite( val );
}
static __forceinline void write24( u32 val )
{
*(u32*)x86Ptr = val;
x86Ptr += 3;
}
static __forceinline void write32( u32 val )
{
xWrite( val );
}
static __forceinline void write64( u64 val )
{
xWrite( val );
}
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// xRegister // xRegisterBase
// Unless templating some fancy stuff, use the friendly xRegister32/16/8 typedefs instead. // Unless templating some fancy stuff, use the friendly xRegister32/16/8 typedefs instead.
// //
template< typename OperandType > template< typename OperandType >
class xRegister class xRegisterBase
{ {
public: public:
static const uint OperandSize = sizeof( OperandType ); static const uint OperandSize = sizeof( OperandType );
static const xRegister Empty; // defined as an empty/unused value (-1) static const xRegisterBase Empty; // defined as an empty/unused value (-1)
int Id; int Id;
xRegister( const xRegister<OperandType>& src ) : Id( src.Id ) {} xRegisterBase( const xRegisterBase<OperandType>& src ) : Id( src.Id ) {}
xRegister(): Id( -1 ) {} xRegisterBase(): Id( -1 ) {}
explicit xRegister( int regId ) : Id( regId ) { jASSUME( Id >= -1 && Id < 8 ); } explicit xRegisterBase( int regId ) : Id( regId ) { jASSUME( Id >= -1 && Id < 8 ); }
bool IsEmpty() const { return Id < 0; } bool IsEmpty() const { return Id < 0; }
@ -235,19 +215,60 @@ namespace x86Emitter
// returns true if the register is a valid MMX or XMM register. // returns true if the register is a valid MMX or XMM register.
bool IsSIMD() const { return OperandSize == 8 || OperandSize == 16; } bool IsSIMD() const { return OperandSize == 8 || OperandSize == 16; }
bool operator==( const xRegister<OperandType>& src ) const bool operator==( const xRegisterBase<OperandType>& src ) const { return (Id == src.Id); }
{ bool operator!=( const xRegisterBase<OperandType>& src ) const { return (Id != src.Id); }
return (Id == src.Id);
}
bool operator!=( const xRegister<OperandType>& src ) const xRegisterBase<OperandType>& operator=( const xRegisterBase<OperandType>& src )
{ {
return (Id != src.Id); Id = src.Id;
return *this;
} }
};
//////////////////////////////////////////////////////////////////////////////////////////
//
template< typename OperandType >
class xRegister : public xRegisterBase<OperandType>
{
public:
static const xRegister Empty; // defined as an empty/unused value (-1)
public:
xRegister(): xRegisterBase<OperandType>() {}
xRegister( const xRegister& src ) : xRegisterBase<OperandType>( src.Id ) {}
explicit xRegister( const xRegisterBase<OperandType>& src ) : xRegisterBase<OperandType>( src ) {}
explicit xRegister( int regId ) : xRegisterBase<OperandType>( regId ) {}
bool operator==( const xRegister<OperandType>& src ) const { return Id == src.Id; }
bool operator!=( const xRegister<OperandType>& src ) const { return Id != src.Id; }
xRegister<OperandType>& operator=( const xRegister<OperandType>& src ) xRegister<OperandType>& operator=( const xRegister<OperandType>& src )
{ {
Id = src.Id; xRegisterBase<OperandType>::Id = src.Id;
return *this;
}
};
//////////////////////////////////////////////////////////////////////////////////////////
//
template< typename OperandType >
class xRegisterSIMD : public xRegisterBase<OperandType>
{
public:
static const xRegisterSIMD Empty; // defined as an empty/unused value (-1)
public:
xRegisterSIMD(): xRegisterBase<OperandType>() {}
xRegisterSIMD( const xRegisterSIMD& src ) : xRegisterBase<OperandType>( src.Id ) {}
explicit xRegisterSIMD( const xRegisterBase<OperandType>& src ) : xRegisterBase<OperandType>( src ) {}
explicit xRegisterSIMD( int regId ) : xRegisterBase<OperandType>( regId ) {}
bool operator==( const xRegisterSIMD<OperandType>& src ) const { return Id == src.Id; }
bool operator!=( const xRegisterSIMD<OperandType>& src ) const { return Id != src.Id; }
xRegisterSIMD<OperandType>& operator=( const xRegisterSIMD<OperandType>& src )
{
xRegisterBase<OperandType>::Id = src.Id;
return *this; return *this;
} }
}; };
@ -260,8 +281,8 @@ namespace x86Emitter
// all about the the templated code in haphazard fashion. Yay.. >_< // all about the the templated code in haphazard fashion. Yay.. >_<
// //
typedef xRegister<u128> xRegisterSSE; typedef xRegisterSIMD<u128> xRegisterSSE;
typedef xRegister<u64> xRegisterMMX; typedef xRegisterSIMD<u64> xRegisterMMX;
typedef xRegister<u32> xRegister32; typedef xRegister<u32> xRegister32;
typedef xRegister<u16> xRegister16; typedef xRegister<u16> xRegister16;
typedef xRegister<u8> xRegister8; typedef xRegister<u8> xRegister8;
@ -624,9 +645,9 @@ namespace x86Emitter
xSmartJump( JccComparisonType ccType ) xSmartJump( JccComparisonType ccType )
{ {
jASSUME( ccType != Jcc_Unknown ); jASSUME( ccType != Jcc_Unknown );
m_baseptr = iGetPtr(); m_baseptr = xGetPtr();
m_cc = ccType; m_cc = ccType;
iAdvancePtr( GetMaxInstructionSize() ); xAdvancePtr( GetMaxInstructionSize() );
} }
protected: protected:
@ -662,18 +683,69 @@ namespace x86Emitter
// //
namespace Internal namespace Internal
{ {
extern void ModRM( uint mod, uint reg, uint rm ); extern void SimdPrefix( u8 prefix, u16 opcode );
extern void ModRM_Direct( uint reg, uint rm ); extern void EmitSibMagic( uint regfield, const void* address );
extern void SibSB( u32 ss, u32 index, u32 base );
extern void xWriteDisp( int regfield, s32 displacement );
extern void xWriteDisp( int regfield, const void* address );
extern void EmitSibMagic( uint regfield, const ModSibBase& info ); extern void EmitSibMagic( uint regfield, const ModSibBase& info );
extern void iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward );
// 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 ); }
// ------------------------------------------------------------------------
template< typename T > bool Is8BitOp() { return sizeof(T) == 1; } template< typename T > bool Is8BitOp() { return sizeof(T) == 1; }
template< typename T > void prefix16() { if( sizeof(T) == 2 ) xWrite<u8>( 0x66 ); } template< typename T > void prefix16() { if( sizeof(T) == 2 ) xWrite8( 0x66 ); }
#include "implement/xmm/basehelpers.h" #include "implement/xmm/basehelpers.h"
#include "implement/xmm/moremovs.h" #include "implement/xmm/moremovs.h"
@ -686,7 +758,6 @@ namespace x86Emitter
#include "implement/movs.h" // cmov and movsx/zx #include "implement/movs.h" // cmov and movsx/zx
#include "implement/dwshift.h" // doubleword shifts! #include "implement/dwshift.h" // doubleword shifts!
#include "implement/incdec.h" #include "implement/incdec.h"
#include "implement/bittest.h"
#include "implement/test.h" #include "implement/test.h"
#include "implement/jmpcall.h" #include "implement/jmpcall.h"
} }