mirror of https://github.com/PCSX2/pcsx2.git
Emitter: Fixed a small bug in the ModSib emitter logic which caused some forms of ESP to encode incorrectly. Implemented CALL/BSF/BSR [x86], MOVQ, MOVD, and MOVSS [mmx/xmm]. Renamed ix86_mmx.cpp and i86_sse.cpp to ix86_legacy_mmx.cpp and i8x_legacy_sse.cpp.
iMMI.cpp: Removed mucho dead pre-SSE2 code. (old code can be grabbed from a tagged revision, in case it's useful for future reference). git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1011 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
924869f765
commit
6f99ec45b9
|
@ -86,6 +86,7 @@ typedef unsigned int uint;
|
||||||
|
|
||||||
#define __naked __declspec(naked)
|
#define __naked __declspec(naked)
|
||||||
#define __unused /*unused*/
|
#define __unused /*unused*/
|
||||||
|
#define __noinline __declspec(noinline)
|
||||||
#define CALLBACK __stdcall
|
#define CALLBACK __stdcall
|
||||||
|
|
||||||
#else // _MSC_VER
|
#else // _MSC_VER
|
||||||
|
@ -134,6 +135,7 @@ typedef union _LARGE_INTEGER
|
||||||
#define __unused __attribute__((unused))
|
#define __unused __attribute__((unused))
|
||||||
#define _inline __inline__ __attribute__((unused))
|
#define _inline __inline__ __attribute__((unused))
|
||||||
#define __forceinline __attribute__((always_inline,unused))
|
#define __forceinline __attribute__((always_inline,unused))
|
||||||
|
#define __noinline __attribute__((noinline))
|
||||||
#define __naked // GCC lacks the naked specifier
|
#define __naked // GCC lacks the naked specifier
|
||||||
#define CALLBACK // CALLBACK is win32-specific mess
|
#define CALLBACK // CALLBACK is win32-specific mess
|
||||||
|
|
||||||
|
|
|
@ -2953,18 +2953,18 @@
|
||||||
RelativePath="..\..\x86\ix86\ix86_legacy_internal.h"
|
RelativePath="..\..\x86\ix86\ix86_legacy_internal.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\x86\ix86\ix86_legacy_mmx.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\x86\ix86\ix86_legacy_sse.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\x86\ix86\ix86_legacy_types.h"
|
RelativePath="..\..\x86\ix86\ix86_legacy_types.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\x86\ix86\ix86_mmx.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\x86\ix86\ix86_sse.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\x86\ix86\ix86_sse_helpers.h"
|
RelativePath="..\..\x86\ix86\ix86_sse_helpers.h"
|
||||||
>
|
>
|
||||||
|
@ -3004,6 +3004,10 @@
|
||||||
RelativePath="..\..\x86\ix86\implement\incdec.h"
|
RelativePath="..\..\x86\ix86\implement\incdec.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\x86\ix86\implement\jmpcall.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\x86\ix86\implement\movs.h"
|
RelativePath="..\..\x86\ix86\implement\movs.h"
|
||||||
>
|
>
|
||||||
|
@ -3012,12 +3016,16 @@
|
||||||
RelativePath="..\..\x86\ix86\implement\test.h"
|
RelativePath="..\..\x86\ix86\implement\test.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<Filter
|
||||||
|
Name="xmm"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\x86\ix86\implement\xmm\movqss.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<File
|
|
||||||
RelativePath=".\ClassDiagram1.cd"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Common.h"
|
RelativePath="..\..\Common.h"
|
||||||
>
|
>
|
||||||
|
|
1540
pcsx2/x86/iMMI.cpp
1540
pcsx2/x86/iMMI.cpp
File diff suppressed because it is too large
Load Diff
|
@ -249,19 +249,6 @@ void eeRecompileCodeConstSPECIAL(R5900FNPTR constcode, R5900FNPTR_INFO multicode
|
||||||
#define XMMINFO_READACC 0x200
|
#define XMMINFO_READACC 0x200
|
||||||
#define XMMINFO_WRITEACC 0x400
|
#define XMMINFO_WRITEACC 0x400
|
||||||
|
|
||||||
#define CPU_SSE_XMMCACHE_START(xmminfo) \
|
|
||||||
{ \
|
|
||||||
int info = eeRecompileCodeXMM(xmminfo); \
|
|
||||||
|
|
||||||
#define CPU_SSE2_XMMCACHE_START(xmminfo) \
|
|
||||||
{ \
|
|
||||||
int info = eeRecompileCodeXMM(xmminfo); \
|
|
||||||
|
|
||||||
#define CPU_SSE_XMMCACHE_END \
|
|
||||||
_clearNeededXMMregs(); \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
|
|
||||||
#define FPURECOMPILE_CONSTCODE(fn, xmminfo) \
|
#define FPURECOMPILE_CONSTCODE(fn, xmminfo) \
|
||||||
void rec##fn(void) \
|
void rec##fn(void) \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
@ -2,7 +2,7 @@ INCLUDES = -I@srcdir@/.. -I@srcdir@/../../ -I@srcdir@/../../../common/include
|
||||||
noinst_LIBRARIES = libix86.a
|
noinst_LIBRARIES = libix86.a
|
||||||
|
|
||||||
libix86_a_SOURCES = \
|
libix86_a_SOURCES = \
|
||||||
ix86.cpp ix86_cpudetect.cpp ix86_fpu.cpp ix86_jmp.cpp ix86_mmx.cpp ix86_tools.cpp ix86_3dnow.cpp \
|
ix86.cpp ix86_cpudetect.cpp ix86_fpu.cpp ix86_jmp.cpp ix86_legacy_mmx.cpp ix86_tools.cpp ix86_3dnow.cpp \
|
||||||
ix86_legacy.cpp ix86_sse.cpp \
|
ix86_legacy.cpp ix86_legacy_sse.cpp \
|
||||||
ix86_internal.h ix86_legacy_instructions.h ix86_macros.h ix86_sse_helpers.h ix86.h ix86_legacy_internal.h \
|
ix86_internal.h ix86_legacy_instructions.h ix86_macros.h ix86_sse_helpers.h ix86.h ix86_legacy_internal.h \
|
||||||
ix86_instructions.h ix86_legacy_types.h ix86_types.h
|
ix86_instructions.h ix86_legacy_types.h ix86_types.h
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Implementations found here: BTS/BT/BTC/BTR!
|
// Implementations found here: BTS/BT/BTC/BTR plus BSF/BSR!
|
||||||
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
||||||
|
|
||||||
// These instructions are in the 'Group8' as per Intel's manual, but since they all have
|
// These instructions are in the 'Group8' as per Intel's manual, but since they all have
|
||||||
|
@ -46,6 +46,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
Group8Impl() {} // For the love of GCC.
|
Group8Impl() {} // For the love of GCC.
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const iRegister<ImmType>& bitbase, const iRegister<ImmType>& bitoffset )
|
static __emitinline void Emit( const iRegister<ImmType>& bitbase, const iRegister<ImmType>& bitoffset )
|
||||||
{
|
{
|
||||||
prefix16();
|
prefix16();
|
||||||
|
@ -54,6 +55,7 @@ public:
|
||||||
ModRM_Direct( bitoffset.Id, bitbase.Id );
|
ModRM_Direct( bitoffset.Id, bitbase.Id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( void* bitbase, const iRegister<ImmType>& bitoffset )
|
static __emitinline void Emit( void* bitbase, const iRegister<ImmType>& bitoffset )
|
||||||
{
|
{
|
||||||
prefix16();
|
prefix16();
|
||||||
|
@ -62,6 +64,7 @@ public:
|
||||||
iWriteDisp( bitoffset.Id, bitbase.Id );
|
iWriteDisp( bitoffset.Id, bitbase.Id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const ModSibBase& bitbase, const iRegister<ImmType>& bitoffset )
|
static __emitinline void Emit( const ModSibBase& bitbase, const iRegister<ImmType>& bitoffset )
|
||||||
{
|
{
|
||||||
prefix16();
|
prefix16();
|
||||||
|
@ -70,6 +73,7 @@ public:
|
||||||
EmitSibMagic( bitoffset.Id, bitbase );
|
EmitSibMagic( bitoffset.Id, bitbase );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const iRegister<ImmType>& bitbase, u8 immoffset )
|
static __emitinline void Emit( const iRegister<ImmType>& bitbase, u8 immoffset )
|
||||||
{
|
{
|
||||||
prefix16();
|
prefix16();
|
||||||
|
@ -78,6 +82,7 @@ public:
|
||||||
iWrite<u8>( immoffset );
|
iWrite<u8>( immoffset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const ModSibStrict<ImmType>& bitbase, u8 immoffset )
|
static __emitinline void Emit( const ModSibStrict<ImmType>& bitbase, u8 immoffset )
|
||||||
{
|
{
|
||||||
prefix16();
|
prefix16();
|
||||||
|
@ -115,3 +120,68 @@ public:
|
||||||
|
|
||||||
Group8ImplAll() {}
|
Group8ImplAll() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// BSF / BSR -- 16/32 operands supported only.
|
||||||
|
//
|
||||||
|
template< bool isReverse, typename ImmType >
|
||||||
|
class BitScanImpl
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static const uint OperandSize = sizeof(ImmType);
|
||||||
|
static void prefix16() { if( OperandSize == 2 ) iWrite<u8>( 0x66 ); }
|
||||||
|
static void emitbase()
|
||||||
|
{
|
||||||
|
prefix16();
|
||||||
|
iWrite<u8>( 0x0f );
|
||||||
|
iWrite<u8>( isReverse ? 0xbd : 0xbc );
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
BitScanImpl() {} // For the love of GCC.
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
static __emitinline void Emit( const iRegister<ImmType>& to, const iRegister<ImmType>& from )
|
||||||
|
{
|
||||||
|
emitbase();
|
||||||
|
ModRM_Direct( to.Id, from.Id );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
static __emitinline void Emit( const iRegister<ImmType>& to, const void* src )
|
||||||
|
{
|
||||||
|
emitbase();
|
||||||
|
iWriteDisp( to.Id, src );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
static __emitinline void Emit( const iRegister<ImmType>& to, const ModSibBase& sibsrc )
|
||||||
|
{
|
||||||
|
emitbase();
|
||||||
|
EmitSibMagic( to.Id, sibsrc );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// BSF/BSR -- 16 and 32 bit operand forms only!
|
||||||
|
//
|
||||||
|
template< bool isReverse >
|
||||||
|
class BitScanImplAll
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
typedef BitScanImpl<isReverse,u32> m_32;
|
||||||
|
typedef BitScanImpl<isReverse,u32> m_16;
|
||||||
|
|
||||||
|
public:
|
||||||
|
__forceinline void operator()( const iRegister32& to, const iRegister32& from ) const { m_32::Emit( to, from ); }
|
||||||
|
__forceinline void operator()( const iRegister16& to, const iRegister16& from ) const { m_16::Emit( to, from ); }
|
||||||
|
__forceinline void operator()( const iRegister32& to, const void* src ) const { m_32::Emit( to, src ); }
|
||||||
|
__forceinline void operator()( const iRegister16& to, const void* src ) const { m_16::Emit( to, src ); }
|
||||||
|
__noinline void operator()( const iRegister32& to, const ModSibBase& sibsrc ) const { m_32::Emit( to, sibsrc ); }
|
||||||
|
__noinline void operator()( const iRegister16& to, const ModSibBase& sibsrc ) const { m_16::Emit( to, sibsrc ); }
|
||||||
|
|
||||||
|
BitScanImplAll() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
DwordShiftImpl() {} // because GCC doesn't like static classes
|
DwordShiftImpl() {} // because GCC doesn't like static classes
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const iRegister<ImmType>& to, const iRegister<ImmType>& from )
|
static __emitinline void Emit( const iRegister<ImmType>& to, const iRegister<ImmType>& from )
|
||||||
{
|
{
|
||||||
prefix16();
|
prefix16();
|
||||||
|
@ -52,6 +53,7 @@ public:
|
||||||
ModRM_Direct( from.Id, to.Id );
|
ModRM_Direct( from.Id, to.Id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const iRegister<ImmType>& to, const iRegister<ImmType>& from, u8 imm )
|
static __emitinline void Emit( const iRegister<ImmType>& to, const iRegister<ImmType>& from, u8 imm )
|
||||||
{
|
{
|
||||||
if( imm == 0 ) return;
|
if( imm == 0 ) return;
|
||||||
|
@ -61,12 +63,14 @@ public:
|
||||||
write8( imm );
|
write8( imm );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const ModSibBase& sibdest, const iRegister<ImmType>& from, __unused const iRegisterCL& clreg )
|
static __emitinline void Emit( const ModSibBase& sibdest, const iRegister<ImmType>& from, __unused const iRegisterCL& clreg )
|
||||||
{
|
{
|
||||||
basesibform();
|
basesibform();
|
||||||
EmitSibMagic( from.Id, sibdest );
|
EmitSibMagic( from.Id, sibdest );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const ModSibBase& sibdest, const iRegister<ImmType>& from, u8 imm )
|
static __emitinline void Emit( const ModSibBase& sibdest, const iRegister<ImmType>& from, u8 imm )
|
||||||
{
|
{
|
||||||
basesibform();
|
basesibform();
|
||||||
|
@ -74,6 +78,7 @@ public:
|
||||||
write8( imm );
|
write8( imm );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
// dest data type is inferred from the 'from' register, so we can do void* resolution :)
|
// dest data type is inferred from the 'from' register, so we can do void* resolution :)
|
||||||
static __emitinline void Emit( void* dest, const iRegister<ImmType>& from, __unused const iRegisterCL& clreg )
|
static __emitinline void Emit( void* dest, const iRegister<ImmType>& from, __unused const iRegisterCL& clreg )
|
||||||
{
|
{
|
||||||
|
@ -81,6 +86,7 @@ public:
|
||||||
iWriteDisp( from.Id, dest );
|
iWriteDisp( from.Id, dest );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
// dest data type is inferred from the 'from' register, so we can do void* resolution :)
|
// dest data type is inferred from the 'from' register, so we can do void* resolution :)
|
||||||
static __emitinline void Emit( void* dest, const iRegister<ImmType>& from, u8 imm )
|
static __emitinline void Emit( void* dest, const iRegister<ImmType>& from, u8 imm )
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,6 +50,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
Group2Impl() {} // For the love of GCC.
|
Group2Impl() {} // For the love of GCC.
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const iRegister<ImmType>& to )
|
static __emitinline void Emit( const iRegister<ImmType>& to )
|
||||||
{
|
{
|
||||||
prefix16();
|
prefix16();
|
||||||
|
@ -57,6 +58,7 @@ public:
|
||||||
ModRM_Direct( InstType, to.Id );
|
ModRM_Direct( InstType, to.Id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const iRegister<ImmType>& to, u8 imm )
|
static __emitinline void Emit( const iRegister<ImmType>& to, u8 imm )
|
||||||
{
|
{
|
||||||
if( imm == 0 ) return;
|
if( imm == 0 ) return;
|
||||||
|
@ -76,6 +78,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const ModSibStrict<ImmType>& sibdest )
|
static __emitinline void Emit( const ModSibStrict<ImmType>& sibdest )
|
||||||
{
|
{
|
||||||
prefix16();
|
prefix16();
|
||||||
|
@ -83,6 +86,7 @@ public:
|
||||||
EmitSibMagic( InstType, sibdest );
|
EmitSibMagic( InstType, sibdest );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
static __emitinline void Emit( const ModSibStrict<ImmType>& sibdest, u8 imm )
|
static __emitinline void Emit( const ModSibStrict<ImmType>& sibdest, u8 imm )
|
||||||
{
|
{
|
||||||
if( imm == 0 ) return;
|
if( imm == 0 ) return;
|
||||||
|
@ -108,17 +112,7 @@ public:
|
||||||
template< G2Type InstType >
|
template< G2Type InstType >
|
||||||
class Group2ImplAll
|
class Group2ImplAll
|
||||||
{
|
{
|
||||||
// Inlining Notes:
|
|
||||||
// I've set up the inlining to be as practical and intelligent as possible, which means
|
|
||||||
// forcing inlining for (void*) forms of ModRM, which thanks to constprop reduce to
|
|
||||||
// virtually no code. In the case of (Reg, Imm) forms, the inlining is up to the dis-
|
|
||||||
// creation of the compiler.
|
|
||||||
//
|
|
||||||
|
|
||||||
// (Note: I'm not going to macro this since it would likely clobber intellisense parameter resolution)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// ---------- 32 Bit Interface -----------
|
|
||||||
template< typename T > __forceinline void operator()( const iRegister<T>& to, __unused const iRegisterCL& from ) const
|
template< typename T > __forceinline void operator()( const iRegister<T>& to, __unused const iRegisterCL& from ) const
|
||||||
{ Group2Impl<InstType,T>::Emit( to ); }
|
{ Group2Impl<InstType,T>::Emit( to ); }
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,9 @@ public:
|
||||||
|
|
||||||
static __emitinline void Emit( bool isDec, const ModSibStrict<ImmType>& dest )
|
static __emitinline void Emit( bool isDec, const ModSibStrict<ImmType>& dest )
|
||||||
{
|
{
|
||||||
|
prefix16();
|
||||||
write8( Is8BitOperand() ? 0xfe : 0xff );
|
write8( Is8BitOperand() ? 0xfe : 0xff );
|
||||||
EmitSibMagic( isDec ? 1: 0, dest );
|
EmitSibMagic( isDec ? 1 : 0, dest );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,10 +68,10 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
__forceinline void operator()( const iRegister32& to ) const { m_32::Emit( isDec, to ); }
|
__forceinline void operator()( const iRegister32& to ) const { m_32::Emit( isDec, to ); }
|
||||||
__noinline void operator()( const ModSibStrict<u32>& sibdest ) const { m_32::Emit( isDec, sibdest ); }
|
__noinline void operator()( const ModSibStrict<u32>& sibdest ) const{ m_32::Emit( isDec, sibdest ); }
|
||||||
|
|
||||||
__forceinline void operator()( const iRegister16& to ) const { m_16::Emit( isDec, to ); }
|
__forceinline void operator()( const iRegister16& to ) const { m_16::Emit( isDec, to ); }
|
||||||
__noinline void operator()( const ModSibStrict<u16>& sibdest ) const { m_16::Emit( isDec, sibdest ); }
|
__noinline void operator()( const ModSibStrict<u16>& sibdest ) const{ m_16::Emit( isDec, sibdest ); }
|
||||||
|
|
||||||
__forceinline void operator()( const iRegister8& to ) const { m_8::Emit( isDec, to ); }
|
__forceinline void operator()( const iRegister8& to ) const { m_8::Emit( isDec, to ); }
|
||||||
__noinline void operator()( const ModSibStrict<u8>& sibdest ) const { m_8::Emit( isDec, sibdest ); }
|
__noinline void operator()( const ModSibStrict<u8>& sibdest ) const { m_8::Emit( isDec, sibdest ); }
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* 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: 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 ) iWrite<u8>( 0x66 ); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
JmpCallImpl() {} // For the love of GCC.
|
||||||
|
|
||||||
|
static __emitinline void Emit( bool isJmp, const iRegister<ImmType>& absreg )
|
||||||
|
{
|
||||||
|
prefix16();
|
||||||
|
iWrite<u8>( 0xff );
|
||||||
|
ModRM_Direct( isJmp ? 4 : 2, absreg.Id );
|
||||||
|
}
|
||||||
|
|
||||||
|
static __emitinline void Emit( bool isJmp, const ModSibStrict<ImmType>& src )
|
||||||
|
{
|
||||||
|
prefix16();
|
||||||
|
iWrite<u8>( 0xff );
|
||||||
|
EmitSibMagic( isJmp ? 4 : 2, src );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
template< bool isJmp >
|
||||||
|
class JmpCallImplAll
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
typedef JmpCallImpl<u32> m_32;
|
||||||
|
typedef JmpCallImpl<u16> m_16;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JmpCallImplAll() {}
|
||||||
|
|
||||||
|
__forceinline void operator()( const iRegister32& absreg ) const { m_32::Emit( isJmp, absreg ); }
|
||||||
|
__forceinline void operator()( const ModSibStrict<u32>& src ) const { m_32::Emit( isJmp, src ); }
|
||||||
|
|
||||||
|
__forceinline void operator()( const iRegister16& absreg ) const { m_16::Emit( isJmp, absreg ); }
|
||||||
|
__forceinline void operator()( const ModSibStrict<u16>& src ) const { m_16::Emit( isJmp, src ); }
|
||||||
|
|
||||||
|
// Special form for calling functions. This form automatically resolves the
|
||||||
|
// correct displacement based on the size of the instruction being generated.
|
||||||
|
template< typename T >
|
||||||
|
__forceinline void operator()( const T* func ) const
|
||||||
|
{
|
||||||
|
if( isJmp )
|
||||||
|
iJccKnownTarget( Jcc_Unconditional, (void*)func );
|
||||||
|
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);
|
||||||
|
iWrite<u8>( 0xe8 );
|
||||||
|
iWrite<u32>( dest );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -18,7 +18,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Header: ix86_impl_movs.h -- covers cmov and movsx/movzx.
|
// Header: ix86_impl_movs.h -- covers mov, cmov, movsx/movzx, and SETcc (which shares
|
||||||
|
// with cmov many similarities).
|
||||||
|
|
||||||
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
// Note: This header is meant to be included from within the x86Emitter::Internal namespace.
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -143,28 +145,22 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inlining Notes:
|
// ------------------------------------------------------------------------
|
||||||
// I've set up the inlining to be as practical and intelligent as possible, which means
|
|
||||||
// forcing inlining for (void*) forms of ModRM, which thanks to constprop reduce to
|
|
||||||
// virtually no code. In the case of (Reg, Imm) forms, the inlining is up to the dis-
|
|
||||||
// cretion of the compiler.
|
|
||||||
//
|
|
||||||
|
|
||||||
class MovImplAll
|
class MovImplAll
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template< typename T>
|
template< typename T >
|
||||||
__forceinline void operator()( const iRegister<T>& to, const iRegister<T>& from ) const { MovImpl<T>::Emit( to, from ); }
|
__forceinline void operator()( const iRegister<T>& to, const iRegister<T>& from ) const { MovImpl<T>::Emit( to, from ); }
|
||||||
template< typename T>
|
template< typename T >
|
||||||
__forceinline void operator()( const iRegister<T>& to, const void* src ) const { MovImpl<T>::Emit( to, src ); }
|
__forceinline void operator()( const iRegister<T>& to, const void* src ) const { MovImpl<T>::Emit( to, src ); }
|
||||||
template< typename T>
|
template< typename T >
|
||||||
__forceinline void operator()( void* dest, const iRegister<T>& from ) const { MovImpl<T>::Emit( dest, from ); }
|
__forceinline void operator()( void* dest, const iRegister<T>& from ) const { MovImpl<T>::Emit( dest, from ); }
|
||||||
template< typename T>
|
template< typename T >
|
||||||
__noinline void operator()( const ModSibBase& sibdest, const iRegister<T>& from ) const { MovImpl<T>::Emit( sibdest, from ); }
|
__noinline void operator()( const ModSibBase& sibdest, const iRegister<T>& from ) const { MovImpl<T>::Emit( sibdest, from ); }
|
||||||
template< typename T>
|
template< typename T >
|
||||||
__noinline void operator()( const iRegister<T>& to, const ModSibBase& sibsrc ) const { MovImpl<T>::Emit( to, sibsrc ); }
|
__noinline void operator()( const iRegister<T>& to, const ModSibBase& sibsrc ) const { MovImpl<T>::Emit( to, sibsrc ); }
|
||||||
|
|
||||||
template< typename T>
|
template< typename T >
|
||||||
__noinline void operator()( const ModSibStrict<T>& sibdest, int imm ) const { MovImpl<T>::Emit( sibdest, imm ); }
|
__noinline void operator()( const ModSibStrict<T>& sibdest, int imm ) const { MovImpl<T>::Emit( sibdest, imm ); }
|
||||||
|
|
||||||
// preserve_flags - set to true to disable optimizations which could alter the state of
|
// preserve_flags - set to true to disable optimizations which could alter the state of
|
||||||
|
@ -184,9 +180,11 @@ public:
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// CMOV !! [in all of it's disappointing lack-of glory]
|
// CMOV !! [in all of it's disappointing lack-of glory] .. and ..
|
||||||
// Caution! This instruction can look exciting and cool, until you realize that it cannot
|
// SETcc!! [more glory, less lack!]
|
||||||
// load immediate values into registers. -_-
|
//
|
||||||
|
// 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 >
|
template< typename ImmType, int InstBaseVal >
|
||||||
class CMovSetImpl
|
class CMovSetImpl
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// MOV instruction Implementation
|
// TEST instruction Implementation
|
||||||
|
|
||||||
template< typename ImmType >
|
template< typename ImmType >
|
||||||
class TestImpl
|
class TestImpl
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
// This helper function is used for instructions which enter XMM form when the 0x66 prefix
|
||||||
|
// is specified (indicating alternate operand type selection).
|
||||||
|
template< typename OperandType >
|
||||||
|
static __forceinline void preXMM( u8 opcode )
|
||||||
|
{
|
||||||
|
if( sizeof( OperandType ) == 16 )
|
||||||
|
iWrite<u16>( 0x0f66 );
|
||||||
|
else
|
||||||
|
iWrite<u8>( 0x0f );
|
||||||
|
iWrite<u8>( opcode );
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix - 0 indicates MMX, anything assumes XMM.
|
||||||
|
static __forceinline void SimdPrefix( u8 opcode, u8 prefix=0 )
|
||||||
|
{
|
||||||
|
if( prefix != 0 )
|
||||||
|
{
|
||||||
|
iWrite<u16>( 0x0f00 | prefix );
|
||||||
|
iWrite<u8>( opcode );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
iWrite<u16>( (opcode<<8) | 0x0f );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< u8 prefix, typename T, typename T2 >
|
||||||
|
static __forceinline void writeXMMop( const iRegister<T>& to, const iRegister<T2>& from, u8 opcode )
|
||||||
|
{
|
||||||
|
SimdPrefix( opcode, prefix );
|
||||||
|
ModRM_Direct( to.Id, from.Id );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< u8 prefix, typename T >
|
||||||
|
static __noinline void writeXMMop( const iRegister<T>& reg, const ModSibBase& sib, u8 opcode )
|
||||||
|
{
|
||||||
|
SimdPrefix( opcode, prefix );
|
||||||
|
EmitSibMagic( reg.Id, sib );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< u8 prefix, typename T >
|
||||||
|
static __forceinline void writeXMMop( const iRegister<T>& reg, const void* data, u8 opcode )
|
||||||
|
{
|
||||||
|
SimdPrefix( opcode, prefix );
|
||||||
|
iWriteDisp( reg.Id, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// MOVD has valid forms for MMX and XMM registers.
|
||||||
|
//
|
||||||
|
template< typename T >
|
||||||
|
static __forceinline void iMOVDZX( const iRegisterSIMD<T>& to, const iRegister32& from )
|
||||||
|
{
|
||||||
|
preXMM<T>( 0x6e );
|
||||||
|
ModRM_Direct( to.Id, from.Id );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T>
|
||||||
|
static __forceinline void iMOVDZX( const iRegisterSIMD<T>& to, const void* src )
|
||||||
|
{
|
||||||
|
preXMM<T>( 0x6e );
|
||||||
|
iWriteDisp( to.Id, src );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T>
|
||||||
|
static __forceinline void iMOVDZX( const iRegisterSIMD<T>& to, const ModSibBase& src )
|
||||||
|
{
|
||||||
|
preXMM<T>( 0x6e );
|
||||||
|
EmitSibMagic( to.Id, src );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T>
|
||||||
|
static __emitinline void iMOVD( const iRegister32& to, const iRegisterSIMD<T>& from )
|
||||||
|
{
|
||||||
|
preXMM<T>( 0x7e );
|
||||||
|
ModRM_Direct( from.Id, to.Id );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T>
|
||||||
|
static __forceinline void iMOVD( void* dest, const iRegisterSIMD<T>& from )
|
||||||
|
{
|
||||||
|
preXMM<T>( 0x7e );
|
||||||
|
iWriteDisp( from.Id, dest );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T>
|
||||||
|
static __noinline void iMOVD( const ModSibBase& dest, const iRegisterSIMD<T>& from )
|
||||||
|
{
|
||||||
|
preXMM<T>( 0x7e );
|
||||||
|
EmitSibMagic( from.Id, dest );
|
||||||
|
}
|
|
@ -66,10 +66,10 @@ __threadlocal XMMSSEType g_xmmtypes[iREGCNT_XMM] = { XMMT_INT };
|
||||||
|
|
||||||
namespace x86Emitter {
|
namespace x86Emitter {
|
||||||
|
|
||||||
const x86IndexerType ptr;
|
const iAddressIndexerBase ptr;
|
||||||
const x86IndexerTypeExplicit<u32> ptr32;
|
const iAddressIndexer<u32> ptr32;
|
||||||
const x86IndexerTypeExplicit<u16> ptr16;
|
const iAddressIndexer<u16> ptr16;
|
||||||
const x86IndexerTypeExplicit<u8> ptr8;
|
const iAddressIndexer<u8> ptr8;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -280,6 +280,9 @@ const Group8ImplAll<G8Type_BTR> iBTR;
|
||||||
const Group8ImplAll<G8Type_BTS> iBTS;
|
const Group8ImplAll<G8Type_BTS> iBTS;
|
||||||
const Group8ImplAll<G8Type_BTC> iBTC;
|
const Group8ImplAll<G8Type_BTC> iBTC;
|
||||||
|
|
||||||
|
const BitScanImplAll<false> iBSF;
|
||||||
|
const BitScanImplAll<true> iBSR;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
const CMovImplGeneric iCMOV;
|
const CMovImplGeneric iCMOV;
|
||||||
|
|
||||||
|
@ -607,8 +610,6 @@ __forceinline void iSMUL( const iRegister16& to, const iRegister16& from, s16 im
|
||||||
__noinline void iSMUL( const iRegister16& to, const ModSibBase& src ) { iMUL16::Emit( to, src ); }
|
__noinline void iSMUL( const iRegister16& to, const ModSibBase& src ) { iMUL16::Emit( to, src ); }
|
||||||
__noinline void iSMUL( const iRegister16& to, const ModSibBase& from, s16 imm ) { iMUL16::Emit( to, from, imm ); }
|
__noinline void iSMUL( const iRegister16& to, const ModSibBase& from, s16 imm ) { iMUL16::Emit( to, from, imm ); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Push / Pop Emitters
|
// Push / Pop Emitters
|
||||||
//
|
//
|
||||||
|
@ -627,5 +628,112 @@ __emitinline void iPUSH( const ModSibBase& from )
|
||||||
EmitSibMagic( 6, from );
|
EmitSibMagic( 6, from );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
__emitinline void iBSWAP( const iRegister32& to )
|
||||||
|
{
|
||||||
|
write8( 0x0F );
|
||||||
|
write8( 0xC8 | to.Id );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MMX / XMM Instructions
|
||||||
|
// (these will get put in their own file later)
|
||||||
|
|
||||||
|
__emitinline void iMOVQ( const iRegisterMMX& to, const iRegisterMMX& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0>( to, from, 0x6f );
|
||||||
|
}
|
||||||
|
|
||||||
|
__noinline void iMOVQ( const iRegisterMMX& to, const ModSibBase& src )
|
||||||
|
{
|
||||||
|
writeXMMop<0>( to, src, 0x6f );
|
||||||
|
}
|
||||||
|
|
||||||
|
__emitinline void iMOVQ( const iRegisterMMX& to, const void* src )
|
||||||
|
{
|
||||||
|
writeXMMop<0>( to, src, 0x6f );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moves from XMM to XMM, with the *upper 64 bits* of the destination register
|
||||||
|
// being cleared to zero.
|
||||||
|
__emitinline void iMOVQZX( const iRegisterXMM& to, const iRegisterXMM& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( to, from, 0x7e );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moves from XMM to XMM, with the *upper 64 bits* of the destination register
|
||||||
|
// being cleared to zero.
|
||||||
|
__noinline void iMOVQZX( const iRegisterXMM& to, const ModSibBase& src )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( to, src, 0x7e );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moves from XMM to XMM, with the *upper 64 bits* of the destination register
|
||||||
|
// being cleared to zero.
|
||||||
|
__emitinline void iMOVQZX( const iRegisterXMM& to, const void* src )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( to, src, 0x7e );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVQ( const ModSibBase& dest, const iRegisterMMX& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0>( from, dest, 0x7f );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVQ( void* dest, const iRegisterMMX& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0>( from, dest, 0x7f );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVQ( const ModSibBase& dest, const iRegisterXMM& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( from, dest, 0x7e );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVQ( void* dest, const iRegisterXMM& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( from, dest, 0x7e );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVQ( const iRegisterXMM& to, const iRegisterMMX& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( to, from, 0xd6 );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVQ( const iRegisterMMX& to, const iRegisterXMM& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf2>( to, from, 0xd6 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
|
||||||
|
__forceinline void iMOVSS( const iRegisterXMM& to, const iRegisterXMM& from )
|
||||||
|
{
|
||||||
|
if( to != from )
|
||||||
|
writeXMMop<0xf3>( to, from, 0x10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVSSZX( const iRegisterXMM& to, const void* from )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( to, from, 0x10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVSSZX( const iRegisterXMM& to, const ModSibBase& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( to, from, 0x10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVSS( const void* to, const iRegisterXMM& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( from, to, 0x11 );
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void iMOVSS( const ModSibBase& to, const iRegisterXMM& from )
|
||||||
|
{
|
||||||
|
writeXMMop<0xf3>( from, to, 0x11 );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,15 +121,30 @@ namespace x86Emitter
|
||||||
// fashion.
|
// fashion.
|
||||||
__forceinline void ModSibBase::Reduce()
|
__forceinline void ModSibBase::Reduce()
|
||||||
{
|
{
|
||||||
|
if( Index.IsStackPointer() )
|
||||||
|
{
|
||||||
|
// esp cannot be encoded as the index, so move it to the Base, if possible.
|
||||||
|
// note: intentionally leave index assigned to esp also (generates correct
|
||||||
|
// encoding later, since ESP cannot be encoded 'alone')
|
||||||
|
|
||||||
|
jASSUME( Scale == 0 ); // esp can't have an index modifier!
|
||||||
|
jASSUME( Base.IsEmpty() ); // base must be empty or else!
|
||||||
|
|
||||||
|
Base = Index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If no index reg, then load the base register into the index slot.
|
// If no index reg, then load the base register into the index slot.
|
||||||
if( Index.IsEmpty() )
|
if( Index.IsEmpty() )
|
||||||
{
|
{
|
||||||
Index = Base;
|
Index = Base;
|
||||||
Scale = 0;
|
Scale = 0;
|
||||||
Base = x86IndexReg::Empty;
|
if( !Base.IsStackPointer() ) // prevent ESP from being encoded 'alone'
|
||||||
|
Base = x86IndexReg::Empty;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The Scale has a series of valid forms, all shown here:
|
// The Scale has a series of valid forms, all shown here:
|
||||||
|
|
||||||
switch( Scale )
|
switch( Scale )
|
||||||
|
@ -167,17 +182,6 @@ namespace x86Emitter
|
||||||
Scale = 3;
|
Scale = 3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Index.IsStackPointer() )
|
|
||||||
{
|
|
||||||
// esp cannot be encoded as the index, so move it to the Base, if possible.
|
|
||||||
jASSUME( Scale == 0 );
|
|
||||||
jASSUME( Base.IsEmpty() );
|
|
||||||
|
|
||||||
Base = Index;
|
|
||||||
// noe: leave index assigned to esp also (generates correct encoding later)
|
|
||||||
//Index = x86IndexReg::Empty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -35,7 +35,127 @@
|
||||||
|
|
||||||
namespace x86Emitter
|
namespace x86Emitter
|
||||||
{
|
{
|
||||||
extern void iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward=false );
|
// ------------------------------------------------------------------------
|
||||||
|
// Group 1 Instruction Class
|
||||||
|
|
||||||
|
extern const Internal::Group1ImplAll<Internal::G1Type_ADD> iADD;
|
||||||
|
extern const Internal::Group1ImplAll<Internal::G1Type_OR> iOR;
|
||||||
|
extern const Internal::Group1ImplAll<Internal::G1Type_ADC> iADC;
|
||||||
|
extern const Internal::Group1ImplAll<Internal::G1Type_SBB> iSBB;
|
||||||
|
extern const Internal::Group1ImplAll<Internal::G1Type_AND> iAND;
|
||||||
|
extern const Internal::Group1ImplAll<Internal::G1Type_SUB> iSUB;
|
||||||
|
extern const Internal::Group1ImplAll<Internal::G1Type_XOR> iXOR;
|
||||||
|
extern const Internal::Group1ImplAll<Internal::G1Type_CMP> iCMP;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Group 2 Instruction Class
|
||||||
|
//
|
||||||
|
// Optimization Note: For Imm forms, we ignore the instruction if the shift count is
|
||||||
|
// zero. This is a safe optimization since any zero-value shift does not affect any
|
||||||
|
// flags.
|
||||||
|
|
||||||
|
extern const Internal::MovImplAll iMOV;
|
||||||
|
extern const Internal::TestImplAll iTEST;
|
||||||
|
|
||||||
|
extern const Internal::Group2ImplAll<Internal::G2Type_ROL> iROL;
|
||||||
|
extern const Internal::Group2ImplAll<Internal::G2Type_ROR> iROR;
|
||||||
|
extern const Internal::Group2ImplAll<Internal::G2Type_RCL> iRCL;
|
||||||
|
extern const Internal::Group2ImplAll<Internal::G2Type_RCR> iRCR;
|
||||||
|
extern const Internal::Group2ImplAll<Internal::G2Type_SHL> iSHL;
|
||||||
|
extern const Internal::Group2ImplAll<Internal::G2Type_SHR> iSHR;
|
||||||
|
extern const Internal::Group2ImplAll<Internal::G2Type_SAR> iSAR;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Group 3 Instruction Class
|
||||||
|
|
||||||
|
extern const Internal::Group3ImplAll<Internal::G3Type_NOT> iNOT;
|
||||||
|
extern const Internal::Group3ImplAll<Internal::G3Type_NEG> iNEG;
|
||||||
|
extern const Internal::Group3ImplAll<Internal::G3Type_MUL> iUMUL;
|
||||||
|
extern const Internal::Group3ImplAll<Internal::G3Type_DIV> iUDIV;
|
||||||
|
extern const Internal::Group3ImplAll<Internal::G3Type_iDIV> iSDIV;
|
||||||
|
|
||||||
|
extern const Internal::IncDecImplAll<false> iINC;
|
||||||
|
extern const Internal::IncDecImplAll<true> iDEC;
|
||||||
|
|
||||||
|
extern const Internal::MovExtendImplAll<false> iMOVZX;
|
||||||
|
extern const Internal::MovExtendImplAll<true> iMOVSX;
|
||||||
|
|
||||||
|
extern const Internal::DwordShiftImplAll<false> iSHLD;
|
||||||
|
extern const Internal::DwordShiftImplAll<true> iSHRD;
|
||||||
|
|
||||||
|
extern const Internal::Group8ImplAll<Internal::G8Type_BT> iBT;
|
||||||
|
extern const Internal::Group8ImplAll<Internal::G8Type_BTR> iBTR;
|
||||||
|
extern const Internal::Group8ImplAll<Internal::G8Type_BTS> iBTS;
|
||||||
|
extern const Internal::Group8ImplAll<Internal::G8Type_BTC> iBTC;
|
||||||
|
|
||||||
|
extern const Internal::JmpCallImplAll<true> iJMP;
|
||||||
|
extern const Internal::JmpCallImplAll<false> iCALL;
|
||||||
|
|
||||||
|
extern const Internal::BitScanImplAll<false> iBSF;
|
||||||
|
extern const Internal::BitScanImplAll<true> iBSR;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
extern const Internal::CMovImplGeneric iCMOV;
|
||||||
|
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Above> iCMOVA;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_AboveOrEqual> iCMOVAE;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Below> iCMOVB;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_BelowOrEqual> iCMOVBE;
|
||||||
|
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Greater> iCMOVG;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_GreaterOrEqual> iCMOVGE;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Less> iCMOVL;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_LessOrEqual> iCMOVLE;
|
||||||
|
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Zero> iCMOVZ;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Equal> iCMOVE;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_NotZero> iCMOVNZ;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_NotEqual> iCMOVNE;
|
||||||
|
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Overflow> iCMOVO;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_NotOverflow> iCMOVNO;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Carry> iCMOVC;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_NotCarry> iCMOVNC;
|
||||||
|
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Signed> iCMOVS;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_Unsigned> iCMOVNS;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_ParityEven> iCMOVPE;
|
||||||
|
extern const Internal::CMovImplAll<Jcc_ParityOdd> iCMOVPO;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
extern const Internal::SetImplGeneric iSET;
|
||||||
|
|
||||||
|
extern const Internal::SetImplAll<Jcc_Above> iSETA;
|
||||||
|
extern const Internal::SetImplAll<Jcc_AboveOrEqual> iSETAE;
|
||||||
|
extern const Internal::SetImplAll<Jcc_Below> iSETB;
|
||||||
|
extern const Internal::SetImplAll<Jcc_BelowOrEqual> iSETBE;
|
||||||
|
|
||||||
|
extern const Internal::SetImplAll<Jcc_Greater> iSETG;
|
||||||
|
extern const Internal::SetImplAll<Jcc_GreaterOrEqual> iSETGE;
|
||||||
|
extern const Internal::SetImplAll<Jcc_Less> iSETL;
|
||||||
|
extern const Internal::SetImplAll<Jcc_LessOrEqual> iSETLE;
|
||||||
|
|
||||||
|
extern const Internal::SetImplAll<Jcc_Zero> iSETZ;
|
||||||
|
extern const Internal::SetImplAll<Jcc_Equal> iSETE;
|
||||||
|
extern const Internal::SetImplAll<Jcc_NotZero> iSETNZ;
|
||||||
|
extern const Internal::SetImplAll<Jcc_NotEqual> iSETNE;
|
||||||
|
|
||||||
|
extern const Internal::SetImplAll<Jcc_Overflow> iSETO;
|
||||||
|
extern const Internal::SetImplAll<Jcc_NotOverflow> iSETNO;
|
||||||
|
extern const Internal::SetImplAll<Jcc_Carry> iSETC;
|
||||||
|
extern const Internal::SetImplAll<Jcc_NotCarry> iSETNC;
|
||||||
|
|
||||||
|
extern const Internal::SetImplAll<Jcc_Signed> iSETS;
|
||||||
|
extern const Internal::SetImplAll<Jcc_Unsigned> iSETNS;
|
||||||
|
extern const Internal::SetImplAll<Jcc_ParityEven> iSETPE;
|
||||||
|
extern const Internal::SetImplAll<Jcc_ParityOdd> iSETPO;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Miscellaneous Instructions
|
||||||
|
// These are all defined inline or in ix86.cpp.
|
||||||
|
//
|
||||||
|
|
||||||
|
extern void iBSWAP( const iRegister32& to );
|
||||||
|
|
||||||
// ----- Lea Instructions (Load Effective Address) -----
|
// ----- Lea Instructions (Load Effective Address) -----
|
||||||
// Note: alternate (void*) forms of these instructions are not provided since those
|
// Note: alternate (void*) forms of these instructions are not provided since those
|
||||||
|
@ -81,7 +201,7 @@ namespace x86Emitter
|
||||||
|
|
||||||
// NOP 1-byte
|
// NOP 1-byte
|
||||||
__forceinline void iNOP() { write8(0x90); }
|
__forceinline void iNOP() { write8(0x90); }
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// MUL / DIV instructions
|
// MUL / DIV instructions
|
||||||
|
|
||||||
|
@ -105,6 +225,8 @@ namespace x86Emitter
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// JMP / Jcc Instructions!
|
// JMP / Jcc Instructions!
|
||||||
|
|
||||||
|
extern void iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward=false );
|
||||||
|
|
||||||
#define DEFINE_FORWARD_JUMP( label, cond ) \
|
#define DEFINE_FORWARD_JUMP( label, cond ) \
|
||||||
template< typename OperandType > \
|
template< typename OperandType > \
|
||||||
class iForward##label : public iForwardJump<OperandType> \
|
class iForward##label : public iForwardJump<OperandType> \
|
||||||
|
@ -193,5 +315,40 @@ namespace x86Emitter
|
||||||
typedef iForwardJPE<s32> iForwardJPE32;
|
typedef iForwardJPE<s32> iForwardJPE32;
|
||||||
typedef iForwardJPO<s8> iForwardJPO8;
|
typedef iForwardJPO<s8> iForwardJPO8;
|
||||||
typedef iForwardJPO<s32> iForwardJPO32;
|
typedef iForwardJPO<s32> iForwardJPO32;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MMX Mov Instructions (MOVD, MOVQ, MOVSS).
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// * Some of the functions have been renamed to more clearly reflect what they actually
|
||||||
|
// do. Namely we've affixed "ZX" to several MOVs that take a register as a destination
|
||||||
|
// since that's what they do (MOVD clears upper 32/96 bits, etc).
|
||||||
|
//
|
||||||
|
|
||||||
|
using Internal::iMOVD;
|
||||||
|
using Internal::iMOVDZX;
|
||||||
|
|
||||||
|
extern void iMOVQ( const iRegisterMMX& to, const iRegisterMMX& from );
|
||||||
|
extern void iMOVQ( const iRegisterMMX& to, const iRegisterXMM& from );
|
||||||
|
extern void iMOVQ( const iRegisterXMM& to, const iRegisterMMX& from );
|
||||||
|
|
||||||
|
extern void iMOVQ( void* dest, const iRegisterXMM& from );
|
||||||
|
extern void iMOVQ( const ModSibBase& dest, const iRegisterXMM& from );
|
||||||
|
extern void iMOVQ( void* dest, const iRegisterMMX& from );
|
||||||
|
extern void iMOVQ( const ModSibBase& dest, const iRegisterMMX& from );
|
||||||
|
extern void iMOVQ( const iRegisterMMX& to, const void* src );
|
||||||
|
extern void iMOVQ( const iRegisterMMX& to, const ModSibBase& src );
|
||||||
|
|
||||||
|
extern void iMOVQZX( const iRegisterXMM& to, const void* src );
|
||||||
|
extern void iMOVQZX( const iRegisterXMM& to, const ModSibBase& src );
|
||||||
|
extern void iMOVQZX( const iRegisterXMM& to, const iRegisterXMM& from );
|
||||||
|
|
||||||
|
extern void iMOVSS( const iRegisterXMM& to, const iRegisterXMM& from );
|
||||||
|
extern void iMOVSS( const void* to, const iRegisterXMM& from );
|
||||||
|
extern void iMOVSS( const ModSibBase& to, const iRegisterXMM& from );
|
||||||
|
|
||||||
|
extern void iMOVSSZX( const iRegisterXMM& to, const void* from );
|
||||||
|
extern void iMOVSSZX( const iRegisterXMM& to, const ModSibBase& from );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,19 +38,20 @@
|
||||||
|
|
||||||
namespace x86Emitter {
|
namespace x86Emitter {
|
||||||
|
|
||||||
|
using namespace Internal;
|
||||||
|
|
||||||
|
const JmpCallImplAll<true> iJMP;
|
||||||
|
const JmpCallImplAll<false> iCALL;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
void iSmartJump::SetTarget()
|
void iSmartJump::SetTarget()
|
||||||
{
|
{
|
||||||
jASSUME( !m_written );
|
u8* target = iGetPtr();
|
||||||
if( m_written )
|
|
||||||
throw Exception::InvalidOperation( "Attempted to set SmartJump label multiple times." );
|
|
||||||
|
|
||||||
m_target = iGetPtr();
|
|
||||||
if( m_baseptr == NULL ) return;
|
if( m_baseptr == NULL ) return;
|
||||||
|
|
||||||
iSetPtr( m_baseptr );
|
iSetPtr( m_baseptr );
|
||||||
u8* const saveme = m_baseptr + GetMaxInstructionSize();
|
u8* const saveme = m_baseptr + GetMaxInstructionSize();
|
||||||
iJccKnownTarget( m_cc, m_target, true );
|
iJccKnownTarget( m_cc, target, true );
|
||||||
|
|
||||||
// Copy recompiled data inward if the jump instruction didn't fill the
|
// Copy recompiled data inward if the jump instruction didn't fill the
|
||||||
// alloted buffer (means that we optimized things to a j8!)
|
// alloted buffer (means that we optimized things to a j8!)
|
||||||
|
@ -59,17 +60,19 @@ void iSmartJump::SetTarget()
|
||||||
if( spacer != 0 )
|
if( spacer != 0 )
|
||||||
{
|
{
|
||||||
u8* destpos = iGetPtr();
|
u8* destpos = iGetPtr();
|
||||||
const int copylen = (sptr)m_target - (sptr)saveme;
|
const int copylen = (sptr)target - (sptr)saveme;
|
||||||
|
|
||||||
memcpy_fast( destpos, saveme, copylen );
|
memcpy_fast( destpos, saveme, copylen );
|
||||||
iSetPtr( m_target - spacer );
|
iSetPtr( target - spacer );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_written = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
iSmartJump::~iSmartJump()
|
||||||
//
|
{
|
||||||
|
SetTarget();
|
||||||
|
m_baseptr = NULL; // just in case (sometimes helps in debugging too)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Writes a jump at the current x86Ptr, which targets a pre-established target address.
|
// Writes a jump at the current x86Ptr, which targets a pre-established target address.
|
||||||
|
@ -78,6 +81,7 @@ void iSmartJump::SetTarget()
|
||||||
// slideForward - used internally by iSmartJump to indicate that the jump target is going
|
// slideForward - used internally by iSmartJump to indicate that the jump target is going
|
||||||
// to slide forward in the event of an 8 bit displacement.
|
// to slide forward in the event of an 8 bit displacement.
|
||||||
//
|
//
|
||||||
|
// Using this
|
||||||
__emitinline void iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward )
|
__emitinline void iJccKnownTarget( JccComparisonType comparison, void* target, bool slideForward )
|
||||||
{
|
{
|
||||||
// Calculate the potential j8 displacement first, assuming an instruction length of 2:
|
// Calculate the potential j8 displacement first, assuming an instruction length of 2:
|
||||||
|
@ -110,9 +114,4 @@ __emitinline void iJccKnownTarget( JccComparisonType comparison, void* target, b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__emitinline void iJcc( JccComparisonType comparison, void* target )
|
|
||||||
{
|
|
||||||
iJccKnownTarget( comparison, target );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -445,18 +445,6 @@ emitterT void NOP( void ) { iNOP(); }
|
||||||
// jump instructions /
|
// jump instructions /
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
|
|
||||||
emitterT u8* JMP( uptr to ) {
|
|
||||||
uptr jump = ( x86Ptr - (u8*)to ) - 1;
|
|
||||||
|
|
||||||
if ( jump > 0x7f ) {
|
|
||||||
assert( to <= 0xffffffff );
|
|
||||||
return (u8*)JMP32( to );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (u8*)JMP8( to );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* jmp rel8 */
|
/* jmp rel8 */
|
||||||
emitterT u8* JMP8( u8 to )
|
emitterT u8* JMP8( u8 to )
|
||||||
{
|
{
|
||||||
|
@ -477,17 +465,13 @@ emitterT u32* JMP32( uptr to )
|
||||||
/* jmp r32/r64 */
|
/* jmp r32/r64 */
|
||||||
emitterT void JMPR( x86IntRegType to )
|
emitterT void JMPR( x86IntRegType to )
|
||||||
{
|
{
|
||||||
RexB(0, to);
|
iJMP( iRegister32(to) );
|
||||||
write8( 0xFF );
|
|
||||||
ModRM( 3, 4, to );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// jmp m32
|
// jmp m32
|
||||||
emitterT void JMP32M( uptr to )
|
emitterT void JMP32M( uptr to )
|
||||||
{
|
{
|
||||||
write8( 0xFF );
|
iJMP( ptr32[to] );
|
||||||
ModRM( 0, 4, DISP32 );
|
|
||||||
write32( MEMADDR(to, 4));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jp rel8 */
|
/* jp rel8 */
|
||||||
|
@ -736,41 +720,27 @@ emitterT u32* JNO32( u32 to )
|
||||||
/* call func */
|
/* call func */
|
||||||
emitterT void CALLFunc( uptr func )
|
emitterT void CALLFunc( uptr func )
|
||||||
{
|
{
|
||||||
func -= ( (uptr)x86Ptr + 5 );
|
iCALL( (void*)func );
|
||||||
assert( (sptr)func <= 0x7fffffff && (sptr)func >= -0x7fffffff );
|
|
||||||
CALL32(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* call rel32 */
|
|
||||||
emitterT void CALL32( u32 to )
|
|
||||||
{
|
|
||||||
write8( 0xE8 );
|
|
||||||
write32( to );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call r32 */
|
/* call r32 */
|
||||||
emitterT void CALL32R( x86IntRegType to )
|
emitterT void CALL32R( x86IntRegType to )
|
||||||
{
|
{
|
||||||
write8( 0xFF );
|
iCALL( iRegister32( to ) );
|
||||||
ModRM( 3, 2, to );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call m32 */
|
/* call m32 */
|
||||||
emitterT void CALL32M( u32 to )
|
emitterT void CALL32M( u32 to )
|
||||||
{
|
{
|
||||||
write8( 0xFF );
|
iCALL( ptr32[to] );
|
||||||
ModRM( 0, 2, DISP32 );
|
|
||||||
write32( MEMADDR(to, 4) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void BSRRtoR(x86IntRegType to, x86IntRegType from)
|
emitterT void BSRRtoR(x86IntRegType to, x86IntRegType from)
|
||||||
{
|
{
|
||||||
write16( 0xBD0F );
|
iBSR( iRegister32(to), iRegister32(from) );
|
||||||
ModRM( 3, from, to );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void BSWAP32R( x86IntRegType to )
|
emitterT void BSWAP32R( x86IntRegType to )
|
||||||
{
|
{
|
||||||
write8( 0x0F );
|
iBSWAP( iRegister32(to) );
|
||||||
write8( 0xC8 + to );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -576,8 +576,6 @@ extern u32* JS32( u32 to );
|
||||||
|
|
||||||
// call func
|
// call func
|
||||||
extern void CALLFunc( uptr func); // based on CALL32
|
extern void CALLFunc( uptr func); // based on CALL32
|
||||||
// call rel32
|
|
||||||
extern void CALL32( u32 to );
|
|
||||||
// call r32
|
// call r32
|
||||||
extern void CALL32R( x86IntRegType to );
|
extern void CALL32R( x86IntRegType to );
|
||||||
// call m32
|
// call m32
|
||||||
|
@ -923,7 +921,6 @@ extern void PUNPCKLDQRtoR( x86MMXRegType to, x86MMXRegType from );
|
||||||
extern void PUNPCKLDQMtoR( x86MMXRegType to, uptr from );
|
extern void PUNPCKLDQMtoR( x86MMXRegType to, uptr from );
|
||||||
extern void PUNPCKHDQRtoR( x86MMXRegType to, x86MMXRegType from );
|
extern void PUNPCKHDQRtoR( x86MMXRegType to, x86MMXRegType from );
|
||||||
extern void PUNPCKHDQMtoR( x86MMXRegType to, uptr from );
|
extern void PUNPCKHDQMtoR( x86MMXRegType to, uptr from );
|
||||||
extern void MOVQ64ItoR( x86MMXRegType reg, u64 i ); //Prototype.Todo add all consts to end of block.not after jr $+8
|
|
||||||
extern void MOVQRtoR( x86MMXRegType to, x86MMXRegType from );
|
extern void MOVQRtoR( x86MMXRegType to, x86MMXRegType from );
|
||||||
extern void MOVQRmtoR( x86MMXRegType to, x86IntRegType from, int offset=0 );
|
extern void MOVQRmtoR( x86MMXRegType to, x86IntRegType from, int offset=0 );
|
||||||
extern void MOVQRtoRm( x86IntRegType to, x86MMXRegType from, int offset=0 );
|
extern void MOVQRtoRm( x86IntRegType to, x86MMXRegType from, int offset=0 );
|
||||||
|
|
|
@ -25,20 +25,24 @@
|
||||||
// note: r64 = mm
|
// note: r64 = mm
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
|
using namespace x86Emitter;
|
||||||
|
|
||||||
/* movq m64 to r64 */
|
/* movq m64 to r64 */
|
||||||
emitterT void MOVQMtoR( x86MMXRegType to, uptr from )
|
emitterT void MOVQMtoR( x86MMXRegType to, uptr from )
|
||||||
{
|
{
|
||||||
write16( 0x6F0F );
|
iMOVQ( iRegisterMMX(to), (void*)from );
|
||||||
ModRM( 0, to, DISP32 );
|
//write16( 0x6F0F );
|
||||||
write32( MEMADDR(from, 4) );
|
//ModRM( 0, to, DISP32 );
|
||||||
|
//write32( MEMADDR(from, 4) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* movq r64 to m64 */
|
/* movq r64 to m64 */
|
||||||
emitterT void MOVQRtoM( uptr to, x86MMXRegType from )
|
emitterT void MOVQRtoM( uptr to, x86MMXRegType from )
|
||||||
{
|
{
|
||||||
write16( 0x7F0F );
|
iMOVQ( (void*)to, iRegisterMMX(from) );
|
||||||
ModRM( 0, from, DISP32 );
|
//write16( 0x7F0F );
|
||||||
write32(MEMADDR(to, 4));
|
//ModRM( 0, from, DISP32 );
|
||||||
|
//write32(MEMADDR(to, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pand r64 to r64 */
|
/* pand r64 to r64 */
|
||||||
|
@ -470,69 +474,71 @@ emitterT void PUNPCKLDQMtoR( x86MMXRegType to, uptr from )
|
||||||
write32( MEMADDR(from, 4) );
|
write32( MEMADDR(from, 4) );
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void MOVQ64ItoR( x86MMXRegType reg, u64 i )
|
|
||||||
{
|
|
||||||
MOVQMtoR( reg, ( uptr )(x86Ptr) + 2 + 7 );
|
|
||||||
JMP8( 8 );
|
|
||||||
write64( i );
|
|
||||||
}
|
|
||||||
|
|
||||||
emitterT void MOVQRtoR( x86MMXRegType to, x86MMXRegType from )
|
emitterT void MOVQRtoR( x86MMXRegType to, x86MMXRegType from )
|
||||||
{
|
{
|
||||||
write16( 0x6F0F );
|
iMOVQ( iRegisterMMX(to), iRegisterMMX(from) );
|
||||||
ModRM( 3, to, from );
|
//write16( 0x6F0F );
|
||||||
|
//ModRM( 3, to, from );
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void MOVQRmtoR( x86MMXRegType to, x86IntRegType from, int offset )
|
emitterT void MOVQRmtoR( x86MMXRegType to, x86IntRegType from, int offset )
|
||||||
{
|
{
|
||||||
write16( 0x6F0F );
|
iMOVQ( iRegisterMMX(to), ptr[x86IndexReg(from)+offset] );
|
||||||
WriteRmOffsetFrom( to, from, offset );
|
//write16( 0x6F0F );
|
||||||
|
//WriteRmOffsetFrom( to, from, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void MOVQRtoRm( x86IntRegType to, x86MMXRegType from, int offset )
|
emitterT void MOVQRtoRm( x86IntRegType to, x86MMXRegType from, int offset )
|
||||||
{
|
{
|
||||||
write16( 0x7F0F );
|
iMOVQ( ptr[x86IndexReg(to)+offset], iRegisterMMX(from) );
|
||||||
WriteRmOffsetFrom( from, to, offset );
|
//write16( 0x7F0F );
|
||||||
|
//WriteRmOffsetFrom( from, to, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* movd m32 to r64 */
|
/* movd m32 to r64 */
|
||||||
emitterT void MOVDMtoMMX( x86MMXRegType to, uptr from )
|
emitterT void MOVDMtoMMX( x86MMXRegType to, uptr from )
|
||||||
{
|
{
|
||||||
write16( 0x6E0F );
|
iMOVDZX( iRegisterMMX(to), (void*)from );
|
||||||
ModRM( 0, to, DISP32 );
|
//write16( 0x6E0F );
|
||||||
write32( MEMADDR(from, 4) );
|
//ModRM( 0, to, DISP32 );
|
||||||
|
//write32( MEMADDR(from, 4) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* movd r64 to m32 */
|
/* movd r64 to m32 */
|
||||||
emitterT void MOVDMMXtoM( uptr to, x86MMXRegType from )
|
emitterT void MOVDMMXtoM( uptr to, x86MMXRegType from )
|
||||||
{
|
{
|
||||||
write16( 0x7E0F );
|
iMOVD( (void*)to, iRegisterMMX(from) );
|
||||||
ModRM( 0, from, DISP32 );
|
//write16( 0x7E0F );
|
||||||
write32( MEMADDR(to, 4) );
|
//ModRM( 0, from, DISP32 );
|
||||||
|
//write32( MEMADDR(to, 4) );
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void MOVD32RtoMMX( x86MMXRegType to, x86IntRegType from )
|
emitterT void MOVD32RtoMMX( x86MMXRegType to, x86IntRegType from )
|
||||||
{
|
{
|
||||||
write16( 0x6E0F );
|
iMOVDZX( iRegisterMMX(to), iRegister32(from) );
|
||||||
ModRM( 3, to, from );
|
//write16( 0x6E0F );
|
||||||
|
//ModRM( 3, to, from );
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void MOVD32RmtoMMX( x86MMXRegType to, x86IntRegType from, int offset )
|
emitterT void MOVD32RmtoMMX( x86MMXRegType to, x86IntRegType from, int offset )
|
||||||
{
|
{
|
||||||
write16( 0x6E0F );
|
iMOVDZX( iRegisterMMX(to), ptr[x86IndexReg(from)+offset] );
|
||||||
WriteRmOffsetFrom( to, from, offset );
|
//write16( 0x6E0F );
|
||||||
|
//WriteRmOffsetFrom( to, from, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void MOVD32MMXtoR( x86IntRegType to, x86MMXRegType from )
|
emitterT void MOVD32MMXtoR( x86IntRegType to, x86MMXRegType from )
|
||||||
{
|
{
|
||||||
write16( 0x7E0F );
|
iMOVD( iRegister32(to), iRegisterMMX(from) );
|
||||||
ModRM( 3, from, to );
|
//write16( 0x7E0F );
|
||||||
|
//ModRM( 3, from, to );
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void MOVD32MMXtoRm( x86IntRegType to, x86MMXRegType from, int offset )
|
emitterT void MOVD32MMXtoRm( x86IntRegType to, x86MMXRegType from, int offset )
|
||||||
{
|
{
|
||||||
write16( 0x7E0F );
|
iMOVD( ptr[x86IndexReg(to)+offset], iRegisterMMX(from) );
|
||||||
WriteRmOffsetFrom( from, to, offset );
|
//write16( 0x7E0F );
|
||||||
|
//WriteRmOffsetFrom( from, to, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
// untested
|
// untested
|
|
@ -20,6 +20,8 @@
|
||||||
#include "ix86_legacy_internal.h"
|
#include "ix86_legacy_internal.h"
|
||||||
#include "ix86_sse_helpers.h"
|
#include "ix86_sse_helpers.h"
|
||||||
|
|
||||||
|
using namespace x86Emitter;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// AlwaysUseMovaps [const]
|
// AlwaysUseMovaps [const]
|
||||||
//
|
//
|
||||||
|
@ -303,55 +305,39 @@ emitterT void SSE2_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { S
|
||||||
emitterT void SSE2_MOVSD_M64_to_XMM( x86SSERegType to, uptr from ) { SSE_SD_MtoR( 0x100f, 0); }
|
emitterT void SSE2_MOVSD_M64_to_XMM( x86SSERegType to, uptr from ) { SSE_SD_MtoR( 0x100f, 0); }
|
||||||
emitterT void SSE2_MOVSD_XMM_to_M64( uptr to, x86SSERegType from ) { SSE_SD_RtoM( 0x110f, 0); }
|
emitterT void SSE2_MOVSD_XMM_to_M64( uptr to, x86SSERegType from ) { SSE_SD_RtoM( 0x110f, 0); }
|
||||||
|
|
||||||
emitterT void SSE2_MOVQ_M64_to_XMM( x86SSERegType to, uptr from )
|
emitterT void SSE2_MOVQ_M64_to_XMM( x86SSERegType to, uptr from ) { iMOVQZX( iRegisterXMM(to), (void*)from ); }
|
||||||
{
|
emitterT void SSE2_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { iMOVQZX( iRegisterXMM(to), iRegisterXMM(from) ); }
|
||||||
write8(0xf3); SSEMtoR( 0x7e0f, 0);
|
emitterT void SSE2_MOVQ_XMM_to_M64( u32 to, x86SSERegType from ) { iMOVQ( (void*)to, iRegisterXMM(from) ); }
|
||||||
}
|
emitterT void SSE2_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from) { iMOVQ( iRegisterMMX(to), iRegisterXMM(from) ); }
|
||||||
|
emitterT void SSE2_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from) { iMOVQ( iRegisterXMM(to), iRegisterMMX(from) ); }
|
||||||
emitterT void SSE2_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from )
|
|
||||||
{
|
|
||||||
write8(0xf3); SSERtoR( 0x7e0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
emitterT void SSE2_MOVQ_XMM_to_M64( u32 to, x86SSERegType from )
|
|
||||||
{
|
|
||||||
SSERtoM66(0xd60f);
|
|
||||||
}
|
|
||||||
|
|
||||||
emitterT void SSE2_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from)
|
|
||||||
{
|
|
||||||
write8(0xf2);
|
|
||||||
SSERtoR( 0xd60f);
|
|
||||||
}
|
|
||||||
emitterT void SSE2_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from)
|
|
||||||
{
|
|
||||||
write8(0xf3);
|
|
||||||
SSERtoR( 0xd60f);
|
|
||||||
}
|
|
||||||
|
|
||||||
//**********************************************************************************/
|
//**********************************************************************************/
|
||||||
//MOVSS: Move Scalar Single-Precision FP value *
|
//MOVSS: Move Scalar Single-Precision FP value *
|
||||||
//**********************************************************************************
|
//**********************************************************************************
|
||||||
emitterT void SSE_MOVSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x100f, 0 ); }
|
emitterT void SSE_MOVSS_M32_to_XMM( x86SSERegType to, uptr from ) { iMOVSSZX( iRegisterXMM(to), (void*)from ); }
|
||||||
|
emitterT void SSE_MOVSS_XMM_to_M32( u32 to, x86SSERegType from ) { iMOVSS( (void*)to, iRegisterXMM(from) ); }
|
||||||
|
emitterT void SSE_MOVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { iMOVSS( iRegisterXMM(to), iRegisterXMM(from) ); }
|
||||||
|
emitterT void SSE_MOVSS_Rm_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) { iMOVSSZX( iRegisterXMM(to), ptr[x86IndexReg(from)+offset] ); }
|
||||||
|
emitterT void SSE_MOVSS_XMM_to_Rm( x86IntRegType to, x86SSERegType from, int offset ) { iMOVSS( ptr[x86IndexReg(to)+offset], iRegisterXMM(from) ); }
|
||||||
|
|
||||||
|
/*emitterT void SSE_MOVSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x100f, 0 ); }
|
||||||
emitterT void SSE_MOVSS_XMM_to_M32( u32 to, x86SSERegType from ) { SSE_SS_RtoM( 0x110f, 0 ); }
|
emitterT void SSE_MOVSS_XMM_to_M32( u32 to, x86SSERegType from ) { SSE_SS_RtoM( 0x110f, 0 ); }
|
||||||
|
|
||||||
emitterT void SSE_MOVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { if (to != from) { SSE_SS_RtoR( 0x100f ); } }
|
emitterT void SSE_MOVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { if (to != from) { SSE_SS_RtoR( 0x100f ); } }
|
||||||
|
|
||||||
emitterT void SSE_MOVSS_Rm_to_XMM( x86SSERegType to, x86IntRegType from, int offset )
|
emitterT void SSE_MOVSS_Rm_to_XMM( x86SSERegType to, x86IntRegType from, int offset )
|
||||||
{
|
{
|
||||||
write8(0xf3);
|
write8(0xf3);
|
||||||
RexRB(0, to, from);
|
RexRB(0, to, from);
|
||||||
write16( 0x100f );
|
write16( 0x100f );
|
||||||
WriteRmOffsetFrom(to, from, offset);
|
WriteRmOffsetFrom(to, from, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitterT void SSE_MOVSS_XMM_to_Rm( x86IntRegType to, x86SSERegType from, int offset )
|
emitterT void SSE_MOVSS_XMM_to_Rm( x86IntRegType to, x86SSERegType from, int offset )
|
||||||
{
|
{
|
||||||
write8(0xf3);
|
write8(0xf3);
|
||||||
RexRB(0, from, to);
|
RexRB(0, from, to);
|
||||||
write16(0x110f);
|
write16(0x110f);
|
||||||
WriteRmOffsetFrom(from, to, offset);
|
WriteRmOffsetFrom(from, to, offset);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
emitterT void SSE_MASKMOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xf70f ); }
|
emitterT void SSE_MASKMOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xf70f ); }
|
||||||
//**********************************************************************************/
|
//**********************************************************************************/
|
||||||
|
@ -1405,8 +1391,7 @@ emitterT void SSE4_PMULDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// SSE-X Helpers (generates either INT or FLOAT versions of certain SSE instructions)
|
// SSE-X Helpers (generates either INT or FLOAT versions of certain SSE instructions)
|
||||||
// This header should always be included *after* ix86.h.
|
//
|
||||||
|
|
||||||
// Added AlwaysUseMovaps check to the relevant functions here, which helps reduce the
|
// Added AlwaysUseMovaps check to the relevant functions here, which helps reduce the
|
||||||
// overhead of dynarec instructions that use these, even thought the same check would
|
// overhead of dynarec instructions that use these, even thought the same check would
|
||||||
// have been done redundantly by the emitter function.
|
// have been done redundantly by the emitter function.
|
|
@ -129,22 +129,22 @@ namespace x86Emitter
|
||||||
//
|
//
|
||||||
// This is configured to inline emitter functions appropriately for release builds, and
|
// This is configured to inline emitter functions appropriately for release builds, and
|
||||||
// disables some of the more aggressive inlines for dev builds (which can be helpful when
|
// disables some of the more aggressive inlines for dev builds (which can be helpful when
|
||||||
// debugging).
|
// debugging). Additionally, I've set up the inlining to be as practical and intelligent
|
||||||
|
// as possible with regard to constant propagation. Namely this involves forcing inlining
|
||||||
|
// for (void*) forms of ModRM, which (thanks to constprop) reduce to virtually no code, and
|
||||||
|
// force-disabling inlining on complicated SibSB forms [since MSVC would sometimes inline
|
||||||
|
// despite being a generally bad idea].
|
||||||
//
|
//
|
||||||
// Note: I use __forceinline directly for most single-line class members, when needed.
|
// In the case of (Reg, Imm) forms, the inlining is up to the discreation of the compiler.
|
||||||
// There's no point in using __emitline in these cases since the debugger can't trace into
|
//
|
||||||
// single-line functions anyway.
|
// Note: I *intentionally* use __forceinline directly for most single-line class members,
|
||||||
|
// when needed. There's no point in using __emitline in these cases since the debugger
|
||||||
|
// can't trace into single-line functions anyway.
|
||||||
//
|
//
|
||||||
#ifdef PCSX2_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
# define __emitinline
|
# define __emitinline
|
||||||
#else
|
#else
|
||||||
# define __emitinline __forceinline
|
# define __emitinline __forceinline
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# define __noinline __declspec(noinline)
|
|
||||||
#else
|
|
||||||
# define __noinline __attribute__((noinline))
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ModRM 'mod' field enumeration. Provided mostly for reference:
|
// ModRM 'mod' field enumeration. Provided mostly for reference:
|
||||||
|
@ -195,6 +195,8 @@ namespace x86Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// iRegister
|
||||||
|
// Unless templating some fancy stuff, use the friendly iRegister32/16/8 typedefs instead.
|
||||||
//
|
//
|
||||||
template< typename OperandType >
|
template< typename OperandType >
|
||||||
class iRegister
|
class iRegister
|
||||||
|
@ -213,6 +215,9 @@ namespace x86Emitter
|
||||||
|
|
||||||
// Returns true if the register is a valid accumulator: Eax, Ax, Al.
|
// Returns true if the register is a valid accumulator: Eax, Ax, Al.
|
||||||
bool IsAccumulator() const { return Id == 0; }
|
bool IsAccumulator() const { return Id == 0; }
|
||||||
|
|
||||||
|
// returns true if the register is a valid MMX or XMM register.
|
||||||
|
bool IsSIMD() const { return OperandSize == 8 || OperandSize == 16; }
|
||||||
|
|
||||||
bool operator==( const iRegister<OperandType>& src ) const
|
bool operator==( const iRegister<OperandType>& src ) const
|
||||||
{
|
{
|
||||||
|
@ -230,6 +235,28 @@ namespace x86Emitter
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
template< typename OperandType >
|
||||||
|
class iRegisterSIMD : public iRegister<OperandType>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const iRegisterSIMD Empty; // defined as an empty/unused value (-1)
|
||||||
|
|
||||||
|
public:
|
||||||
|
iRegisterSIMD(): iRegister<OperandType>() {}
|
||||||
|
iRegisterSIMD( const iRegisterSIMD& src ) : iRegister<OperandType>( src.Id ) {}
|
||||||
|
iRegisterSIMD( const iRegister<OperandType>& src ) : iRegister<OperandType>( src ) {}
|
||||||
|
explicit iRegisterSIMD( int regId ) : iRegister<OperandType>( regId ) {}
|
||||||
|
|
||||||
|
iRegisterSIMD<OperandType>& operator=( const iRegisterSIMD<OperandType>& src )
|
||||||
|
{
|
||||||
|
Id = src.Id;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Note: GCC parses templates ahead of time apparently as a 'favor' to the programmer, which
|
// Note: GCC parses templates ahead of time apparently as a 'favor' to the programmer, which
|
||||||
|
@ -239,9 +266,11 @@ namespace x86Emitter
|
||||||
// all about the the templated code in haphazard fashion. Yay.. >_<
|
// all about the the templated code in haphazard fashion. Yay.. >_<
|
||||||
//
|
//
|
||||||
|
|
||||||
typedef iRegister<u32> iRegister32;
|
typedef iRegisterSIMD<u128> iRegisterXMM;
|
||||||
typedef iRegister<u16> iRegister16;
|
typedef iRegisterSIMD<u64> iRegisterMMX;
|
||||||
typedef iRegister<u8> iRegister8;
|
typedef iRegister<u32> iRegister32;
|
||||||
|
typedef iRegister<u16> iRegister16;
|
||||||
|
typedef iRegister<u8> iRegister8;
|
||||||
|
|
||||||
class iRegisterCL : public iRegister8
|
class iRegisterCL : public iRegister8
|
||||||
{
|
{
|
||||||
|
@ -249,6 +278,14 @@ namespace x86Emitter
|
||||||
iRegisterCL(): iRegister8( 1 ) {}
|
iRegisterCL(): iRegister8( 1 ) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const iRegisterXMM
|
||||||
|
xmm0, xmm1, xmm2, xmm3,
|
||||||
|
xmm4, xmm5, xmm6, xmm7;
|
||||||
|
|
||||||
|
extern const iRegisterMMX
|
||||||
|
mm0, mm1, mm2, mm3,
|
||||||
|
mm4, mm5, mm6, mm7;
|
||||||
|
|
||||||
extern const iRegister32
|
extern const iRegister32
|
||||||
eax, ebx, ecx, edx,
|
eax, ebx, ecx, edx,
|
||||||
esi, edi, ebp, esp;
|
esi, edi, ebp, esp;
|
||||||
|
@ -266,6 +303,7 @@ namespace x86Emitter
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Use 32 bit registers as out index register (for ModSib memory address calculations)
|
// Use 32 bit registers as out index register (for ModSib memory address calculations)
|
||||||
// Only x86IndexReg provides operators for constructing iAddressInfo types.
|
// Only x86IndexReg provides operators for constructing iAddressInfo types.
|
||||||
|
//
|
||||||
class x86IndexReg : public iRegister32
|
class x86IndexReg : public iRegister32
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -313,9 +351,9 @@ namespace x86Emitter
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline explicit iAddressInfo( const x86IndexReg& base, int displacement=0 ) :
|
__forceinline explicit iAddressInfo( const x86IndexReg& index, int displacement=0 ) :
|
||||||
Base( base ),
|
Base(),
|
||||||
Index(),
|
Index( index ),
|
||||||
Factor(0),
|
Factor(0),
|
||||||
Displacement( displacement )
|
Displacement( displacement )
|
||||||
{
|
{
|
||||||
|
@ -349,13 +387,6 @@ namespace x86Emitter
|
||||||
__forceinline iAddressInfo operator-( s32 imm ) const { return iAddressInfo( *this ).Add( -imm ); }
|
__forceinline iAddressInfo operator-( s32 imm ) const { return iAddressInfo( *this ).Add( -imm ); }
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OperandSizeType
|
|
||||||
{
|
|
||||||
OpSize_8 = 1,
|
|
||||||
OpSize_16 = 2,
|
|
||||||
OpSize_32 = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// ModSib - Internal low-level representation of the ModRM/SIB information.
|
// ModSib - Internal low-level representation of the ModRM/SIB information.
|
||||||
//
|
//
|
||||||
|
@ -422,9 +453,9 @@ namespace x86Emitter
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// x86IndexerType - This is a static class which provisions our ptr[] syntax.
|
// iAddressIndexerBase - This is a static class which provisions our ptr[] syntax.
|
||||||
//
|
//
|
||||||
struct x86IndexerType
|
struct iAddressIndexerBase
|
||||||
{
|
{
|
||||||
// passthrough instruction, allows ModSib to pass silently through ptr translation
|
// passthrough instruction, allows ModSib to pass silently through ptr translation
|
||||||
// without doing anything and without compiler error.
|
// without doing anything and without compiler error.
|
||||||
|
@ -450,7 +481,7 @@ namespace x86Emitter
|
||||||
return ModSibBase( (uptr)src );
|
return ModSibBase( (uptr)src );
|
||||||
}
|
}
|
||||||
|
|
||||||
x86IndexerType() {} // applease the GCC gods
|
iAddressIndexerBase() {} // appease the GCC gods
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -458,7 +489,7 @@ namespace x86Emitter
|
||||||
// specification of the operand size for ImmToMem operations.
|
// specification of the operand size for ImmToMem operations.
|
||||||
//
|
//
|
||||||
template< typename OperandType >
|
template< typename OperandType >
|
||||||
struct x86IndexerTypeExplicit
|
struct iAddressIndexer
|
||||||
{
|
{
|
||||||
static const uint OperandSize = sizeof( OperandType );
|
static const uint OperandSize = sizeof( OperandType );
|
||||||
|
|
||||||
|
@ -486,13 +517,15 @@ namespace x86Emitter
|
||||||
return ModSibStrict<OperandType>( (uptr)src );
|
return ModSibStrict<OperandType>( (uptr)src );
|
||||||
}
|
}
|
||||||
|
|
||||||
x86IndexerTypeExplicit() {} // GCC initialization dummy
|
iAddressIndexer() {} // GCC initialization dummy
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const x86IndexerType ptr;
|
// ptr[] - use this form for instructions which can resolve the address operand size from
|
||||||
extern const x86IndexerTypeExplicit<u32> ptr32;
|
// the other register operand sizes.
|
||||||
extern const x86IndexerTypeExplicit<u16> ptr16;
|
extern const iAddressIndexerBase ptr;
|
||||||
extern const x86IndexerTypeExplicit<u8> ptr8;
|
extern const iAddressIndexer<u32> ptr32; // explicitly typed addressing, usually needed for '[dest],imm' instruction forms
|
||||||
|
extern const iAddressIndexer<u16> ptr16; // explicitly typed addressing, usually needed for '[dest],imm' instruction forms
|
||||||
|
extern const iAddressIndexer<u8> ptr8; // explicitly typed addressing, usually needed for '[dest],imm' instruction forms
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// JccComparisonType - enumerated possibilities for inspired code branching!
|
// JccComparisonType - enumerated possibilities for inspired code branching!
|
||||||
|
@ -533,64 +566,67 @@ namespace x86Emitter
|
||||||
// as per the measured displacement distance. If the displacement is a valid s8, then
|
// as per the measured displacement distance. If the displacement is a valid s8, then
|
||||||
// a j8 is inserted, else a j32.
|
// a j8 is inserted, else a j32.
|
||||||
//
|
//
|
||||||
// Performance Analysis: j8's use 4 less byes per opcode, and thus can provide
|
// Note: This class is inherently unsafe, and so it's recommended to use iForwardJump8/32
|
||||||
// minor speed benefits in the form of L1/L2 cache clutter. They're also notably faster
|
// whenever it is known that the jump destination is (or is not) short. Only use
|
||||||
// on P4's, and mildly faster on AMDs. (Core2's and i7's don't care)
|
// iSmartJump in cases where it's unknown what jump encoding will be ideal.
|
||||||
//
|
//
|
||||||
class iSmartJump
|
// Important: Use this tool with caution! iSmartJump cannot be used in cases where jump
|
||||||
|
// targets overlap, since the writeback of the second target will alter the position of
|
||||||
|
// the first target (which breaks the relative addressing). To assist in avoiding such
|
||||||
|
// errors, iSmartJump works based on C++ block scope, where the destruction of the
|
||||||
|
// iSmartJump object (invoked by a '}') signals the target of the jump. Example:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// iCMP( EAX, ECX );
|
||||||
|
// iSmartJump jumpTo( Jcc_Above );
|
||||||
|
// [... conditional code ...]
|
||||||
|
// } // smartjump targets this spot.
|
||||||
|
//
|
||||||
|
// No code inside the scope can attempt to jump outside the scoped block (unless the jump
|
||||||
|
// uses an immediate addressing method, such as Register or Mod/RM forms of JMP/CALL).
|
||||||
|
// Multiple SmartJumps can be safely nested inside scopes, as long as they are properly
|
||||||
|
// scoped themselves.
|
||||||
|
//
|
||||||
|
// Performance Analysis: j8's use 4 less byes per opcode, and thus can provide minor
|
||||||
|
// speed benefits in the form of L1/L2 cache clutter, on any CPU. They're also notably
|
||||||
|
// faster on P4's, and mildly faster on AMDs. (Core2's and i7's don't care)
|
||||||
|
//
|
||||||
|
class iSmartJump : public NoncopyableObject
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
u8* m_target; // x86Ptr target address of this label
|
|
||||||
u8* m_baseptr; // base address of the instruction (passed to the instruction emitter)
|
u8* m_baseptr; // base address of the instruction (passed to the instruction emitter)
|
||||||
JccComparisonType m_cc; // comparison type of the instruction
|
JccComparisonType m_cc; // comparison type of the instruction
|
||||||
bool m_written; // set true when the jump is written (at which point the object becomes invalid)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
const int GetMaxInstructionSize() const
|
const int GetMaxInstructionSize() const
|
||||||
{
|
{
|
||||||
jASSUME( m_cc != Jcc_Unknown );
|
jASSUME( m_cc != Jcc_Unknown );
|
||||||
return ( m_cc == Jcc_Unconditional ) ? 5 : 6;
|
return ( m_cc == Jcc_Unconditional ) ? 5 : 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a backward jump label which will be passed into a Jxx instruction (or few!)
|
JccComparisonType GetCondition() const { return m_cc; }
|
||||||
// later on, and the current x86Ptr is recorded as the target [thus making the class
|
virtual ~iSmartJump();
|
||||||
// creation point the jump target].
|
|
||||||
iSmartJump()
|
|
||||||
{
|
|
||||||
m_target = iGetPtr();
|
|
||||||
m_baseptr = NULL;
|
|
||||||
m_cc = Jcc_Unknown;
|
|
||||||
m_written = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
// ccType - Comparison type to be written back to the jump instruction position.
|
// ccType - Comparison type to be written back to the jump instruction position.
|
||||||
//
|
//
|
||||||
iSmartJump( JccComparisonType ccType )
|
iSmartJump( JccComparisonType ccType )
|
||||||
{
|
{
|
||||||
jASSUME( ccType != Jcc_Unknown );
|
jASSUME( ccType != Jcc_Unknown );
|
||||||
m_target = NULL;
|
|
||||||
m_baseptr = iGetPtr();
|
m_baseptr = iGetPtr();
|
||||||
m_cc = ccType;
|
m_cc = ccType;
|
||||||
m_written = false;
|
|
||||||
iAdvancePtr( GetMaxInstructionSize() );
|
iAdvancePtr( GetMaxInstructionSize() );
|
||||||
}
|
}
|
||||||
|
|
||||||
JccComparisonType GetCondition() const
|
protected:
|
||||||
{
|
|
||||||
return m_cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8* GetTarget() const
|
|
||||||
{
|
|
||||||
return m_target;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTarget();
|
void SetTarget();
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
// iForwardJump
|
||||||
|
// Primary use of this class is through the various iForwardJA8/iForwardJLE32/etc. helpers
|
||||||
|
// defined later in this header. :)
|
||||||
|
//
|
||||||
template< typename OperandType >
|
template< typename OperandType >
|
||||||
class iForwardJump
|
class iForwardJump
|
||||||
{
|
{
|
||||||
|
@ -601,8 +637,13 @@ namespace x86Emitter
|
||||||
// relative to this address.
|
// relative to this address.
|
||||||
s8* const BasePtr;
|
s8* const BasePtr;
|
||||||
|
|
||||||
public:
|
// The jump instruction is emitted at the point of object construction. The conditional
|
||||||
|
// type must be valid (Jcc_Unknown generates an assertion).
|
||||||
iForwardJump( JccComparisonType cctype = Jcc_Unconditional );
|
iForwardJump( JccComparisonType cctype = Jcc_Unconditional );
|
||||||
|
|
||||||
|
// Sets the jump target by writing back the current x86Ptr to the jump instruction.
|
||||||
|
// This method can be called multiple times, re-writing the jump instruction's target
|
||||||
|
// in each case. (the the last call is the one that takes effect).
|
||||||
void SetTarget() const;
|
void SetTarget() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -627,116 +668,12 @@ namespace x86Emitter
|
||||||
#include "implement/incdec.h"
|
#include "implement/incdec.h"
|
||||||
#include "implement/bittest.h"
|
#include "implement/bittest.h"
|
||||||
#include "implement/test.h"
|
#include "implement/test.h"
|
||||||
|
#include "implement/jmpcall.h"
|
||||||
|
#include "implement/xmm/movqss.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// ----- Group 1 Instruction Class -----
|
|
||||||
|
|
||||||
extern const Internal::Group1ImplAll<Internal::G1Type_ADD> iADD;
|
|
||||||
extern const Internal::Group1ImplAll<Internal::G1Type_OR> iOR;
|
|
||||||
extern const Internal::Group1ImplAll<Internal::G1Type_ADC> iADC;
|
|
||||||
extern const Internal::Group1ImplAll<Internal::G1Type_SBB> iSBB;
|
|
||||||
extern const Internal::Group1ImplAll<Internal::G1Type_AND> iAND;
|
|
||||||
extern const Internal::Group1ImplAll<Internal::G1Type_SUB> iSUB;
|
|
||||||
extern const Internal::Group1ImplAll<Internal::G1Type_XOR> iXOR;
|
|
||||||
extern const Internal::Group1ImplAll<Internal::G1Type_CMP> iCMP;
|
|
||||||
|
|
||||||
// ----- Group 2 Instruction Class -----
|
|
||||||
// Optimization Note: For Imm forms, we ignore the instruction if the shift count is
|
|
||||||
// zero. This is a safe optimization since any zero-value shift does not affect any
|
|
||||||
// flags.
|
|
||||||
|
|
||||||
extern const Internal::MovImplAll iMOV;
|
|
||||||
extern const Internal::TestImplAll iTEST;
|
|
||||||
|
|
||||||
extern const Internal::Group2ImplAll<Internal::G2Type_ROL> iROL;
|
|
||||||
extern const Internal::Group2ImplAll<Internal::G2Type_ROR> iROR;
|
|
||||||
extern const Internal::Group2ImplAll<Internal::G2Type_RCL> iRCL;
|
|
||||||
extern const Internal::Group2ImplAll<Internal::G2Type_RCR> iRCR;
|
|
||||||
extern const Internal::Group2ImplAll<Internal::G2Type_SHL> iSHL;
|
|
||||||
extern const Internal::Group2ImplAll<Internal::G2Type_SHR> iSHR;
|
|
||||||
extern const Internal::Group2ImplAll<Internal::G2Type_SAR> iSAR;
|
|
||||||
|
|
||||||
// ----- Group 3 Instruction Class -----
|
|
||||||
|
|
||||||
extern const Internal::Group3ImplAll<Internal::G3Type_NOT> iNOT;
|
|
||||||
extern const Internal::Group3ImplAll<Internal::G3Type_NEG> iNEG;
|
|
||||||
extern const Internal::Group3ImplAll<Internal::G3Type_MUL> iUMUL;
|
|
||||||
extern const Internal::Group3ImplAll<Internal::G3Type_DIV> iUDIV;
|
|
||||||
extern const Internal::Group3ImplAll<Internal::G3Type_iDIV> iSDIV;
|
|
||||||
|
|
||||||
extern const Internal::IncDecImplAll<false> iINC;
|
|
||||||
extern const Internal::IncDecImplAll<true> iDEC;
|
|
||||||
|
|
||||||
extern const Internal::MovExtendImplAll<false> iMOVZX;
|
|
||||||
extern const Internal::MovExtendImplAll<true> iMOVSX;
|
|
||||||
|
|
||||||
extern const Internal::DwordShiftImplAll<false> iSHLD;
|
|
||||||
extern const Internal::DwordShiftImplAll<true> iSHRD;
|
|
||||||
|
|
||||||
extern const Internal::Group8ImplAll<Internal::G8Type_BT> iBT;
|
|
||||||
extern const Internal::Group8ImplAll<Internal::G8Type_BTR> iBTR;
|
|
||||||
extern const Internal::Group8ImplAll<Internal::G8Type_BTS> iBTS;
|
|
||||||
extern const Internal::Group8ImplAll<Internal::G8Type_BTC> iBTC;
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
extern const Internal::CMovImplGeneric iCMOV;
|
|
||||||
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Above> iCMOVA;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_AboveOrEqual> iCMOVAE;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Below> iCMOVB;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_BelowOrEqual> iCMOVBE;
|
|
||||||
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Greater> iCMOVG;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_GreaterOrEqual> iCMOVGE;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Less> iCMOVL;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_LessOrEqual> iCMOVLE;
|
|
||||||
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Zero> iCMOVZ;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Equal> iCMOVE;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_NotZero> iCMOVNZ;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_NotEqual> iCMOVNE;
|
|
||||||
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Overflow> iCMOVO;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_NotOverflow> iCMOVNO;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Carry> iCMOVC;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_NotCarry> iCMOVNC;
|
|
||||||
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Signed> iCMOVS;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_Unsigned> iCMOVNS;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_ParityEven> iCMOVPE;
|
|
||||||
extern const Internal::CMovImplAll<Jcc_ParityOdd> iCMOVPO;
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
extern const Internal::SetImplGeneric iSET;
|
|
||||||
|
|
||||||
extern const Internal::SetImplAll<Jcc_Above> iSETA;
|
|
||||||
extern const Internal::SetImplAll<Jcc_AboveOrEqual> iSETAE;
|
|
||||||
extern const Internal::SetImplAll<Jcc_Below> iSETB;
|
|
||||||
extern const Internal::SetImplAll<Jcc_BelowOrEqual> iSETBE;
|
|
||||||
|
|
||||||
extern const Internal::SetImplAll<Jcc_Greater> iSETG;
|
|
||||||
extern const Internal::SetImplAll<Jcc_GreaterOrEqual> iSETGE;
|
|
||||||
extern const Internal::SetImplAll<Jcc_Less> iSETL;
|
|
||||||
extern const Internal::SetImplAll<Jcc_LessOrEqual> iSETLE;
|
|
||||||
|
|
||||||
extern const Internal::SetImplAll<Jcc_Zero> iSETZ;
|
|
||||||
extern const Internal::SetImplAll<Jcc_Equal> iSETE;
|
|
||||||
extern const Internal::SetImplAll<Jcc_NotZero> iSETNZ;
|
|
||||||
extern const Internal::SetImplAll<Jcc_NotEqual> iSETNE;
|
|
||||||
|
|
||||||
extern const Internal::SetImplAll<Jcc_Overflow> iSETO;
|
|
||||||
extern const Internal::SetImplAll<Jcc_NotOverflow> iSETNO;
|
|
||||||
extern const Internal::SetImplAll<Jcc_Carry> iSETC;
|
|
||||||
extern const Internal::SetImplAll<Jcc_NotCarry> iSETNC;
|
|
||||||
|
|
||||||
extern const Internal::SetImplAll<Jcc_Signed> iSETS;
|
|
||||||
extern const Internal::SetImplAll<Jcc_Unsigned> iSETNS;
|
|
||||||
extern const Internal::SetImplAll<Jcc_ParityEven> iSETPE;
|
|
||||||
extern const Internal::SetImplAll<Jcc_ParityOdd> iSETPO;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "ix86_inlines.inl"
|
#include "ix86_inlines.inl"
|
||||||
|
|
Loading…
Reference in New Issue