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"
>
</File>
<File
RelativePath="..\..\x86\ix86\ix86_writers.inl"
>
</File>
<Filter
Name="Implement"
>
<File
RelativePath="..\..\x86\ix86\implement\bittest.h"
>
</File>
<File
RelativePath="..\..\x86\ix86\implement\dwshift.h"
>

View File

@ -1644,7 +1644,7 @@ StartRecomp:
}
if (startpc != 0x81fc0) {
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

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.
// 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
// *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 >
class DwordShiftImplAll
{
protected:
typedef DwordShiftImpl<u32, isShiftRight> m_32;
typedef DwordShiftImpl<u16, isShiftRight> m_16;
static const u8 m_shiftop = isShiftRight ? 0x8 : 0;
public:
// ---------- 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()( void* dest, const xRegister32& from, __unused const xRegisterCL& clreg ) const { m_32::Emit( dest, from ); }
__noinline void operator()( const ModSibBase& sibdest, const xRegister32& from, __unused const xRegisterCL& clreg ) const { m_32::Emit( sibdest, from ); }
__forceinline void operator()( const xRegister32& to, const xRegister32& from, u8 shiftcnt ) const { m_32::Emit( to, from, shiftcnt ); }
__forceinline void operator()( void* dest, const xRegister32& from, u8 shiftcnt ) const { m_32::Emit( dest, from, shiftcnt ); }
__noinline void operator()( const ModSibBase& sibdest, const xRegister32& from, u8 shiftcnt ) const { m_32::Emit( sibdest, shiftcnt ); }
__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 { xOpWrite0F( 0xa5 | m_shiftop, from, dest ); }
__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 { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, to, from ); }
__forceinline void operator()( void* dest, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, from, dest, shiftcnt ); }
__forceinline void operator()( const ModSibBase& dest, const xRegister32& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0xa4 | m_shiftop, from, dest, shiftcnt ); }
// ---------- 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()( void* dest, const xRegister16& from, __unused const xRegisterCL& clreg ) const { m_16::Emit( dest, from ); }
__noinline void operator()( const ModSibBase& sibdest, const xRegister16& from, __unused const xRegisterCL& clreg ) const { m_16::Emit( sibdest, from ); }
__forceinline void operator()( const xRegister16& to, const xRegister16& from, u8 shiftcnt ) const { m_16::Emit( to, from, shiftcnt ); }
__forceinline void operator()( void* dest, const xRegister16& from, u8 shiftcnt ) const { m_16::Emit( dest, from, shiftcnt ); }
__noinline void operator()( const ModSibBase& sibdest, const xRegister16& from, u8 shiftcnt ) const { m_16::Emit( sibdest, shiftcnt ); }
__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 { xOpWrite0F( 0x66, 0xa5 | m_shiftop, from, dest ); }
__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 { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, to, from ); }
__forceinline void operator()( void* dest, const xRegister16& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, from, dest, shiftcnt ); }
__forceinline void operator()( const ModSibBase& dest, const xRegister16& from, u8 shiftcnt ) const { if( shiftcnt != 0 ) xOpWrite0F( 0x66, 0xa4 | m_shiftop, from, dest, shiftcnt ); }
DwordShiftImplAll() {} // Why does GCC need these?
};

View File

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

View File

@ -34,136 +34,79 @@ enum G3Type
//////////////////////////////////////////////////////////////////////////////////////////
//
template< G3Type InstType >
class Group3ImplAll
class xImpl_Group3
{
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>();
xWrite<u8>(Is8BitOp<T>() ? 0xf6 : 0xf7 );
ModRM_Direct( InstType, from.Id );
xWrite8(Is8BitOp<T>() ? 0xf6 : 0xf7 );
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>();
xWrite<u8>( Is8BitOp<T>() ? 0xf6 : 0xf7 );
xWrite8( Is8BitOp<T>() ? 0xf6 : 0xf7 );
EmitSibMagic( InstType, from );
}
Group3ImplAll() {}
xImpl_Group3() {}
};
// ------------------------------------------------------------------------
// This class combines x86 and SSE/SSE2 instructions for iMUL and iDIV.
//
template< G3Type InstType, u16 OpcodeSSE >
class xImpl_Group3 : public Group3ImplAll<InstType>
class ImplMulDivBase : public xImpl_Group3<InstType>
{
public:
ImplMulDivBase() {}
const SimdImpl_DestRegSSE<0x00,OpcodeSSE> PS;
const SimdImpl_DestRegSSE<0x66,OpcodeSSE> PD;
const SimdImpl_DestRegSSE<0xf3,OpcodeSSE> SS;
const SimdImpl_DestRegSSE<0xf2,OpcodeSSE> SD;
};
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!
template< typename ImmType >
class iMulImpl
//
class xImpl_iMul : public ImplMulDivBase<G3Type_iMUL,0x59>
{
protected:
static const uint OperandSize = sizeof(ImmType);
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); }
template< typename T1, typename T2, typename ImmType >
static __forceinline void ImmStyle( const T1& param1, const T2& param2, ImmType imm8 )
{
xOpWrite0F( (sizeof(ImmType) == 2) ? 0x66 : 0, is_s8( imm8 ) ? 0x6b : 0x69, param1, param2 );
if( is_s8( imm8 ) )
xWrite8( imm8 );
else
xWrite<ImmType>( imm8 );
}
public:
// ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, const xRegister<ImmType>& from )
{
prefix16();
write16( 0xaf0f );
ModRM_Direct( to.Id, from.Id );
}
using ImplMulDivBase<G3Type_iMUL,0x59>::operator();
// ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, const void* src )
{
prefix16();
write16( 0xaf0f );
xWriteDisp( to.Id, src );
}
__forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { xOpWrite0F( 0xaf, to, from ); }
__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 ); }
__forceinline void operator()( const xRegister32& to, const xRegister32& from, s32 imm ) const{ ImmStyle( to, from, imm ); }
__forceinline void operator()( const xRegister32& to, const ModSibBase& from, s32 imm ) const { ImmStyle( to, from, imm ); }
// ------------------------------------------------------------------------
static __emitinline void Emit( const xRegister<ImmType>& to, const ModSibBase& src )
{
prefix16();
write16( 0xaf0f );
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 ); }
__forceinline void operator()( const xRegister16& to, const xRegister16& from ) const { xOpWrite0F( 0x66, 0xaf, to, from ); }
__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 ); }
__forceinline void operator()( const xRegister16& to, const xRegister16& from, s16 imm ) const{ ImmStyle( to, from, imm ); }
__forceinline void operator()( const xRegister16& to, const ModSibBase& from, s16 imm ) const { ImmStyle( to, from, imm ); }
xImpl_iMul() {}
};

View File

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

View File

@ -21,48 +21,18 @@
// Implementations found here: CALL and JMP! (unconditional only)
// 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 >
class JmpCallImplAll
class xImpl_JmpCall
{
protected:
typedef JmpCallImpl<u32> m_32;
typedef JmpCallImpl<u16> m_16;
public:
JmpCallImplAll() {}
xImpl_JmpCall() {}
__forceinline void operator()( const xRegister32& absreg ) const { m_32::Emit( isJmp, absreg ); }
__forceinline void operator()( const ModSibStrict<u32>& src ) const { m_32::Emit( isJmp, src ); }
__forceinline void operator()( const xRegister32& absreg ) const { xOpWrite( 0x00, 0xff, isJmp ? 4 : 2, absreg ); }
__forceinline void operator()( const ModSibStrict<u32>& src ) const { xOpWrite( 0x00, 0xff, isJmp ? 4 : 2, src ); }
__forceinline void operator()( const xRegister16& absreg ) const { m_16::Emit( isJmp, absreg ); }
__forceinline void operator()( const ModSibStrict<u16>& src ) const { m_16::Emit( isJmp, src ); }
__forceinline void operator()( const xRegister16& absreg ) const { xOpWrite( 0x66, 0xff, isJmp ? 4 : 2, absreg ); }
__forceinline void operator()( const ModSibStrict<u16>& src ) const { xOpWrite( 0x66, 0xff, isJmp ? 4 : 2, src ); }
// Special form for calling functions. This form automatically resolves the
// correct displacement based on the size of the instruction being generated.
@ -70,16 +40,16 @@ public:
__forceinline void operator()( const T* func ) const
{
if( isJmp )
iJccKnownTarget( Jcc_Unconditional, (void*)(uptr)func );
iJcc( Jcc_Unconditional, (void*)(uptr)func ); // double cast to/from (uptr) needed to appease GCC
else
{
// 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).
sptr dest = (sptr)func - ((sptr)iGetPtr() + 5);
xWrite<u8>( 0xe8 );
xWrite<u32>( dest );
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
xWrite8( 0xe8 );
xWrite32( dest );
}
}
};

View File

@ -32,7 +32,7 @@ class MovImpl
protected:
static const uint OperandSize = sizeof(ImmType);
static bool Is8BitOperand() { return OperandSize == 1; }
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); }
static void prefix16() { if( OperandSize == 2 ) xWrite8( 0x66 ); }
public:
MovImpl() {}
@ -43,8 +43,8 @@ public:
if( to == from ) return; // ignore redundant MOVs.
prefix16();
xWrite<u8>( Is8BitOperand() ? 0x88 : 0x89 );
ModRM_Direct( from.Id, to.Id );
xWrite8( Is8BitOperand() ? 0x88 : 0x89 );
EmitSibMagic( from, to );
}
// ------------------------------------------------------------------------
@ -57,12 +57,12 @@ public:
if( from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty() )
{
xWrite<u8>( Is8BitOperand() ? 0xa2 : 0xa3 );
xWrite<u32>( dest.Displacement );
xWrite8( Is8BitOperand() ? 0xa2 : 0xa3 );
xWrite32( dest.Displacement );
}
else
{
xWrite<u8>( Is8BitOperand() ? 0x88 : 0x89 );
xWrite8( Is8BitOperand() ? 0x88 : 0x89 );
EmitSibMagic( from.Id, dest );
}
}
@ -77,13 +77,13 @@ public:
if( to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty() )
{
xWrite<u8>( Is8BitOperand() ? 0xa0 : 0xa1 );
xWrite<u32>( src.Displacement );
xWrite8( Is8BitOperand() ? 0xa0 : 0xa1 );
xWrite32( src.Displacement );
}
else
{
xWrite<u8>( Is8BitOperand() ? 0x8a : 0x8b );
EmitSibMagic( to.Id, src );
xWrite8( Is8BitOperand() ? 0x8a : 0x8b );
EmitSibMagic( to, src );
}
}
@ -96,13 +96,13 @@ public:
if( from.IsAccumulator() )
{
xWrite<u8>( Is8BitOperand() ? 0xa2 : 0xa3 );
xWrite8( Is8BitOperand() ? 0xa2 : 0xa3 );
xWrite<s32>( (s32)dest );
}
else
{
xWrite<u8>( Is8BitOperand() ? 0x88 : 0x89 );
xWriteDisp( from.Id, dest );
xWrite8( Is8BitOperand() ? 0x88 : 0x89 );
EmitSibMagic( from, dest );
}
}
@ -115,13 +115,13 @@ public:
if( to.IsAccumulator() )
{
xWrite<u8>( Is8BitOperand() ? 0xa0 : 0xa1 );
xWrite8( Is8BitOperand() ? 0xa0 : 0xa1 );
xWrite<s32>( (s32)src );
}
else
{
xWrite<u8>( Is8BitOperand() ? 0x8a : 0x8b );
xWriteDisp( to.Id, src );
xWrite8( Is8BitOperand() ? 0x8a : 0x8b );
EmitSibMagic( to, src );
}
}
@ -131,7 +131,7 @@ public:
// Note: MOV does not have (reg16/32,imm8) forms.
prefix16();
xWrite<u8>( (Is8BitOperand() ? 0xb0 : 0xb8) | to.Id );
xWrite8( (Is8BitOperand() ? 0xb0 : 0xb8) | to.Id );
xWrite<ImmType>( imm );
}
@ -139,7 +139,7 @@ public:
static __emitinline void Emit( ModSibStrict<ImmType> dest, ImmType imm )
{
prefix16();
xWrite<u8>( Is8BitOperand() ? 0xc6 : 0xc7 );
xWrite8( Is8BitOperand() ? 0xc6 : 0xc7 );
EmitSibMagic( 0, dest );
xWrite<ImmType>( imm );
}
@ -178,6 +178,7 @@ public:
MovImplAll() {} // Satisfy GCC's whims.
};
#define ccSane() jASSUME( ccType >= 0 && ccType <= 0x0f )
//////////////////////////////////////////////////////////////////////////////////////////
// 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
// 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
// *only* 32 and 16 bit register operand forms (8 bit registers are not valid in CMOV).
//
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:
__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 void* src ) const { m_32::Emit( 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 xRegister32& from ) const { ccSane(); xOpWrite0F( 0x40 | ccType, to, from ); }
__forceinline void operator()( JccComparisonType ccType, const xRegister32& to, const void* src ) const { ccSane(); xOpWrite0F( 0x40 | ccType, to, src ); }
__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 void* src ) const { m_16::Emit( 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 xRegister16& from ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, from ); }
__forceinline void operator()( JccComparisonType ccType, const xRegister16& to, const void* src ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, src ); }
__forceinline void operator()( JccComparisonType ccType, const xRegister16& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x66, 0x40 | ccType, to, sibsrc ); }
CMovImplGeneric() {} // don't ask.
};
@ -273,18 +208,16 @@ public:
template< JccComparisonType ccType >
class CMovImplAll
{
protected:
typedef CMovSetImpl<u32, 0x40> m_32;
typedef CMovSetImpl<u16, 0x40> m_16;
static const u16 Opcode = 0x40 | ccType;
public:
__forceinline void operator()( const xRegister32& to, const xRegister32& from ) const { m_32::Emit( ccType, to, from ); }
__forceinline void operator()( const xRegister32& to, const void* src ) const { m_32::Emit( ccType, 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 xRegister32& from ) const { ccSane(); xOpWrite0F( Opcode, to, from ); }
__forceinline void operator()( const xRegister32& to, const void* src ) const { ccSane(); xOpWrite0F( Opcode, to, src ); }
__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 void* src ) const { m_16::Emit( ccType, 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 xRegister16& from ) const { ccSane(); xOpWrite0F( 0x66, Opcode, to, from ); }
__forceinline void operator()( const xRegister16& to, const void* src ) const { ccSane(); xOpWrite0F( 0x66, Opcode, to, src ); }
__forceinline void operator()( const xRegister16& to, const ModSibBase& sibsrc ) const { ccSane(); xOpWrite0F( 0x66, Opcode, to, sibsrc ); }
CMovImplAll() {} // don't ask.
};
@ -292,13 +225,11 @@ public:
// ------------------------------------------------------------------------
class SetImplGeneric
{
protected:
typedef CMovSetImpl<u8, 0x90> Impl; // 0x90 is the SETcc base instruction id
// note: SETcc are 0x90, with 0 in the Reg field of ModRM.
public:
__forceinline void operator()( JccComparisonType cc, const xRegister8& to ) const { Impl::EmitSet( cc, to ); }
__forceinline void operator()( JccComparisonType cc, void* dest ) const { Impl::EmitSet( cc, dest ); }
__noinline void operator()( JccComparisonType cc, const ModSibStrict<u8>& dest ) const { Impl::EmitSet( cc, dest ); }
__forceinline void operator()( JccComparisonType ccType, const xRegister8& to ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, to ); }
__forceinline void operator()( JccComparisonType ccType, void* dest ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, dest ); }
__noinline void operator()( JccComparisonType ccType, const ModSibStrict<u8>& dest ) const { ccSane(); xOpWrite0F( 0x90 | ccType, 0, dest ); }
SetImplGeneric() {} // if you do, ask GCC.
};
@ -307,13 +238,12 @@ public:
template< JccComparisonType ccType >
class SetImplAll
{
protected:
typedef CMovSetImpl<u8, 0x90> Impl; // 0x90 is the SETcc base instruction id
static const u16 Opcode = 0x90 | ccType; // SETcc are 0x90 base opcode, with 0 in the Reg field of ModRM.
public:
__forceinline void operator()( const xRegister8& to ) const { Impl::EmitSet( ccType, to ); }
__forceinline void operator()( void* dest ) const { Impl::EmitSet( ccType, dest ); }
__noinline void operator()( const ModSibStrict<u8>& dest ) const { Impl::EmitSet( ccType, dest ); }
__forceinline void operator()( const xRegister8& to ) const { ccSane(); xOpWrite0F( Opcode, 0, to ); }
__forceinline void operator()( void* dest ) const { ccSane(); xOpWrite0F( Opcode, 0, dest ); }
__noinline void operator()( const ModSibStrict<u8>& dest ) const { ccSane(); xOpWrite0F( Opcode, 0, dest ); }
SetImplAll() {} // if you do, ask GCC.
};
@ -330,12 +260,12 @@ protected:
static const uint SrcOperandSize = sizeof( SrcImmType );
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 )
{
prefix16();
xWrite<u8>( 0x0f );
xWrite<u8>( 0xb6 | (Is8BitOperand() ? 0 : 1) | (SignExtend ? 8 : 0 ) );
xWrite8( 0x0f );
xWrite8( 0xb6 | (Is8BitOperand() ? 0 : 1) | (SignExtend ? 8 : 0 ) );
}
public:
@ -344,13 +274,13 @@ public:
static __emitinline void Emit( const xRegister<DestImmType>& to, const xRegister<SrcImmType>& from, bool 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 )
{
emit_base( SignExtend );
EmitSibMagic( to.Id, sibsrc );
EmitSibMagic( to, sibsrc );
}
};

View File

@ -18,66 +18,93 @@
#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
template< typename ImmType >
class TestImpl
//
class xImpl_Test
{
protected:
static const uint OperandSize = sizeof(ImmType);
static bool Is8BitOperand() { return OperandSize == 1; }
static void prefix16() { if( OperandSize == 2 ) xWrite<u8>( 0x66 ); }
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();
xWrite<u8>( Is8BitOperand() ? 0x84 : 0x85 );
ModRM_Direct( from.Id, to.Id );
prefix16<T>();
xWrite8( Is8BitOp<T>() ? 0x84 : 0x85 );
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() )
xWrite<u8>( Is8BitOperand() ? 0xa8 : 0xa9 );
xWrite8( Is8BitOp<T>() ? 0xa8 : 0xa9 );
else
{
xWrite<u8>( Is8BitOperand() ? 0xf6 : 0xf7 );
ModRM_Direct( 0, to.Id );
xWrite8( Is8BitOp<T>() ? 0xf6 : 0xf7 );
EmitSibMagic( 0, to );
}
xWrite<ImmType>( imm );
xWrite<T>( imm );
}
// ------------------------------------------------------------------------
static __emitinline void Emit( ModSibStrict<ImmType> dest, ImmType imm )
{
prefix16();
xWrite<u8>( Is8BitOperand() ? 0xf6 : 0xf7 );
EmitSibMagic( 0, dest );
xWrite<ImmType>( imm );
}
xImpl_Test() {} // Why does GCC need these?
};
// -------------------------------------------------------------------
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:
template< typename T >
__forceinline void operator()( const xRegister<T>& to, const xRegister<T>& from ) const { TestImpl<T>::Emit( to, from ); }
xImpl_BitScan() {}
template< typename T >
__noinline void operator()( const ModSibStrict<T>& sibdest, T imm ) const { TestImpl<T>::Emit( sibdest, imm ); }
template< typename T >
void operator()( const xRegister<T>& to, T imm ) const { TestImpl<T>::Emit( to, imm ); }
TestImplAll() {} // Why does GCC need these?
__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 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
{
SimdPrefix( 0x66, OpcodeImm );
ModRM( 3, (int)Modcode, to.Id );
xWrite<u8>( imm8 );
EmitSibMagic( (int)Modcode, to );
xWrite8( imm8 );
}
__emitinline void operator()( const xRegisterMMX& to, u8 imm8 ) const
{
SimdPrefix( 0x00, OpcodeImm );
ModRM( 3, (int)Modcode, to.Id );
xWrite<u8>( imm8 );
EmitSibMagic( (int)Modcode, to );
xWrite8( imm8 );
}
};
@ -78,7 +78,7 @@ public:
{
SimdPrefix( 0x66, 0x73 );
ModRM( 3, (int)Modcode+1, to.Id );
xWrite<u8>( imm8 );
xWrite8( imm8 );
}
SimdImpl_Shift() {}

View File

@ -21,110 +21,6 @@
//////////////////////////////////////////////////////////////////////////////////////////
// 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,
// like ANDPS/ANDPD

View File

@ -41,9 +41,9 @@ class SimdImpl_Compare
protected:
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 void* 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 ); 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 ); xWrite8( CType ); }
__forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from ) const { xOpWrite0F( Prefix, 0xc2, to, from ); xWrite8( CType ); }
Woot() {}
};

View File

@ -122,17 +122,17 @@ public:
{
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
{
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
{
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
{
// 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 );
}
#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
{
// 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() );
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:
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 void* 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 ); 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 ); xWrite8( cmptype ); }
__forceinline void operator()( const xRegisterSSE& to, const ModSibBase& from, u8 cmptype ) const { xOpWrite0F( Prefix, OpcodeSSE, to, from ); xWrite8( cmptype ); }
Woot() {}
};

View File

@ -66,6 +66,26 @@ __threadlocal XMMSSEType g_xmmtypes[iREGCNT_XMM] = { XMMT_INT };
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 xAddressIndexer<u128> ptr128;
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 xRegisterSSE
@ -110,8 +130,11 @@ const xRegister8
const xRegisterCL cl;
//////////////////////////////////////////////////////////////////////////////////////////
namespace Internal
{
//////////////////////////////////////////////////////////////////////////////////////////
// Performance note: VC++ wants to use byte/word register form for the following
// ModRM/SibSB constructors when we use xWrite<u8>, and furthermore unrolls the
// the shift using a series of ADDs for the following results:
@ -135,32 +158,22 @@ namespace Internal
// (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)
__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 )
{
xWrite<u8>( (ss << 6) | (index << 3) | base );
}
__forceinline void xWriteDisp( int regfield, s32 displacement )
__forceinline void EmitSibMagic( uint regfield, const void* address )
{
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
// 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 )
{
SimdPrefix( prefix, opcode );
xWriteDisp( instId, data );
EmitSibMagic( instId, data );
}
__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
// 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 );
@ -235,7 +248,7 @@ namespace Internal
if( info.Index.IsEmpty() )
{
xWriteDisp( regfield, info.Displacement );
EmitSibMagic( regfield, (void*)info.Displacement );
return;
}
else
@ -284,7 +297,7 @@ namespace Internal
using namespace Internal;
const MovImplAll xMOV;
const TestImplAll xTEST;
const xImpl_Test xTEST;
const xImpl_G1Logic<G1Type_AND,0x54> xAND;
const xImpl_G1Logic<G1Type_OR,0x56> xOR;
@ -305,15 +318,15 @@ const Group2ImplAll<G2Type_SHL> xSHL;
const Group2ImplAll<G2Type_SHR> xSHR;
const Group2ImplAll<G2Type_SAR> xSAR;
const Group3ImplAll<G3Type_NOT> xNOT;
const Group3ImplAll<G3Type_NEG> xNEG;
const Group3ImplAll<G3Type_MUL> xUMUL;
const Group3ImplAll<G3Type_DIV> xUDIV;
const xImpl_Group3<G3Type_iDIV,0x5e> xDIV;
const xImpl_Group3<G3Type_NOT> xNOT;
const xImpl_Group3<G3Type_NEG> xNEG;
const xImpl_Group3<G3Type_MUL> xUMUL;
const xImpl_Group3<G3Type_DIV> xUDIV;
const xImpl_iDiv xDIV;
const xImpl_iMul xMUL;
const IncDecImplAll<false> xINC;
const IncDecImplAll<true> xDEC;
const xImpl_IncDec<false> xINC;
const xImpl_IncDec<true> xDEC;
const MovExtendImplAll<false> xMOVZX;
const MovExtendImplAll<true> xMOVSX;
@ -321,13 +334,13 @@ const MovExtendImplAll<true> xMOVSX;
const DwordShiftImplAll<false> xSHLD;
const DwordShiftImplAll<true> xSHRD;
const Group8Impl<G8Type_BT> xBT;
const Group8Impl<G8Type_BTR> xBTR;
const Group8Impl<G8Type_BTS> xBTS;
const Group8Impl<G8Type_BTC> xBTC;
const xImpl_Group8<G8Type_BT> xBT;
const xImpl_Group8<G8Type_BTR> xBTR;
const xImpl_Group8<G8Type_BTS> xBTS;
const xImpl_Group8<G8Type_BTC> xBTC;
const BitScanImpl<0xbc> xBSF;
const BitScanImpl<0xbd> xBSR;
const xImpl_BitScan<0xbc> xBSF;
const xImpl_BitScan<0xbd> xBSR;
// ------------------------------------------------------------------------
const CMovImplGeneric xCMOV;
@ -390,7 +403,7 @@ const SetImplAll<Jcc_ParityOdd> xSETPO;
// Assigns the current emitter buffer target address.
// This is provided instead of using x86Ptr directly, since we may in the future find
// a need to change the storage class system for the x86Ptr 'under the hood.'
__emitinline void iSetPtr( void* ptr )
__emitinline void xSetPtr( void* ptr )
{
x86Ptr = (u8*)ptr;
}
@ -399,26 +412,26 @@ __emitinline void iSetPtr( void* ptr )
// Retrieves the current emitter buffer target address.
// This is provided instead of using x86Ptr directly, since we may in the future find
// a need to change the storage class system for the x86Ptr 'under the hood.'
__emitinline u8* iGetPtr()
__emitinline u8* xGetPtr()
{
return x86Ptr;
}
// ------------------------------------------------------------------------
__emitinline void iAlignPtr( uint bytes )
__emitinline void xAlignPtr( uint bytes )
{
// forward align
x86Ptr = (u8*)( ( (uptr)x86Ptr + bytes - 1) & ~(bytes - 1) );
}
// ------------------------------------------------------------------------
__emitinline void iAdvancePtr( uint bytes )
__emitinline void xAdvancePtr( uint bytes )
{
if( IsDevBuild )
{
// common debugger courtesy: advance with INT3 as filler.
for( uint i=0; i<bytes; i++ )
xWrite<u8>( 0xcc );
xWrite8( 0xcc );
}
else
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
// register assignments above (via MOV)
xWrite<u8>( 0x8d );
xWrite8( 0x8d );
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 );
return;
}
xWrite<u8>( 0x8d );
xWrite8( 0x8d );
ModRM( 0, to.Id, ModRm_UseSib );
SibSB( src.Scale, src.Index.Id, ModRm_UseDisp32 );
xWrite<u32>( src.Displacement );
xWrite32( src.Displacement );
return;
}
else
@ -614,7 +627,7 @@ static void EmitLeaMagic( xRegister<OperandType> to, const ModSibBase& src, bool
if( src.Base == ebp && displacement_size == 0 )
displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]!
xWrite<u8>( 0x8d );
xWrite8( 0x8d );
ModRM( displacement_size, to.Id, ModRm_UseSib );
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 )
{
write8( 0x66 );
xWrite8( 0x66 );
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 )
{
xWrite<u8>( 0x8f );
xWrite8( 0x8f );
EmitSibMagic( 0, from );
}
__emitinline void xPUSH( const ModSibBase& from )
{
xWrite<u8>( 0xff );
xWrite8( 0xff );
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 )
{
write8( 0x0F );
write8( 0xC8 | to.Id );
xWrite8( 0x0F );
xWrite8( 0xC8 | to.Id );
}
}

View File

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

View File

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

View File

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

View File

@ -57,7 +57,7 @@ namespace x86Emitter
// flags.
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_ROR> xROR;
@ -70,15 +70,15 @@ namespace x86Emitter
// ------------------------------------------------------------------------
// Group 3 Instruction Class
extern const Internal::Group3ImplAll<Internal::G3Type_NOT> xNOT;
extern const Internal::Group3ImplAll<Internal::G3Type_NEG> xNEG;
extern const Internal::Group3ImplAll<Internal::G3Type_MUL> xUMUL;
extern const Internal::Group3ImplAll<Internal::G3Type_DIV> xUDIV;
extern const Internal::xImpl_Group3<Internal::G3Type_iDIV,0x5e> xDIV;
extern const Internal::xImpl_Group3<Internal::G3Type_NOT> xNOT;
extern const Internal::xImpl_Group3<Internal::G3Type_NEG> xNEG;
extern const Internal::xImpl_Group3<Internal::G3Type_MUL> xUMUL;
extern const Internal::xImpl_Group3<Internal::G3Type_DIV> xUDIV;
extern const Internal::xImpl_iDiv xDIV;
extern const Internal::xImpl_iMul xMUL;
extern const Internal::IncDecImplAll<false> xINC;
extern const Internal::IncDecImplAll<true> xDEC;
extern const Internal::xImpl_IncDec<false> xINC;
extern const Internal::xImpl_IncDec<true> xDEC;
extern const Internal::MovExtendImplAll<false> xMOVZX;
extern const Internal::MovExtendImplAll<true> xMOVSX;
@ -86,16 +86,16 @@ namespace x86Emitter
extern const Internal::DwordShiftImplAll<false> xSHLD;
extern const Internal::DwordShiftImplAll<true> xSHRD;
extern const Internal::Group8Impl<Internal::G8Type_BT> xBT;
extern const Internal::Group8Impl<Internal::G8Type_BTR> xBTR;
extern const Internal::Group8Impl<Internal::G8Type_BTS> xBTS;
extern const Internal::Group8Impl<Internal::G8Type_BTC> xBTC;
extern const Internal::xImpl_Group8<Internal::G8Type_BT> xBT;
extern const Internal::xImpl_Group8<Internal::G8Type_BTR> xBTR;
extern const Internal::xImpl_Group8<Internal::G8Type_BTS> xBTS;
extern const Internal::xImpl_Group8<Internal::G8Type_BTC> xBTC;
extern const Internal::JmpCallImplAll<true> xJMP;
extern const Internal::JmpCallImplAll<false> xCALL;
extern const Internal::xImpl_JmpCall<true> xJMP;
extern const Internal::xImpl_JmpCall<false> xCALL;
extern const Internal::BitScanImpl<0xbc> xBSF;
extern const Internal::BitScanImpl<0xbd> xBSR;
extern const Internal::xImpl_BitScan<0xbc> xBSF;
extern const Internal::xImpl_BitScan<0xbd> xBSR;
// ------------------------------------------------------------------------
extern const Internal::CMovImplGeneric xCMOV;
@ -175,41 +175,76 @@ namespace x86Emitter
extern void xPOP( const ModSibBase& from );
extern void xPUSH( const ModSibBase& from );
static __forceinline void xPOP( xRegister32 from ) { write8( 0x58 | from.Id ); }
static __forceinline void xPOP( void* from ) { xPOP( ptr[from] ); }
extern void xPOP( xRegister32 from );
extern void xPOP( void* from );
static __forceinline void xPUSH( u32 imm ) { write8( 0x68 ); write32( imm ); }
static __forceinline void xPUSH( xRegister32 from ) { write8( 0x50 | from.Id ); }
static __forceinline void xPUSH( void* from ) { xPUSH( ptr[from] ); }
extern void xPUSH( u32 imm );
extern void xPUSH( xRegister32 from );
extern void xPUSH( void* from );
// pushes the EFLAGS register onto the stack
static __forceinline void xPUSHFD() { write8( 0x9C ); }
extern void xPUSHFD();
// pops the EFLAGS register from the stack
static __forceinline void xPOPFD() { write8( 0x9D ); }
extern void xPOPFD();
// ----- Miscellaneous Instructions -----
// Various Instructions with no parameter and no special encoding logic.
__forceinline void xRET() { write8( 0xC3 ); }
__forceinline void xCBW() { write16( 0x9866 ); }
__forceinline void xCWD() { write8( 0x98 ); }
__forceinline void xCDQ() { write8( 0x99 ); }
__forceinline void xCWDE() { write8( 0x98 ); }
extern void xRET();
extern void xCBW();
extern void xCWD();
extern void xCDQ();
extern void xCWDE();
__forceinline void xLAHF() { write8( 0x9f ); }
__forceinline void xSAHF() { write8( 0x9e ); }
extern void xLAHF();
extern void xSAHF();
__forceinline void xSTC() { write8( 0xF9 ); }
__forceinline void xCLC() { write8( 0xF8 ); }
extern void xSTC();
extern void xCLC();
// NOP 1-byte
__forceinline void xNOP() { write8(0x90); }
extern void xNOP();
//////////////////////////////////////////////////////////////////////////////////////////
// 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 ) \
template< typename OperandType > \
class xForward##label : public xForwardJump<OperandType> \

View File

@ -40,30 +40,30 @@ namespace x86Emitter {
using namespace Internal;
const JmpCallImplAll<true> xJMP;
const JmpCallImplAll<false> xCALL;
const xImpl_JmpCall<true> xJMP;
const xImpl_JmpCall<false> xCALL;
// ------------------------------------------------------------------------
void xSmartJump::SetTarget()
{
u8* target = iGetPtr();
u8* target = xGetPtr();
if( m_baseptr == NULL ) return;
iSetPtr( m_baseptr );
xSetPtr( m_baseptr );
u8* const saveme = m_baseptr + GetMaxInstructionSize();
iJccKnownTarget( m_cc, target, true );
// Copy recompiled data inward if the jump instruction didn't fill the
// 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 )
{
u8* destpos = iGetPtr();
u8* destpos = xGetPtr();
const int copylen = (sptr)target - (sptr)saveme;
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
// to slide forward in the event of an 8 bit displacement.
//
// Using this
__emitinline void iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward )
__emitinline void Internal::iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward )
{
// 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;
displacement8 -= slideVal;
@ -96,7 +95,7 @@ __emitinline void iJccKnownTarget( JccComparisonType comparison, void* target, b
if( is_s8( displacement8 ) )
{
xWrite<u8>( (comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison) );
xWrite8( (comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison) );
xWrite<s8>( displacement8 );
}
else
@ -104,14 +103,21 @@ __emitinline void iJccKnownTarget( JccComparisonType comparison, void* target, b
// Perform a 32 bit jump instead. :(
if( comparison == Jcc_Unconditional )
xWrite<u8>( 0xe9 );
xWrite8( 0xe9 );
else
{
xWrite<u8>( 0x0f );
xWrite<u8>( 0x80 | comparison );
xWrite8( 0x0f );
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 "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;
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 )
{
write8( cc );
write8( to );
xWrite8( cc );
xWrite8( to );
return (u8*)(x86Ptr - 1);
}
emitterT u16* J16Rel( int cc, u32 to )
{
write16( 0x0F66 );
write8( cc );
write16( to );
xWrite16( 0x0F66 );
xWrite8( cc );
xWrite16( to );
return (u16*)( x86Ptr - 2 );
}
emitterT u32* J32Rel( int cc, u32 to )
{
write8( 0x0F );
write8( cc );
write32( to );
xWrite8( 0x0F );
xWrite8( cc );
xWrite32( to );
return (u32*)( x86Ptr - 4 );
}
@ -448,8 +435,8 @@ emitterT void NOP( void ) { xNOP(); }
/* jmp rel8 */
emitterT u8* JMP8( u8 to )
{
write8( 0xEB );
write8( to );
xWrite8( 0xEB );
xWrite8( to );
return x86Ptr - 1;
}
@ -457,8 +444,8 @@ emitterT u8* JMP8( u8 to )
emitterT u32* JMP32( uptr to )
{
assert( (sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff );
write8( 0xE9 );
write32( to );
xWrite8( 0xE9 );
xWrite32( to );
return (u32*)(x86Ptr - 4 );
}

View File

@ -18,17 +18,6 @@
#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
//------------------------------------------------------------------

View File

@ -24,6 +24,13 @@
// 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_instructions.h"
@ -37,7 +44,6 @@
#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 SibSB( uint ss, uint index, uint base );
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 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);
// 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!
if( !is16BitOpcode ) jASSUME( (opcode >> 8) == 0 );
if( prefix != 0 )
{
if( is16BitOpcode )
xWrite<u32>( (opcode<<16) | 0x0f00 | prefix );
xWrite32( (opcode<<16) | 0x0f00 | prefix );
else
{
xWrite<u16>( 0x0f00 | prefix );
xWrite<u8>( opcode );
xWrite16( 0x0f00 | prefix );
xWrite8( opcode );
}
}
else
{
if( is16BitOpcode )
{
xWrite<u8>( 0x0f );
xWrite<u16>( opcode );
xWrite8( 0x0f );
xWrite16( opcode );
}
else
xWrite<u16>( (opcode<<8) | 0x0f );
xWrite16( (opcode<<8) | 0x0f );
}
}
@ -199,23 +199,31 @@ const SimdImpl_PMove<false> xPMOVZX;
//////////////////////////////////////////////////////////////////////////////////////////
//
__emitinline void xEMMS()
{
xWrite<u16>( 0x770F );
}
// 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,
// 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.
__emitinline void xSTMXCSR( u32* dest )
{
SimdPrefix( 0, 0xae );
xWriteDisp( 3, dest );
EmitSibMagic( 3, dest );
}
// Load Streaming SIMD Extension Control/Status from Mem32.
__emitinline void xLDMXCSR( const u32* src )
{
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();
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 )
{
xWrite<u32>( 0x2A380f66 );
xWriteDisp( to.Id, from );
xWrite32( 0x2A380f66 );
EmitSibMagic( to.Id, from );
}
__forceinline void xMOVNTDQA( const xRegisterSSE& to, const ModSibBase& from )
{
xWrite<u32>( 0x2A380f66 );
xWrite32( 0x2A380f66 );
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
//cpu capabilities structure
struct CAPABILITIES {
struct CAPABILITIES
{
u32 hasFloatingPointUnit;
u32 hasVirtual8086ModeEnhancements;
u32 hasDebuggingExtensions;
@ -63,8 +64,8 @@ struct CAPABILITIES {
extern CAPABILITIES cpucaps;
struct CPUINFO{
struct CPUINFO
{
u32 x86Family; // Processor Family
u32 x86Model; // Processor Model
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];
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.
template< typename T >
static __forceinline bool is_s8( T imm ) { return (s8)imm == (s32)imm; }
template< typename T >
static __forceinline void xWrite( T val )
__forceinline void xWrite( T val )
{
*(T*)x86Ptr = val;
x86Ptr += sizeof(T);
}
namespace x86Emitter
{
//////////////////////////////////////////////////////////////////////////////////////////
// ALWAYS_USE_MOVAPS [define] / AlwaysUseMovaps [const]
@ -178,54 +185,27 @@ namespace x86Emitter
class xAddressInfo;
class ModSibBase;
extern void iSetPtr( void* ptr );
extern u8* iGetPtr();
extern void iAlignPtr( uint bytes );
extern void iAdvancePtr( 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 );
}
extern void xSetPtr( void* ptr );
extern u8* xGetPtr();
extern void xAlignPtr( uint bytes );
extern void xAdvancePtr( uint bytes );
//////////////////////////////////////////////////////////////////////////////////////////
// xRegister
// xRegisterBase
// Unless templating some fancy stuff, use the friendly xRegister32/16/8 typedefs instead.
//
template< typename OperandType >
class xRegister
class xRegisterBase
{
public:
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;
xRegister( const xRegister<OperandType>& src ) : Id( src.Id ) {}
xRegister(): Id( -1 ) {}
explicit xRegister( int regId ) : Id( regId ) { jASSUME( Id >= -1 && Id < 8 ); }
xRegisterBase( const xRegisterBase<OperandType>& src ) : Id( src.Id ) {}
xRegisterBase(): Id( -1 ) {}
explicit xRegisterBase( int regId ) : Id( regId ) { jASSUME( Id >= -1 && Id < 8 ); }
bool IsEmpty() const { return Id < 0; }
@ -235,19 +215,60 @@ namespace x86Emitter
// returns true if the register is a valid MMX or XMM register.
bool IsSIMD() const { return OperandSize == 8 || OperandSize == 16; }
bool operator==( const xRegister<OperandType>& src ) const
{
return (Id == src.Id);
}
bool operator==( const xRegisterBase<OperandType>& src ) const { return (Id == src.Id); }
bool operator!=( const xRegisterBase<OperandType>& src ) const { 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 )
{
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;
}
};
@ -260,8 +281,8 @@ namespace x86Emitter
// all about the the templated code in haphazard fashion. Yay.. >_<
//
typedef xRegister<u128> xRegisterSSE;
typedef xRegister<u64> xRegisterMMX;
typedef xRegisterSIMD<u128> xRegisterSSE;
typedef xRegisterSIMD<u64> xRegisterMMX;
typedef xRegister<u32> xRegister32;
typedef xRegister<u16> xRegister16;
typedef xRegister<u8> xRegister8;
@ -624,9 +645,9 @@ namespace x86Emitter
xSmartJump( JccComparisonType ccType )
{
jASSUME( ccType != Jcc_Unknown );
m_baseptr = iGetPtr();
m_baseptr = xGetPtr();
m_cc = ccType;
iAdvancePtr( GetMaxInstructionSize() );
xAdvancePtr( GetMaxInstructionSize() );
}
protected:
@ -662,18 +683,69 @@ namespace x86Emitter
//
namespace Internal
{
extern void ModRM( uint mod, uint reg, uint rm );
extern void ModRM_Direct( uint reg, uint rm );
extern void SibSB( u32 ss, u32 index, u32 base );
extern void xWriteDisp( int regfield, s32 displacement );
extern void xWriteDisp( int regfield, const void* address );
extern void SimdPrefix( u8 prefix, u16 opcode );
extern void EmitSibMagic( uint regfield, const void* address );
extern void EmitSibMagic( uint regfield, const ModSibBase& info );
extern void 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 > 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/moremovs.h"
@ -686,7 +758,6 @@ namespace x86Emitter
#include "implement/movs.h" // cmov and movsx/zx
#include "implement/dwshift.h" // doubleword shifts!
#include "implement/incdec.h"
#include "implement/bittest.h"
#include "implement/test.h"
#include "implement/jmpcall.h"
}