2015-05-24 06:55:12 +02:00
// Copyright 2008 Dolphin Emulator Project
2015-05-18 01:08:10 +02:00
// Licensed under GPLv2+
2013-04-17 23:09:55 -04:00
// Refer to the license.txt file included.
2008-12-19 21:24:52 +00:00
2013-10-26 11:55:41 +02:00
#include <cinttypes>
2015-08-21 17:57:35 -04:00
#include <cstring>
2013-10-26 11:55:41 +02:00
2014-09-07 20:06:58 -05:00
#include "Common/CommonTypes.h"
2014-02-17 05:18:15 -05:00
#include "Common/CPUDetect.h"
#include "Common/x64Emitter.h"
2014-06-05 19:29:54 -04:00
#include "Common/Logging/Log.h"
2014-02-17 05:18:15 -05:00
2008-12-08 05:30:24 +00:00
namespace Gen
{
2008-12-19 21:24:52 +00:00
// TODO(ector): Add EAX special casing, for ever so slightly smaller code.
struct NormalOpDef
{
2014-09-02 02:11:24 -07:00
u8 toRm8 , toRm32 , fromRm8 , fromRm32 , imm8 , imm32 , simm8 , eaximm8 , eaximm32 , ext ;
2008-12-19 21:24:52 +00:00
};
2014-08-06 16:36:53 -04:00
// 0xCC is code for invalid combination of immediates
2014-09-02 02:11:24 -07:00
static const NormalOpDef normalops [ 11 ] =
2008-12-19 21:24:52 +00:00
{
2014-09-02 02:11:24 -07:00
{ 0x00 , 0x01 , 0x02 , 0x03 , 0x80 , 0x81 , 0x83 , 0x04 , 0x05 , 0 }, //ADD
{ 0x10 , 0x11 , 0x12 , 0x13 , 0x80 , 0x81 , 0x83 , 0x14 , 0x15 , 2 }, //ADC
2008-12-19 21:24:52 +00:00
2014-09-02 02:11:24 -07:00
{ 0x28 , 0x29 , 0x2A , 0x2B , 0x80 , 0x81 , 0x83 , 0x2C , 0x2D , 5 }, //SUB
{ 0x18 , 0x19 , 0x1A , 0x1B , 0x80 , 0x81 , 0x83 , 0x1C , 0x1D , 3 }, //SBB
2008-12-19 21:24:52 +00:00
2014-09-02 02:11:24 -07:00
{ 0x20 , 0x21 , 0x22 , 0x23 , 0x80 , 0x81 , 0x83 , 0x24 , 0x25 , 4 }, //AND
{ 0x08 , 0x09 , 0x0A , 0x0B , 0x80 , 0x81 , 0x83 , 0x0C , 0x0D , 1 }, //OR
2008-12-19 21:24:52 +00:00
2014-09-02 02:11:24 -07:00
{ 0x30 , 0x31 , 0x32 , 0x33 , 0x80 , 0x81 , 0x83 , 0x34 , 0x35 , 6 }, //XOR
{ 0x88 , 0x89 , 0x8A , 0x8B , 0xC6 , 0xC7 , 0xCC , 0xCC , 0xCC , 0 }, //MOV
2008-12-19 21:24:52 +00:00
2014-09-02 02:11:24 -07:00
{ 0x84 , 0x85 , 0x84 , 0x85 , 0xF6 , 0xF7 , 0xCC , 0xA8 , 0xA9 , 0 }, //TEST (to == from)
{ 0x38 , 0x39 , 0x3A , 0x3B , 0x80 , 0x81 , 0x83 , 0x3C , 0x3D , 7 }, //CMP
2008-12-19 21:24:52 +00:00
2014-09-02 02:11:24 -07:00
{ 0x86 , 0x87 , 0x86 , 0x87 , 0xCC , 0xCC , 0xCC , 0xCC , 0xCC , 7 }, //XCHG
2008-12-19 21:24:52 +00:00
};
enum NormalSSEOps
{
2013-09-18 07:43:31 -04:00
sseCMP = 0xC2 ,
sseADD = 0x58 , //ADD
sseSUB = 0x5C , //SUB
sseAND = 0x54 , //AND
sseANDN = 0x55 , //ANDN
sseOR = 0x56 ,
sseXOR = 0x57 ,
sseMUL = 0x59 , //MUL
sseDIV = 0x5E , //DIV
sseMIN = 0x5D , //MIN
sseMAX = 0x5F , //MAX
sseCOMIS = 0x2F , //COMIS
sseUCOMIS = 0x2E , //UCOMIS
sseSQRT = 0x51 , //SQRT
sseRSQRT = 0x52 , //RSQRT (NO DOUBLE PRECISION!!!)
2008-12-19 21:24:52 +00:00
sseMOVAPfromRM = 0x28 , //MOVAP from RM
2013-09-18 07:43:31 -04:00
sseMOVAPtoRM = 0x29 , //MOVAP to RM
2008-12-19 21:24:52 +00:00
sseMOVUPfromRM = 0x10 , //MOVUP from RM
2013-09-18 07:43:31 -04:00
sseMOVUPtoRM = 0x11 , //MOVUP to RM
2015-01-07 11:09:51 +01:00
sseMOVLPfromRM = 0x12 ,
sseMOVLPtoRM = 0x13 ,
sseMOVHPfromRM = 0x16 ,
sseMOVHPtoRM = 0x17 ,
2014-09-18 03:57:13 -07:00
sseMOVHLPS = 0x12 ,
sseMOVLHPS = 0x16 ,
2014-10-10 17:56:17 +02:00
sseMOVDQfromRM = 0x6F ,
sseMOVDQtoRM = 0x7F ,
2013-09-18 07:43:31 -04:00
sseMASKMOVDQU = 0xF7 ,
sseLDDQU = 0xF0 ,
sseSHUF = 0xC6 ,
2008-12-19 21:24:52 +00:00
sseMOVNTDQ = 0xE7 ,
sseMOVNTP = 0x2B ,
};
2015-05-28 21:45:39 -04:00
void XEmitter :: SetCodePtr ( u8 * ptr )
2010-01-16 19:01:00 +00:00
{
code = ptr ;
}
2008-12-08 05:30:24 +00:00
2015-05-28 21:45:39 -04:00
const u8 * XEmitter :: GetCodePtr () const
2010-01-16 19:01:00 +00:00
{
return code ;
}
2008-12-08 05:30:24 +00:00
2015-05-28 21:45:39 -04:00
u8 * XEmitter :: GetWritableCodePtr ()
2010-01-16 19:01:00 +00:00
{
return code ;
}
2008-12-08 05:30:24 +00:00
2015-08-21 17:57:35 -04:00
void XEmitter :: Write8 ( u8 value )
{
* code ++ = value ;
}
void XEmitter :: Write16 ( u16 value )
{
std :: memcpy ( code , & value , sizeof ( u16 ));
code += sizeof ( u16 );
}
void XEmitter :: Write32 ( u32 value )
{
std :: memcpy ( code , & value , sizeof ( u32 ));
code += sizeof ( u32 );
}
void XEmitter :: Write64 ( u64 value )
{
std :: memcpy ( code , & value , sizeof ( u64 ));
code += sizeof ( u64 );
}
2010-01-16 19:01:00 +00:00
void XEmitter :: ReserveCodeSpace ( int bytes )
{
for ( int i = 0 ; i < bytes ; i ++ )
* code ++ = 0xCC ;
}
2008-12-08 05:30:24 +00:00
2015-05-28 21:45:39 -04:00
const u8 * XEmitter :: AlignCode4 ()
2010-01-16 19:01:00 +00:00
{
int c = int (( u64 ) code & 3 );
if ( c )
ReserveCodeSpace ( 4 - c );
return code ;
}
2008-12-08 05:30:24 +00:00
2015-05-28 21:45:39 -04:00
const u8 * XEmitter :: AlignCode16 ()
2010-01-16 19:01:00 +00:00
{
int c = int (( u64 ) code & 15 );
if ( c )
ReserveCodeSpace ( 16 - c );
return code ;
}
2008-12-08 05:30:24 +00:00
2015-05-28 21:45:39 -04:00
const u8 * XEmitter :: AlignCodePage ()
2010-01-16 19:01:00 +00:00
{
int c = int (( u64 ) code & 4095 );
if ( c )
ReserveCodeSpace ( 4096 - c );
return code ;
}
2008-12-08 05:30:24 +00:00
2014-09-26 20:40:24 -07:00
// This operation modifies flags; check to see the flags are locked.
// If the flags are locked, we should immediately and loudly fail before
// causing a subtle JIT bug.
void XEmitter :: CheckFlags ()
{
_assert_msg_ ( DYNA_REC , ! flags_locked , "Attempt to modify flags while flags locked!" );
}
2014-01-25 17:33:31 +01:00
void XEmitter :: WriteModRM ( int mod , int reg , int rm )
2010-01-16 19:01:00 +00:00
{
2014-01-25 17:33:31 +01:00
Write8 (( u8 )(( mod << 6 ) | (( reg & 7 ) << 3 ) | ( rm & 7 )));
2010-01-16 19:01:00 +00:00
}
2008-12-08 05:30:24 +00:00
2010-01-16 19:01:00 +00:00
void XEmitter :: WriteSIB ( int scale , int index , int base )
{
Write8 (( u8 )(( scale << 6 ) | (( index & 7 ) << 3 ) | ( base & 7 )));
}
2008-12-08 05:30:24 +00:00
2015-05-28 21:45:39 -04:00
void OpArg :: WriteREX ( XEmitter * emit , int opBits , int bits , int customOp ) const
2010-01-16 19:01:00 +00:00
{
2011-02-19 14:20:52 +00:00
if ( customOp == - 1 ) customOp = operandReg ;
2010-01-16 19:01:00 +00:00
u8 op = 0x40 ;
2014-03-25 13:50:14 -07:00
// REX.W (whether operation is a 64-bit operation)
2011-02-19 14:20:52 +00:00
if ( opBits == 64 ) op |= 8 ;
2014-03-25 13:50:14 -07:00
// REX.R (whether ModR/M reg field refers to R8-R15.
2011-02-19 14:20:52 +00:00
if ( customOp & 8 ) op |= 4 ;
2014-03-25 13:50:14 -07:00
// REX.X (whether ModR/M SIB index field refers to R8-R15)
2011-02-19 14:20:52 +00:00
if ( indexReg & 8 ) op |= 2 ;
2014-03-25 13:50:14 -07:00
// REX.B (whether ModR/M rm or SIB base or opcode reg field refers to R8-R15)
if ( offsetOrBaseReg & 8 ) op |= 1 ;
// Write REX if wr have REX bits to write, or if the operation accesses
// SIL, DIL, BPL, or SPL.
2011-02-19 14:20:52 +00:00
if ( op != 0x40 ||
2014-08-30 16:14:56 -04:00
( scale == SCALE_NONE && bits == 8 && ( offsetOrBaseReg & 0x10c ) == 4 ) ||
( opBits == 8 && ( customOp & 0x10c ) == 4 ))
{
2010-01-16 19:01:00 +00:00
emit -> Write8 ( op );
2014-03-25 13:50:14 -07:00
// Check the operation doesn't access AH, BH, CH, or DH.
_dbg_assert_ ( DYNA_REC , ( offsetOrBaseReg & 0x100 ) == 0 );
_dbg_assert_ ( DYNA_REC , ( customOp & 0x100 ) == 0 );
2011-02-19 14:20:52 +00:00
}
2010-01-16 19:01:00 +00:00
}
2008-12-08 05:30:24 +00:00
2015-05-17 05:38:01 +02:00
void OpArg :: WriteVEX ( XEmitter * emit , X64Reg regOp1 , X64Reg regOp2 , int L , int pp , int mmmmm , int W ) const
2013-11-04 21:37:07 +01:00
{
int R = ! ( regOp1 & 8 );
int X = ! ( indexReg & 8 );
int B = ! ( offsetOrBaseReg & 8 );
int vvvv = ( regOp2 == X64Reg :: INVALID_REG ) ? 0xf : ( regOp2 ^ 0xf );
// do we need any VEX fields that only appear in the three-byte form?
if ( X == 1 && B == 1 && W == 0 && mmmmm == 1 )
{
2015-05-20 09:33:26 +02:00
u8 RvvvvLpp = ( R << 7 ) | ( vvvv << 3 ) | ( L << 2 ) | pp ;
2013-11-04 21:37:07 +01:00
emit -> Write8 ( 0xC5 );
emit -> Write8 ( RvvvvLpp );
}
else
{
u8 RXBmmmmm = ( R << 7 ) | ( X << 6 ) | ( B << 5 ) | mmmmm ;
2015-05-20 09:33:26 +02:00
u8 WvvvvLpp = ( W << 7 ) | ( vvvv << 3 ) | ( L << 2 ) | pp ;
2013-11-04 21:37:07 +01:00
emit -> Write8 ( 0xC4 );
emit -> Write8 ( RXBmmmmm );
emit -> Write8 ( WvvvvLpp );
}
}
2015-05-28 21:45:39 -04:00
void OpArg :: WriteRest ( XEmitter * emit , int extraBytes , X64Reg _operandReg ,
2013-09-18 07:43:31 -04:00
bool warn_64bit_offset ) const
2010-01-16 19:01:00 +00:00
{
2014-08-24 17:39:30 -07:00
if ( _operandReg == INVALID_REG )
2010-01-16 19:01:00 +00:00
_operandReg = ( X64Reg ) this -> operandReg ;
int mod = 0 ;
int ireg = indexReg ;
bool SIB = false ;
int _offsetOrBaseReg = this -> offsetOrBaseReg ;
if ( scale == SCALE_RIP ) //Also, on 32-bit, just an immediate address
2008-12-08 05:30:24 +00:00
{
2011-02-19 14:20:52 +00:00
// Oh, RIP addressing.
2010-01-16 19:01:00 +00:00
_offsetOrBaseReg = 5 ;
2014-01-25 18:38:06 +01:00
emit -> WriteModRM ( 0 , _operandReg , _offsetOrBaseReg );
2010-01-16 19:01:00 +00:00
//TODO : add some checks
u64 ripAddr = ( u64 ) emit -> GetCodePtr () + 4 + extraBytes ;
2010-09-26 19:37:30 +00:00
s64 distance = ( s64 ) offset - ( s64 ) ripAddr ;
2014-03-29 11:05:44 +01:00
_assert_msg_ ( DYNA_REC ,
2014-03-11 00:30:55 +13:00
( distance < 0x80000000LL &&
distance >= - 0x80000000LL ) ||
! warn_64bit_offset ,
"WriteRest: op out of range (0x%" PRIx64 " uses 0x%" PRIx64 ")" ,
ripAddr , offset );
2010-09-26 19:37:30 +00:00
s32 offs = ( s32 ) distance ;
2010-01-16 19:01:00 +00:00
emit -> Write32 (( u32 ) offs );
return ;
}
2008-12-08 05:30:24 +00:00
2010-01-16 19:01:00 +00:00
if ( scale == 0 )
{
// Oh, no memory, Just a reg.
mod = 3 ; //11
}
2015-03-17 00:49:55 +13:00
else
2010-01-16 19:01:00 +00:00
{
//Ah good, no scaling.
if ( scale == SCALE_ATREG && ! (( _offsetOrBaseReg & 7 ) == 4 || ( _offsetOrBaseReg & 7 ) == 5 ))
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
//Okay, we're good. No SIB necessary.
int ioff = ( int ) offset ;
if ( ioff == 0 )
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
mod = 0 ;
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
else if ( ioff <- 128 || ioff > 127 )
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
mod = 2 ; //32-bit displacement
}
else
{
mod = 1 ; //8-bit displacement
2008-12-08 05:30:24 +00:00
}
}
2011-06-29 22:40:01 +00:00
else if ( scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8 )
{
SIB = true ;
mod = 0 ;
_offsetOrBaseReg = 5 ;
}
2015-03-17 00:49:55 +13:00
else
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
if (( _offsetOrBaseReg & 7 ) == 4 ) //this would occupy the SIB encoding :(
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
//So we have to fake it with SIB encoding :(
SIB = true ;
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
if ( scale >= SCALE_1 && scale < SCALE_ATREG )
{
SIB = true ;
}
2013-10-29 01:23:17 -04:00
if ( scale == SCALE_ATREG && (( _offsetOrBaseReg & 7 ) == 4 ))
2010-01-16 19:01:00 +00:00
{
SIB = true ;
ireg = _offsetOrBaseReg ;
}
//Okay, we're fine. Just disp encoding.
//We need displacement. Which size?
int ioff = ( int )( s64 ) offset ;
if ( ioff < - 128 || ioff > 127 )
{
mod = 2 ; //32-bit displacement
}
else
{
mod = 1 ; //8-bit displacement
}
2008-12-08 05:30:24 +00:00
}
}
2010-01-16 19:01:00 +00:00
// Okay. Time to do the actual writing
// ModRM byte:
int oreg = _offsetOrBaseReg ;
if ( SIB )
oreg = 4 ;
2013-10-29 01:23:17 -04:00
2010-01-16 19:01:00 +00:00
emit -> WriteModRM ( mod , _operandReg & 7 , oreg & 7 );
2008-12-08 05:30:24 +00:00
2010-01-16 19:01:00 +00:00
if ( SIB )
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
//SIB byte
int ss ;
switch ( scale )
2008-12-08 05:30:24 +00:00
{
2013-10-29 01:23:17 -04:00
case SCALE_NONE : _offsetOrBaseReg = 4 ; ss = 0 ; break ; //RSP
2011-06-29 22:40:01 +00:00
case SCALE_1 : ss = 0 ; break ;
case SCALE_2 : ss = 1 ; break ;
case SCALE_4 : ss = 2 ; break ;
case SCALE_8 : ss = 3 ; break ;
case SCALE_NOBASE_2 : ss = 1 ; break ;
case SCALE_NOBASE_4 : ss = 2 ; break ;
case SCALE_NOBASE_8 : ss = 3 ; break ;
2010-01-16 19:01:00 +00:00
case SCALE_ATREG : ss = 0 ; break ;
default : _assert_msg_ ( DYNA_REC , 0 , "Invalid scale for SIB byte" ); ss = 0 ; break ;
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
emit -> Write8 (( u8 )(( ss << 6 ) | (( ireg & 7 ) << 3 ) | ( _offsetOrBaseReg & 7 )));
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
if ( mod == 1 ) //8-bit disp
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
emit -> Write8 (( u8 )( s8 )( s32 ) offset );
2008-12-08 05:30:24 +00:00
}
2011-06-29 22:40:01 +00:00
else if ( mod == 2 || ( scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8 )) //32-bit disp
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
emit -> Write32 (( u32 ) offset );
}
}
// W = operand extended width (1 if 64-bit)
// R = register# upper bit
// X = scale amnt upper bit
// B = base register# upper bit
void XEmitter :: Rex ( int w , int r , int x , int b )
{
2013-10-29 01:23:17 -04:00
w = w ? 1 : 0 ;
2010-01-16 19:01:00 +00:00
r = r ? 1 : 0 ;
x = x ? 1 : 0 ;
b = b ? 1 : 0 ;
u8 rx = ( u8 )( 0x40 | ( w << 3 ) | ( r << 2 ) | ( x << 1 ) | ( b ));
if ( rx != 0x40 )
Write8 ( rx );
}
2015-05-28 21:45:39 -04:00
void XEmitter :: JMP ( const u8 * addr , bool force5Bytes )
2010-01-16 19:01:00 +00:00
{
u64 fn = ( u64 ) addr ;
if ( ! force5Bytes )
{
2011-02-19 14:20:52 +00:00
s64 distance = ( s64 )( fn - (( u64 ) code + 2 ));
_assert_msg_ ( DYNA_REC , distance >= - 0x80 && distance < 0x80 ,
"Jump target too far away, needs force5Bytes = true" );
2010-01-16 19:01:00 +00:00
//8 bits will do
2008-12-08 05:30:24 +00:00
Write8 ( 0xEB );
2010-01-16 19:01:00 +00:00
Write8 (( u8 )( s8 ) distance );
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
else
2008-12-08 05:30:24 +00:00
{
2011-02-19 14:20:52 +00:00
s64 distance = ( s64 )( fn - (( u64 ) code + 5 ));
2010-12-16 22:38:31 +00:00
2014-03-11 00:30:55 +13:00
_assert_msg_ ( DYNA_REC ,
distance >= - 0x80000000LL && distance < 0x80000000LL ,
"Jump target too far away, needs indirect register" );
2010-01-16 19:01:00 +00:00
Write8 ( 0xE9 );
Write32 (( u32 )( s32 ) distance );
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
}
2008-12-08 05:30:24 +00:00
2015-05-28 21:45:39 -04:00
void XEmitter :: JMPptr ( const OpArg & arg2 )
2010-01-16 19:01:00 +00:00
{
OpArg arg = arg2 ;
if ( arg . IsImm ()) _assert_msg_ ( DYNA_REC , 0 , "JMPptr - Imm argument" );
arg . operandReg = 4 ;
2015-05-17 05:37:03 +02:00
arg . WriteREX ( this , 0 , 0 );
2010-01-16 19:01:00 +00:00
Write8 ( 0xFF );
arg . WriteRest ( this );
}
2008-12-08 05:30:24 +00:00
2010-01-16 19:01:00 +00:00
//Can be used to trap other processors, before overwriting their code
2015-01-11 00:17:29 -05:00
// not used in Dolphin
2010-01-16 19:01:00 +00:00
void XEmitter :: JMPself ()
{
Write8 ( 0xEB );
Write8 ( 0xFE );
}
2008-12-08 05:30:24 +00:00
2010-01-16 19:01:00 +00:00
void XEmitter :: CALLptr ( OpArg arg )
{
if ( arg . IsImm ()) _assert_msg_ ( DYNA_REC , 0 , "CALLptr - Imm argument" );
arg . operandReg = 2 ;
2015-05-17 05:37:03 +02:00
arg . WriteREX ( this , 0 , 0 );
2010-01-16 19:01:00 +00:00
Write8 ( 0xFF );
arg . WriteRest ( this );
}
2008-12-08 05:30:24 +00:00
2015-05-28 21:45:39 -04:00
void XEmitter :: CALL ( const void * fnptr )
2010-01-16 19:01:00 +00:00
{
u64 distance = u64 ( fnptr ) - ( u64 ( code ) + 5 );
2014-03-11 00:30:55 +13:00
_assert_msg_ ( DYNA_REC ,
distance < 0x0000000080000000ULL ||
distance >= 0xFFFFFFFF80000000ULL ,
"CALL out of range (%p calls %p)" , code , fnptr );
2010-01-16 19:01:00 +00:00
Write8 ( 0xE8 );
Write32 ( u32 ( distance ));
}
2008-12-08 05:30:24 +00:00
2010-01-16 19:01:00 +00:00
FixupBranch XEmitter :: J ( bool force5bytes )
{
FixupBranch branch ;
branch . type = force5bytes ? 1 : 0 ;
branch . ptr = code + ( force5bytes ? 5 : 2 );
if ( ! force5bytes )
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
//8 bits will do
Write8 ( 0xEB );
Write8 ( 0 );
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
else
{
Write8 ( 0xE9 );
Write32 ( 0 );
}
return branch ;
}
FixupBranch XEmitter :: J_CC ( CCFlags conditionCode , bool force5bytes )
{
FixupBranch branch ;
branch . type = force5bytes ? 1 : 0 ;
2010-04-11 12:27:27 +00:00
branch . ptr = code + ( force5bytes ? 6 : 2 );
2010-01-16 19:01:00 +00:00
if ( ! force5bytes )
{
//8 bits will do
Write8 ( 0x70 + conditionCode );
Write8 ( 0 );
}
else
{
Write8 ( 0x0F );
Write8 ( 0x80 + conditionCode );
Write32 ( 0 );
}
return branch ;
}
2014-06-03 22:57:17 +02:00
void XEmitter :: J_CC ( CCFlags conditionCode , const u8 * addr )
2010-01-16 19:01:00 +00:00
{
u64 fn = ( u64 ) addr ;
2014-06-03 22:57:17 +02:00
s64 distance = ( s64 )( fn - (( u64 ) code + 2 ));
if ( distance < - 0x80 || distance >= 0x80 )
2010-01-16 19:01:00 +00:00
{
2014-06-03 22:57:17 +02:00
distance = ( s64 )( fn - (( u64 ) code + 6 ));
2014-03-11 00:30:55 +13:00
_assert_msg_ ( DYNA_REC ,
distance >= - 0x80000000LL && distance < 0x80000000LL ,
2014-06-03 22:57:17 +02:00
"Jump target too far away, needs indirect register" );
2010-01-16 19:01:00 +00:00
Write8 ( 0x0F );
Write8 ( 0x80 + conditionCode );
Write32 (( u32 )( s32 ) distance );
}
2014-06-03 22:57:17 +02:00
else
{
Write8 ( 0x70 + conditionCode );
Write8 (( u8 )( s8 ) distance );
}
2010-01-16 19:01:00 +00:00
}
2015-05-28 21:45:39 -04:00
void XEmitter :: SetJumpTarget ( const FixupBranch & branch )
2010-01-16 19:01:00 +00:00
{
if ( branch . type == 0 )
{
2010-12-16 22:38:31 +00:00
s64 distance = ( s64 )( code - branch . ptr );
_assert_msg_ ( DYNA_REC , distance >= - 0x80 && distance < 0x80 , "Jump target too far away, needs force5Bytes = true" );
2010-06-30 16:17:20 +00:00
branch . ptr [ - 1 ] = ( u8 )( s8 ) distance ;
2010-01-16 19:01:00 +00:00
}
else if ( branch . type == 1 )
{
2010-12-16 22:38:31 +00:00
s64 distance = ( s64 )( code - branch . ptr );
_assert_msg_ ( DYNA_REC , distance >= - 0x80000000LL && distance < 0x80000000LL , "Jump target too far away, needs indirect register" );
(( s32 * ) branch . ptr )[ - 1 ] = ( s32 ) distance ;
2010-01-16 19:01:00 +00:00
}
}
//Single byte opcodes
//There is no PUSHAD/POPAD in 64-bit mode.
void XEmitter :: INT3 () { Write8 ( 0xCC );}
void XEmitter :: RET () { Write8 ( 0xC3 );}
void XEmitter :: RET_FAST () { Write8 ( 0xF3 ); Write8 ( 0xC3 );} //two-byte return (rep ret) - recommended by AMD optimization manual for the case of jumping to a ret
2014-04-23 21:15:09 +02:00
// The first sign of decadence: optimized NOPs.
2014-04-30 10:12:15 +02:00
void XEmitter :: NOP ( size_t size )
2010-01-16 19:01:00 +00:00
{
2014-04-30 10:12:15 +02:00
_dbg_assert_ ( DYNA_REC , ( int ) size > 0 );
2014-04-23 21:15:09 +02:00
while ( true )
{
switch ( size )
{
case 0 :
return ;
case 1 :
2008-12-08 05:30:24 +00:00
Write8 ( 0x90 );
2014-04-23 21:15:09 +02:00
return ;
case 2 :
Write8 ( 0x66 ); Write8 ( 0x90 );
return ;
case 3 :
Write8 ( 0x0F ); Write8 ( 0x1F ); Write8 ( 0x00 );
return ;
case 4 :
Write8 ( 0x0F ); Write8 ( 0x1F ); Write8 ( 0x40 ); Write8 ( 0x00 );
return ;
case 5 :
Write8 ( 0x0F ); Write8 ( 0x1F ); Write8 ( 0x44 ); Write8 ( 0x00 );
Write8 ( 0x00 );
return ;
case 6 :
Write8 ( 0x66 ); Write8 ( 0x0F ); Write8 ( 0x1F ); Write8 ( 0x44 );
Write8 ( 0x00 ); Write8 ( 0x00 );
return ;
case 7 :
Write8 ( 0x0F ); Write8 ( 0x1F ); Write8 ( 0x80 ); Write8 ( 0x00 );
Write8 ( 0x00 ); Write8 ( 0x00 ); Write8 ( 0x00 );
return ;
case 8 :
Write8 ( 0x0F ); Write8 ( 0x1F ); Write8 ( 0x84 ); Write8 ( 0x00 );
Write8 ( 0x00 ); Write8 ( 0x00 ); Write8 ( 0x00 ); Write8 ( 0x00 );
return ;
case 9 :
Write8 ( 0x66 ); Write8 ( 0x0F ); Write8 ( 0x1F ); Write8 ( 0x84 );
Write8 ( 0x00 ); Write8 ( 0x00 ); Write8 ( 0x00 ); Write8 ( 0x00 );
Write8 ( 0x00 );
return ;
case 10 :
Write8 ( 0x66 ); Write8 ( 0x66 ); Write8 ( 0x0F ); Write8 ( 0x1F );
Write8 ( 0x84 ); Write8 ( 0x00 ); Write8 ( 0x00 ); Write8 ( 0x00 );
Write8 ( 0x00 ); Write8 ( 0x00 );
return ;
default :
// Even though x86 instructions are allowed to be up to 15 bytes long,
// AMD advises against using NOPs longer than 11 bytes because they
// carry a performance penalty on CPUs older than AMD family 16h.
Write8 ( 0x66 ); Write8 ( 0x66 ); Write8 ( 0x66 ); Write8 ( 0x0F );
Write8 ( 0x1F ); Write8 ( 0x84 ); Write8 ( 0x00 ); Write8 ( 0x00 );
Write8 ( 0x00 ); Write8 ( 0x00 ); Write8 ( 0x00 );
size -= 11 ;
continue ;
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
}
2013-10-29 01:23:17 -04:00
}
2008-12-08 05:30:24 +00:00
2014-11-13 21:28:27 -05:00
void XEmitter :: PAUSE () { Write8 ( 0xF3 ); NOP ();} //use in tight spinloops for energy saving on some CPU
2014-09-26 20:40:24 -07:00
void XEmitter :: CLC () { CheckFlags (); Write8 ( 0xF8 );} //clear carry
void XEmitter :: CMC () { CheckFlags (); Write8 ( 0xF5 );} //flip carry
void XEmitter :: STC () { CheckFlags (); Write8 ( 0xF9 );} //set carry
2010-01-16 19:01:00 +00:00
//TODO: xchg ah, al ???
void XEmitter :: XCHG_AHAL ()
{
Write8 ( 0x86 );
Write8 ( 0xe0 );
// alt. 86 c4
}
//These two can not be executed on early Intel 64-bit CPU:s, only on AMD!
void XEmitter :: LAHF () { Write8 ( 0x9F );}
2014-09-26 20:40:24 -07:00
void XEmitter :: SAHF () { CheckFlags (); Write8 ( 0x9E );}
2010-01-16 19:01:00 +00:00
void XEmitter :: PUSHF () { Write8 ( 0x9C );}
2014-09-26 20:40:24 -07:00
void XEmitter :: POPF () { CheckFlags (); Write8 ( 0x9D );}
2010-01-16 19:01:00 +00:00
void XEmitter :: LFENCE () { Write8 ( 0x0F ); Write8 ( 0xAE ); Write8 ( 0xE8 );}
void XEmitter :: MFENCE () { Write8 ( 0x0F ); Write8 ( 0xAE ); Write8 ( 0xF0 );}
void XEmitter :: SFENCE () { Write8 ( 0x0F ); Write8 ( 0xAE ); Write8 ( 0xF8 );}
void XEmitter :: WriteSimple1Byte ( int bits , u8 byte , X64Reg reg )
{
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2010-01-16 19:01:00 +00:00
Rex ( bits == 64 , 0 , 0 , ( int ) reg >> 3 );
Write8 ( byte + (( int ) reg & 7 ));
}
void XEmitter :: WriteSimple2Byte ( int bits , u8 byte1 , u8 byte2 , X64Reg reg )
{
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2010-01-16 19:01:00 +00:00
Rex ( bits == 64 , 0 , 0 , ( int ) reg >> 3 );
Write8 ( byte1 );
Write8 ( byte2 + (( int ) reg & 7 ));
}
void XEmitter :: CWD ( int bits )
{
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2010-01-16 19:01:00 +00:00
Rex ( bits == 64 , 0 , 0 , 0 );
Write8 ( 0x99 );
}
void XEmitter :: CBW ( int bits )
{
2014-09-06 01:23:05 -05:00
if ( bits == 8 )
Write8 ( 0x66 );
2010-01-16 19:01:00 +00:00
Rex ( bits == 32 , 0 , 0 , 0 );
Write8 ( 0x98 );
}
//Simple opcodes
//push/pop do not need wide to be 64-bit
void XEmitter :: PUSH ( X64Reg reg ) { WriteSimple1Byte ( 32 , 0x50 , reg );}
void XEmitter :: POP ( X64Reg reg ) { WriteSimple1Byte ( 32 , 0x58 , reg );}
2015-05-28 21:45:39 -04:00
void XEmitter :: PUSH ( int bits , const OpArg & reg )
2013-10-29 01:23:17 -04:00
{
2010-01-16 19:01:00 +00:00
if ( reg . IsSimpleReg ())
PUSH ( reg . GetSimpleReg ());
else if ( reg . IsImm ())
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
switch ( reg . GetImmBits ())
2008-12-08 05:30:24 +00:00
{
case 8 :
2010-01-16 19:01:00 +00:00
Write8 ( 0x6A );
Write8 (( u8 )( s8 ) reg . offset );
2008-12-08 05:30:24 +00:00
break ;
2009-01-02 04:34:23 +00:00
case 16 :
2010-01-16 19:01:00 +00:00
Write8 ( 0x66 );
Write8 ( 0x68 );
Write16 (( u16 )( s16 )( s32 ) reg . offset );
2009-01-02 04:34:23 +00:00
break ;
2008-12-08 05:30:24 +00:00
case 32 :
2010-01-16 19:01:00 +00:00
Write8 ( 0x68 );
Write32 (( u32 ) reg . offset );
2008-12-08 05:30:24 +00:00
break ;
default :
2010-01-16 19:01:00 +00:00
_assert_msg_ ( DYNA_REC , 0 , "PUSH - Bad imm bits" );
break ;
2008-12-08 05:30:24 +00:00
}
}
2010-01-16 19:01:00 +00:00
else
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
if ( bits == 16 )
Write8 ( 0x66 );
2015-05-17 05:37:03 +02:00
reg . WriteREX ( this , bits , bits );
2010-01-16 19:01:00 +00:00
Write8 ( 0xFF );
reg . WriteRest ( this , 0 , ( X64Reg ) 6 );
}
}
2015-05-28 21:45:39 -04:00
void XEmitter :: POP ( int /*bits*/ , const OpArg & reg )
2013-10-29 01:23:17 -04:00
{
2010-01-16 19:01:00 +00:00
if ( reg . IsSimpleReg ())
POP ( reg . GetSimpleReg ());
else
2014-08-26 11:28:13 +02:00
_assert_msg_ ( DYNA_REC , 0 , "POP - Unsupported encoding" );
2010-01-16 19:01:00 +00:00
}
void XEmitter :: BSWAP ( int bits , X64Reg reg )
{
if ( bits >= 32 )
{
WriteSimple2Byte ( bits , 0x0F , 0xC8 , reg );
}
else if ( bits == 16 )
{
ROL ( 16 , R ( reg ), Imm8 ( 8 ));
}
else if ( bits == 8 )
{
// Do nothing - can't bswap a single byte...
}
else
{
_assert_msg_ ( DYNA_REC , 0 , "BSWAP - Wrong number of bits" );
}
}
// Undefined opcode - reserved
// If we ever need a way to always cause a non-breakpoint hard exception...
void XEmitter :: UD2 ()
{
Write8 ( 0x0F );
Write8 ( 0x0B );
}
void XEmitter :: PREFETCH ( PrefetchLevel level , OpArg arg )
{
2014-09-06 01:24:03 -05:00
_assert_msg_ ( DYNA_REC , ! arg . IsImm (), "PREFETCH - Imm argument" );
2010-01-16 19:01:00 +00:00
arg . operandReg = ( u8 ) level ;
2015-05-17 05:37:03 +02:00
arg . WriteREX ( this , 0 , 0 );
2010-01-16 19:01:00 +00:00
Write8 ( 0x0F );
Write8 ( 0x18 );
arg . WriteRest ( this );
}
void XEmitter :: SETcc ( CCFlags flag , OpArg dest )
{
2014-09-06 01:24:03 -05:00
_assert_msg_ ( DYNA_REC , ! dest . IsImm (), "SETcc - Imm argument" );
2010-01-16 19:01:00 +00:00
dest . operandReg = 0 ;
2015-05-17 05:37:03 +02:00
dest . WriteREX ( this , 0 , 8 );
2010-01-16 19:01:00 +00:00
Write8 ( 0x0F );
Write8 ( 0x90 + ( u8 ) flag );
dest . WriteRest ( this );
}
void XEmitter :: CMOVcc ( int bits , X64Reg dest , OpArg src , CCFlags flag )
{
2014-09-06 01:24:03 -05:00
_assert_msg_ ( DYNA_REC , ! src . IsImm (), "CMOVcc - Imm argument" );
_assert_msg_ ( DYNA_REC , bits != 8 , "CMOVcc - 8 bits unsupported" );
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2010-01-16 19:01:00 +00:00
src . operandReg = dest ;
2015-05-17 05:37:03 +02:00
src . WriteREX ( this , bits , bits );
2010-01-16 19:01:00 +00:00
Write8 ( 0x0F );
Write8 ( 0x40 + ( u8 ) flag );
src . WriteRest ( this );
}
void XEmitter :: WriteMulDivType ( int bits , OpArg src , int ext )
{
2014-09-06 01:24:03 -05:00
_assert_msg_ ( DYNA_REC , ! src . IsImm (), "WriteMulDivType - Imm argument" );
2014-09-26 20:40:24 -07:00
CheckFlags ();
2010-01-16 19:01:00 +00:00
src . operandReg = ext ;
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2015-05-17 05:37:03 +02:00
src . WriteREX ( this , bits , bits , 0 );
2010-01-16 19:01:00 +00:00
if ( bits == 8 )
{
Write8 ( 0xF6 );
}
2011-02-19 14:20:52 +00:00
else
2010-01-16 19:01:00 +00:00
{
Write8 ( 0xF7 );
}
src . WriteRest ( this );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: MUL ( int bits , const OpArg & src ) { WriteMulDivType ( bits , src , 4 );}
void XEmitter :: DIV ( int bits , const OpArg & src ) { WriteMulDivType ( bits , src , 6 );}
void XEmitter :: IMUL ( int bits , const OpArg & src ) { WriteMulDivType ( bits , src , 5 );}
void XEmitter :: IDIV ( int bits , const OpArg & src ) { WriteMulDivType ( bits , src , 7 );}
void XEmitter :: NEG ( int bits , const OpArg & src ) { WriteMulDivType ( bits , src , 3 );}
void XEmitter :: NOT ( int bits , const OpArg & src ) { WriteMulDivType ( bits , src , 2 );}
2010-01-16 19:01:00 +00:00
2014-09-14 05:31:22 -07:00
void XEmitter :: WriteBitSearchType ( int bits , X64Reg dest , OpArg src , u8 byte2 , bool rep )
2010-01-16 19:01:00 +00:00
{
2014-09-06 01:24:03 -05:00
_assert_msg_ ( DYNA_REC , ! src . IsImm (), "WriteBitSearchType - Imm argument" );
2014-09-26 20:40:24 -07:00
CheckFlags ();
2010-01-16 19:01:00 +00:00
src . operandReg = ( u8 ) dest ;
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2014-09-14 05:31:22 -07:00
if ( rep )
Write8 ( 0xF3 );
2015-05-17 05:37:03 +02:00
src . WriteREX ( this , bits , bits );
2010-01-16 19:01:00 +00:00
Write8 ( 0x0F );
Write8 ( byte2 );
src . WriteRest ( this );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVNTI ( int bits , const OpArg & dest , X64Reg src )
2010-01-16 19:01:00 +00:00
{
2014-09-06 01:23:05 -05:00
if ( bits <= 16 )
_assert_msg_ ( DYNA_REC , 0 , "MOVNTI - bits<=16" );
2010-01-16 19:01:00 +00:00
WriteBitSearchType ( bits , src , dest , 0xC3 );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: BSF ( int bits , X64Reg dest , const OpArg & src ) { WriteBitSearchType ( bits , dest , src , 0xBC );} // Bottom bit to top bit
void XEmitter :: BSR ( int bits , X64Reg dest , const OpArg & src ) { WriteBitSearchType ( bits , dest , src , 0xBD );} // Top bit to bottom bit
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: TZCNT ( int bits , X64Reg dest , const OpArg & src )
2014-09-14 05:31:22 -07:00
{
2014-09-26 20:40:24 -07:00
CheckFlags ();
2014-09-14 05:31:22 -07:00
if ( ! cpu_info . bBMI1 )
PanicAlert ( "Trying to use BMI1 on a system that doesn't support it. Bad programmer." );
WriteBitSearchType ( bits , dest , src , 0xBC , true );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: LZCNT ( int bits , X64Reg dest , const OpArg & src )
2014-09-14 05:31:22 -07:00
{
2014-09-26 20:40:24 -07:00
CheckFlags ();
2014-09-14 05:31:22 -07:00
if ( ! cpu_info . bLZCNT )
PanicAlert ( "Trying to use LZCNT on a system that doesn't support it. Bad programmer." );
WriteBitSearchType ( bits , dest , src , 0xBD , true );
}
2010-01-16 19:01:00 +00:00
void XEmitter :: MOVSX ( int dbits , int sbits , X64Reg dest , OpArg src )
{
2014-09-06 01:24:03 -05:00
_assert_msg_ ( DYNA_REC , ! src . IsImm (), "MOVSX - Imm argument" );
2014-08-30 16:14:56 -04:00
if ( dbits == sbits )
{
2010-01-16 19:01:00 +00:00
MOV ( dbits , R ( dest ), src );
return ;
}
src . operandReg = ( u8 ) dest ;
2014-09-06 01:23:05 -05:00
if ( dbits == 16 )
Write8 ( 0x66 );
2015-05-17 05:37:03 +02:00
src . WriteREX ( this , dbits , sbits );
2010-01-16 19:01:00 +00:00
if ( sbits == 8 )
{
Write8 ( 0x0F );
Write8 ( 0xBE );
}
else if ( sbits == 16 )
{
Write8 ( 0x0F );
Write8 ( 0xBF );
}
else if ( sbits == 32 && dbits == 64 )
{
Write8 ( 0x63 );
}
else
{
Crash ();
}
src . WriteRest ( this );
}
void XEmitter :: MOVZX ( int dbits , int sbits , X64Reg dest , OpArg src )
{
2014-09-06 01:24:03 -05:00
_assert_msg_ ( DYNA_REC , ! src . IsImm (), "MOVZX - Imm argument" );
2014-08-30 16:14:56 -04:00
if ( dbits == sbits )
{
2010-01-16 19:01:00 +00:00
MOV ( dbits , R ( dest ), src );
return ;
}
src . operandReg = ( u8 ) dest ;
2014-09-06 01:23:05 -05:00
if ( dbits == 16 )
Write8 ( 0x66 );
2011-02-19 14:20:52 +00:00
//the 32bit result is automatically zero extended to 64bit
2015-05-17 05:37:03 +02:00
src . WriteREX ( this , dbits == 64 ? 32 : dbits , sbits );
2010-01-16 19:01:00 +00:00
if ( sbits == 8 )
{
Write8 ( 0x0F );
Write8 ( 0xB6 );
}
else if ( sbits == 16 )
{
Write8 ( 0x0F );
Write8 ( 0xB7 );
}
2012-08-25 01:00:13 +02:00
else if ( sbits == 32 && dbits == 64 )
{
Write8 ( 0x8B );
}
2010-01-16 19:01:00 +00:00
else
{
2014-09-02 08:55:07 +02:00
_assert_msg_ ( DYNA_REC , 0 , "MOVZX - Invalid size" );
2010-01-16 19:01:00 +00:00
}
src . WriteRest ( this );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteMOVBE ( int bits , u8 op , X64Reg reg , const OpArg & arg )
2014-03-16 03:43:12 +01:00
{
_assert_msg_ ( DYNA_REC , cpu_info . bMOVBE , "Generating MOVBE on a system that does not support it." );
if ( bits == 8 )
{
2015-01-13 22:31:21 +01:00
MOV ( 8 , op & 1 ? arg : R ( reg ), op & 1 ? R ( reg ) : arg );
2014-03-16 03:43:12 +01:00
return ;
}
if ( bits == 16 )
Write8 ( 0x66 );
2015-01-13 22:31:21 +01:00
_assert_msg_ ( DYNA_REC , ! arg . IsSimpleReg () && ! arg . IsImm (), "MOVBE: need r<-m or m<-r!" );
2015-05-17 05:37:03 +02:00
arg . WriteREX ( this , bits , bits , reg );
2015-01-13 22:31:21 +01:00
Write8 ( 0x0F );
Write8 ( 0x38 );
Write8 ( op );
arg . WriteRest ( this , 0 , reg );
2014-03-16 03:43:12 +01:00
}
2015-01-13 22:31:21 +01:00
void XEmitter :: MOVBE ( int bits , X64Reg dest , const OpArg & src ) { WriteMOVBE ( bits , 0xF0 , dest , src );}
void XEmitter :: MOVBE ( int bits , const OpArg & dest , X64Reg src ) { WriteMOVBE ( bits , 0xF1 , src , dest );}
2010-01-16 19:01:00 +00:00
2015-05-28 21:50:39 -04:00
void XEmitter :: LoadAndSwap ( int size , X64Reg dst , const OpArg & src )
2015-01-14 23:31:00 +01:00
{
if ( cpu_info . bMOVBE )
{
MOVBE ( size , dst , src );
}
else
{
MOV ( size , R ( dst ), src );
BSWAP ( size , dst );
}
}
2015-05-28 21:50:39 -04:00
void XEmitter :: SwapAndStore ( int size , const OpArg & dst , X64Reg src )
2015-01-14 23:31:00 +01:00
{
if ( cpu_info . bMOVBE )
{
MOVBE ( size , dst , src );
}
else
{
BSWAP ( size , src );
MOV ( size , dst , R ( src ));
}
}
2010-01-16 19:01:00 +00:00
void XEmitter :: LEA ( int bits , X64Reg dest , OpArg src )
{
2014-09-06 01:24:03 -05:00
_assert_msg_ ( DYNA_REC , ! src . IsImm (), "LEA - Imm argument" );
2010-01-16 19:01:00 +00:00
src . operandReg = ( u8 ) dest ;
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 ); //TODO: performance warning
2015-05-17 05:37:03 +02:00
src . WriteREX ( this , bits , bits );
2010-01-16 19:01:00 +00:00
Write8 ( 0x8D );
2014-08-24 17:39:30 -07:00
src . WriteRest ( this , 0 , INVALID_REG , bits == 64 );
2010-01-16 19:01:00 +00:00
}
//shift can be either imm8 or cl
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteShift ( int bits , OpArg dest , const OpArg & shift , int ext )
2010-01-16 19:01:00 +00:00
{
2014-09-26 20:40:24 -07:00
CheckFlags ();
2010-01-16 19:01:00 +00:00
bool writeImm = false ;
if ( dest . IsImm ())
{
_assert_msg_ ( DYNA_REC , 0 , "WriteShift - can't shift imms" );
}
if (( shift . IsSimpleReg () && shift . GetSimpleReg () != ECX ) || ( shift . IsImm () && shift . GetImmBits () != 8 ))
{
2013-10-29 01:23:17 -04:00
_assert_msg_ ( DYNA_REC , 0 , "WriteShift - illegal argument" );
2010-01-16 19:01:00 +00:00
}
dest . operandReg = ext ;
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2015-05-17 05:37:03 +02:00
dest . WriteREX ( this , bits , bits , 0 );
2010-01-16 19:01:00 +00:00
if ( shift . GetImmBits () == 8 )
{
//ok an imm
u8 imm = ( u8 ) shift . offset ;
if ( imm == 1 )
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
Write8 ( bits == 8 ? 0xD0 : 0xD1 );
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
else
{
writeImm = true ;
Write8 ( bits == 8 ? 0xC0 : 0xC1 );
}
}
else
{
Write8 ( bits == 8 ? 0xD2 : 0xD3 );
}
dest . WriteRest ( this , writeImm ? 1 : 0 );
if ( writeImm )
Write8 (( u8 ) shift . offset );
}
2015-01-11 00:17:29 -05:00
// large rotates and shift are slower on Intel than AMD
// Intel likes to rotate by 1, and the op is smaller too
2015-05-28 22:15:09 -04:00
void XEmitter :: ROL ( int bits , const OpArg & dest , const OpArg & shift ) { WriteShift ( bits , dest , shift , 0 );}
void XEmitter :: ROR ( int bits , const OpArg & dest , const OpArg & shift ) { WriteShift ( bits , dest , shift , 1 );}
void XEmitter :: RCL ( int bits , const OpArg & dest , const OpArg & shift ) { WriteShift ( bits , dest , shift , 2 );}
void XEmitter :: RCR ( int bits , const OpArg & dest , const OpArg & shift ) { WriteShift ( bits , dest , shift , 3 );}
void XEmitter :: SHL ( int bits , const OpArg & dest , const OpArg & shift ) { WriteShift ( bits , dest , shift , 4 );}
void XEmitter :: SHR ( int bits , const OpArg & dest , const OpArg & shift ) { WriteShift ( bits , dest , shift , 5 );}
void XEmitter :: SAR ( int bits , const OpArg & dest , const OpArg & shift ) { WriteShift ( bits , dest , shift , 7 );}
2010-01-16 19:01:00 +00:00
2012-01-05 22:36:27 -05:00
// index can be either imm8 or register, don't use memory destination because it's slow
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteBitTest ( int bits , const OpArg & dest , const OpArg & index , int ext )
2012-01-05 22:36:27 -05:00
{
2014-09-26 20:40:24 -07:00
CheckFlags ();
2012-01-05 22:36:27 -05:00
if ( dest . IsImm ())
{
_assert_msg_ ( DYNA_REC , 0 , "WriteBitTest - can't test imms" );
}
if (( index . IsImm () && index . GetImmBits () != 8 ))
{
2013-10-29 01:23:17 -04:00
_assert_msg_ ( DYNA_REC , 0 , "WriteBitTest - illegal argument" );
2012-01-05 22:36:27 -05:00
}
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2012-01-05 22:36:27 -05:00
if ( index . IsImm ())
{
2015-05-17 05:37:03 +02:00
dest . WriteREX ( this , bits , bits );
2012-01-05 22:36:27 -05:00
Write8 ( 0x0F ); Write8 ( 0xBA );
dest . WriteRest ( this , 1 , ( X64Reg ) ext );
Write8 (( u8 ) index . offset );
}
else
{
X64Reg operand = index . GetSimpleReg ();
2015-05-17 05:37:03 +02:00
dest . WriteREX ( this , bits , bits , operand );
2012-01-05 22:36:27 -05:00
Write8 ( 0x0F ); Write8 ( 0x83 + 8 * ext );
dest . WriteRest ( this , 1 , operand );
}
}
2015-05-28 22:15:09 -04:00
void XEmitter :: BT ( int bits , const OpArg & dest , const OpArg & index ) { WriteBitTest ( bits , dest , index , 4 );}
void XEmitter :: BTS ( int bits , const OpArg & dest , const OpArg & index ) { WriteBitTest ( bits , dest , index , 5 );}
void XEmitter :: BTR ( int bits , const OpArg & dest , const OpArg & index ) { WriteBitTest ( bits , dest , index , 6 );}
void XEmitter :: BTC ( int bits , const OpArg & dest , const OpArg & index ) { WriteBitTest ( bits , dest , index , 7 );}
2012-01-05 22:36:27 -05:00
2012-01-09 00:10:13 -05:00
//shift can be either imm8 or cl
2015-05-28 22:15:09 -04:00
void XEmitter :: SHRD ( int bits , const OpArg & dest , const OpArg & src , const OpArg & shift )
2012-01-09 00:10:13 -05:00
{
2014-09-26 20:40:24 -07:00
CheckFlags ();
2012-01-09 00:10:13 -05:00
if ( dest . IsImm ())
{
_assert_msg_ ( DYNA_REC , 0 , "SHRD - can't use imms as destination" );
}
if ( ! src . IsSimpleReg ())
{
_assert_msg_ ( DYNA_REC , 0 , "SHRD - must use simple register as source" );
}
if (( shift . IsSimpleReg () && shift . GetSimpleReg () != ECX ) || ( shift . IsImm () && shift . GetImmBits () != 8 ))
{
2013-10-29 01:23:17 -04:00
_assert_msg_ ( DYNA_REC , 0 , "SHRD - illegal shift" );
2012-01-09 00:10:13 -05:00
}
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2012-01-09 00:10:13 -05:00
X64Reg operand = src . GetSimpleReg ();
2015-05-17 05:37:03 +02:00
dest . WriteREX ( this , bits , bits , operand );
2012-01-09 00:10:13 -05:00
if ( shift . GetImmBits () == 8 )
{
Write8 ( 0x0F ); Write8 ( 0xAC );
dest . WriteRest ( this , 1 , operand );
Write8 (( u8 ) shift . offset );
}
else
{
Write8 ( 0x0F ); Write8 ( 0xAD );
dest . WriteRest ( this , 0 , operand );
}
}
2015-05-28 22:15:09 -04:00
void XEmitter :: SHLD ( int bits , const OpArg & dest , const OpArg & src , const OpArg & shift )
2012-01-09 00:10:13 -05:00
{
2014-09-26 20:40:24 -07:00
CheckFlags ();
2012-01-09 00:10:13 -05:00
if ( dest . IsImm ())
{
_assert_msg_ ( DYNA_REC , 0 , "SHLD - can't use imms as destination" );
}
if ( ! src . IsSimpleReg ())
{
_assert_msg_ ( DYNA_REC , 0 , "SHLD - must use simple register as source" );
}
if (( shift . IsSimpleReg () && shift . GetSimpleReg () != ECX ) || ( shift . IsImm () && shift . GetImmBits () != 8 ))
{
2013-10-29 01:23:17 -04:00
_assert_msg_ ( DYNA_REC , 0 , "SHLD - illegal shift" );
2012-01-09 00:10:13 -05:00
}
2014-09-06 01:23:05 -05:00
if ( bits == 16 )
Write8 ( 0x66 );
2012-01-09 00:10:13 -05:00
X64Reg operand = src . GetSimpleReg ();
2015-05-17 05:37:03 +02:00
dest . WriteREX ( this , bits , bits , operand );
2012-01-09 00:10:13 -05:00
if ( shift . GetImmBits () == 8 )
{
Write8 ( 0x0F ); Write8 ( 0xA4 );
dest . WriteRest ( this , 1 , operand );
Write8 (( u8 ) shift . offset );
}
else
{
Write8 ( 0x0F ); Write8 ( 0xA5 );
dest . WriteRest ( this , 0 , operand );
}
}
2015-05-28 21:45:39 -04:00
void OpArg :: WriteSingleByteOp ( XEmitter * emit , u8 op , X64Reg _operandReg , int bits )
2010-01-16 19:01:00 +00:00
{
if ( bits == 16 )
emit -> Write8 ( 0x66 );
this -> operandReg = ( u8 ) _operandReg ;
2015-05-17 05:37:03 +02:00
WriteREX ( emit , bits , bits );
2010-01-16 19:01:00 +00:00
emit -> Write8 ( op );
WriteRest ( emit );
}
//operand can either be immediate or register
2015-05-28 21:45:39 -04:00
void OpArg :: WriteNormalOp ( XEmitter * emit , bool toRM , NormalOp op , const OpArg & operand , int bits ) const
2010-01-16 19:01:00 +00:00
{
2014-08-27 20:36:49 -05:00
X64Reg _operandReg ;
2010-01-16 19:01:00 +00:00
if ( IsImm ())
{
_assert_msg_ ( DYNA_REC , 0 , "WriteNormalOp - Imm argument, wrong order" );
}
if ( bits == 16 )
emit -> Write8 ( 0x66 );
int immToWrite = 0 ;
if ( operand . IsImm ())
{
2015-05-17 05:37:03 +02:00
WriteREX ( emit , bits , bits );
2010-01-16 19:01:00 +00:00
if ( ! toRM )
{
_assert_msg_ ( DYNA_REC , 0 , "WriteNormalOp - Writing to Imm (!toRM)" );
}
2013-10-29 01:23:17 -04:00
if ( operand . scale == SCALE_IMM8 && bits == 8 )
2010-01-16 19:01:00 +00:00
{
2014-09-10 23:54:06 -07:00
// op al, imm8
2014-09-02 02:11:24 -07:00
if ( ! scale && offsetOrBaseReg == AL && normalops [ op ]. eaximm8 != 0xCC )
{
emit -> Write8 ( normalops [ op ]. eaximm8 );
2014-09-10 23:54:06 -07:00
emit -> Write8 (( u8 ) operand . offset );
return ;
2014-09-02 02:11:24 -07:00
}
2014-09-10 23:54:06 -07:00
// mov reg, imm8
if ( ! scale && op == nrmMOV )
2014-09-02 02:11:24 -07:00
{
2014-09-10 23:54:06 -07:00
emit -> Write8 ( 0xB0 + ( offsetOrBaseReg & 7 ));
emit -> Write8 (( u8 ) operand . offset );
return ;
2014-09-02 02:11:24 -07:00
}
2014-09-10 23:54:06 -07:00
// op r/m8, imm8
emit -> Write8 ( normalops [ op ]. imm8 );
2010-01-16 19:01:00 +00:00
immToWrite = 8 ;
}
else if (( operand . scale == SCALE_IMM16 && bits == 16 ) ||
2013-10-29 01:23:17 -04:00
( operand . scale == SCALE_IMM32 && bits == 32 ) ||
2013-03-19 21:51:12 -04:00
( operand . scale == SCALE_IMM32 && bits == 64 ))
2010-01-16 19:01:00 +00:00
{
2014-08-06 16:36:53 -04:00
// Try to save immediate size if we can, but first check to see
// if the instruction supports simm8.
2014-09-10 23:54:06 -07:00
// op r/m, imm8
2014-09-02 02:11:24 -07:00
if ( normalops [ op ]. simm8 != 0xCC &&
2014-08-06 16:36:53 -04:00
(( operand . scale == SCALE_IMM16 && ( s16 ) operand . offset == ( s8 ) operand . offset ) ||
( operand . scale == SCALE_IMM32 && ( s32 ) operand . offset == ( s8 ) operand . offset )))
{
2014-09-02 02:11:24 -07:00
emit -> Write8 ( normalops [ op ]. simm8 );
2014-08-06 16:36:53 -04:00
immToWrite = 8 ;
}
else
{
2014-09-10 23:54:06 -07:00
// mov reg, imm
if ( ! scale && op == nrmMOV && bits != 64 )
{
emit -> Write8 ( 0xB8 + ( offsetOrBaseReg & 7 ));
if ( bits == 16 )
emit -> Write16 (( u16 ) operand . offset );
else
emit -> Write32 (( u32 ) operand . offset );
return ;
}
// op eax, imm
2014-09-02 02:11:24 -07:00
if ( ! scale && offsetOrBaseReg == EAX && normalops [ op ]. eaximm32 != 0xCC )
{
emit -> Write8 ( normalops [ op ]. eaximm32 );
2014-09-10 23:54:06 -07:00
if ( bits == 16 )
emit -> Write16 (( u16 ) operand . offset );
else
emit -> Write32 (( u32 ) operand . offset );
return ;
2014-09-02 02:11:24 -07:00
}
2014-09-10 23:54:06 -07:00
// op r/m, imm
emit -> Write8 ( normalops [ op ]. imm32 );
2014-08-06 16:36:53 -04:00
immToWrite = bits == 16 ? 16 : 32 ;
}
2010-01-16 19:01:00 +00:00
}
else if (( operand . scale == SCALE_IMM8 && bits == 16 ) ||
2013-03-19 21:51:12 -04:00
( operand . scale == SCALE_IMM8 && bits == 32 ) ||
( operand . scale == SCALE_IMM8 && bits == 64 ))
2010-01-16 19:01:00 +00:00
{
2014-09-10 23:54:06 -07:00
// op r/m, imm8
2014-09-02 02:11:24 -07:00
emit -> Write8 ( normalops [ op ]. simm8 );
2010-01-16 19:01:00 +00:00
immToWrite = 8 ;
}
else if ( operand . scale == SCALE_IMM64 && bits == 64 )
{
2014-09-10 23:54:06 -07:00
if ( scale )
{
_assert_msg_ ( DYNA_REC , 0 , "WriteNormalOp - MOV with 64-bit imm requres register destination" );
}
// mov reg64, imm64
else if ( op == nrmMOV )
2010-01-16 19:01:00 +00:00
{
emit -> Write8 ( 0xB8 + ( offsetOrBaseReg & 7 ));
emit -> Write64 (( u64 ) operand . offset );
return ;
}
_assert_msg_ ( DYNA_REC , 0 , "WriteNormalOp - Only MOV can take 64-bit imm" );
}
else
{
2014-11-09 16:21:11 -08:00
_assert_msg_ ( DYNA_REC , 0 , "WriteNormalOp - Unhandled case %d %d" , operand . scale , bits );
2010-01-16 19:01:00 +00:00
}
2014-09-02 02:11:24 -07:00
_operandReg = ( X64Reg ) normalops [ op ]. ext ; //pass extension in REG of ModRM
2010-01-16 19:01:00 +00:00
}
else
{
_operandReg = ( X64Reg ) operand . offsetOrBaseReg ;
2015-05-17 05:37:03 +02:00
WriteREX ( emit , bits , bits , _operandReg );
2014-09-10 23:54:06 -07:00
// op r/m, reg
2010-01-16 19:01:00 +00:00
if ( toRM )
{
2014-09-02 02:11:24 -07:00
emit -> Write8 ( bits == 8 ? normalops [ op ]. toRm8 : normalops [ op ]. toRm32 );
2010-01-16 19:01:00 +00:00
}
2014-09-10 23:54:06 -07:00
// op reg, r/m
2010-01-16 19:01:00 +00:00
else
{
2014-09-02 02:11:24 -07:00
emit -> Write8 ( bits == 8 ? normalops [ op ]. fromRm8 : normalops [ op ]. fromRm32 );
2010-01-16 19:01:00 +00:00
}
}
2014-09-10 23:54:06 -07:00
WriteRest ( emit , immToWrite >> 3 , _operandReg );
2010-01-16 19:01:00 +00:00
switch ( immToWrite )
{
case 0 :
break ;
case 8 :
emit -> Write8 (( u8 ) operand . offset );
break ;
case 16 :
emit -> Write16 (( u16 ) operand . offset );
break ;
case 32 :
emit -> Write32 (( u32 ) operand . offset );
break ;
default :
_assert_msg_ ( DYNA_REC , 0 , "WriteNormalOp - Unhandled case" );
}
}
2015-05-28 21:45:39 -04:00
void XEmitter :: WriteNormalOp ( int bits , NormalOp op , const OpArg & a1 , const OpArg & a2 )
2010-01-16 19:01:00 +00:00
{
if ( a1 . IsImm ())
{
//Booh! Can't write to an imm
_assert_msg_ ( DYNA_REC , 0 , "WriteNormalOp - a1 cannot be imm" );
return ;
}
if ( a2 . IsImm ())
{
2015-03-20 23:07:59 -04:00
a1 . WriteNormalOp ( this , true , op , a2 , bits );
2010-01-16 19:01:00 +00:00
}
else
{
if ( a1 . IsSimpleReg ())
{
2015-03-20 23:07:59 -04:00
a2 . WriteNormalOp ( this , false , op , a1 , bits );
2010-01-16 19:01:00 +00:00
}
else
2008-12-08 05:30:24 +00:00
{
2014-09-15 07:08:08 -07:00
_assert_msg_ ( DYNA_REC , a2 . IsSimpleReg () || a2 . IsImm (), "WriteNormalOp - a1 and a2 cannot both be memory" );
2015-03-20 23:07:59 -04:00
a1 . WriteNormalOp ( this , true , op , a2 , bits );
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
}
}
2015-05-28 21:45:39 -04:00
void XEmitter :: ADD ( int bits , const OpArg & a1 , const OpArg & a2 ) { CheckFlags (); WriteNormalOp ( bits , nrmADD , a1 , a2 );}
void XEmitter :: ADC ( int bits , const OpArg & a1 , const OpArg & a2 ) { CheckFlags (); WriteNormalOp ( bits , nrmADC , a1 , a2 );}
void XEmitter :: SUB ( int bits , const OpArg & a1 , const OpArg & a2 ) { CheckFlags (); WriteNormalOp ( bits , nrmSUB , a1 , a2 );}
void XEmitter :: SBB ( int bits , const OpArg & a1 , const OpArg & a2 ) { CheckFlags (); WriteNormalOp ( bits , nrmSBB , a1 , a2 );}
void XEmitter :: AND ( int bits , const OpArg & a1 , const OpArg & a2 ) { CheckFlags (); WriteNormalOp ( bits , nrmAND , a1 , a2 );}
void XEmitter :: OR ( int bits , const OpArg & a1 , const OpArg & a2 ) { CheckFlags (); WriteNormalOp ( bits , nrmOR , a1 , a2 );}
void XEmitter :: XOR ( int bits , const OpArg & a1 , const OpArg & a2 ) { CheckFlags (); WriteNormalOp ( bits , nrmXOR , a1 , a2 );}
void XEmitter :: MOV ( int bits , const OpArg & a1 , const OpArg & a2 )
2010-01-16 19:01:00 +00:00
{
2014-09-02 10:16:58 +02:00
if ( a1 . IsSimpleReg () && a2 . IsSimpleReg () && a1 . GetSimpleReg () == a2 . GetSimpleReg ())
ERROR_LOG ( DYNA_REC , "Redundant MOV @ %p - bug in JIT?" , code );
2015-03-20 23:07:59 -04:00
WriteNormalOp ( bits , nrmMOV , a1 , a2 );
2010-01-16 19:01:00 +00:00
}
2015-05-28 21:45:39 -04:00
void XEmitter :: TEST ( int bits , const OpArg & a1 , const OpArg & a2 ) { CheckFlags (); WriteNormalOp ( bits , nrmTEST , a1 , a2 );}
void XEmitter :: CMP ( int bits , const OpArg & a1 , const OpArg & a2 ) { CheckFlags (); WriteNormalOp ( bits , nrmCMP , a1 , a2 );}
void XEmitter :: XCHG ( int bits , const OpArg & a1 , const OpArg & a2 ) { WriteNormalOp ( bits , nrmXCHG , a1 , a2 );}
void XEmitter :: CMP_or_TEST ( int bits , const OpArg & a1 , const OpArg & a2 )
2015-02-21 11:12:03 +01:00
{
CheckFlags ();
if ( a1 . IsSimpleReg () && a2 . IsImm () && a2 . offset == 0 ) // turn 'CMP reg, 0' into shorter 'TEST reg, reg'
{
WriteNormalOp ( bits , nrmTEST , a1 , a1 );
}
else
{
WriteNormalOp ( bits , nrmCMP , a1 , a2 );
}
}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: IMUL ( int bits , X64Reg regOp , const OpArg & a1 , const OpArg & a2 )
2010-01-16 19:01:00 +00:00
{
2014-09-26 20:40:24 -07:00
CheckFlags ();
2014-08-30 16:14:56 -04:00
if ( bits == 8 )
{
2010-01-16 19:01:00 +00:00
_assert_msg_ ( DYNA_REC , 0 , "IMUL - illegal bit size!" );
return ;
}
2014-08-30 16:14:56 -04:00
if ( a1 . IsImm ())
{
2010-01-16 19:01:00 +00:00
_assert_msg_ ( DYNA_REC , 0 , "IMUL - second arg cannot be imm!" );
return ;
}
2014-08-30 16:14:56 -04:00
2010-01-16 19:01:00 +00:00
if ( ! a2 . IsImm ())
{
_assert_msg_ ( DYNA_REC , 0 , "IMUL - third arg must be imm!" );
return ;
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
if ( bits == 16 )
Write8 ( 0x66 );
2015-05-17 05:37:03 +02:00
a1 . WriteREX ( this , bits , bits , regOp );
2008-12-08 05:30:24 +00:00
2014-08-06 16:36:53 -04:00
if ( a2 . GetImmBits () == 8 ||
( a2 . GetImmBits () == 16 && ( s8 ) a2 . offset == ( s16 ) a2 . offset ) ||
2014-08-30 16:14:56 -04:00
( a2 . GetImmBits () == 32 && ( s8 ) a2 . offset == ( s32 ) a2 . offset ))
{
2010-01-16 19:01:00 +00:00
Write8 ( 0x6B );
a1 . WriteRest ( this , 1 , regOp );
Write8 (( u8 ) a2 . offset );
2014-08-30 16:14:56 -04:00
}
else
{
2010-01-16 19:01:00 +00:00
Write8 ( 0x69 );
2014-08-30 16:14:56 -04:00
if ( a2 . GetImmBits () == 16 && bits == 16 )
{
2010-01-16 19:01:00 +00:00
a1 . WriteRest ( this , 2 , regOp );
Write16 (( u16 ) a2 . offset );
2014-08-30 16:14:56 -04:00
}
else if ( a2 . GetImmBits () == 32 && ( bits == 32 || bits == 64 ))
{
a1 . WriteRest ( this , 4 , regOp );
Write32 (( u32 ) a2 . offset );
}
else
{
2010-01-16 19:01:00 +00:00
_assert_msg_ ( DYNA_REC , 0 , "IMUL - unhandled case!" );
2008-12-08 05:30:24 +00:00
}
}
2010-01-16 19:01:00 +00:00
}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: IMUL ( int bits , X64Reg regOp , const OpArg & a )
2010-01-16 19:01:00 +00:00
{
2014-09-26 20:40:24 -07:00
CheckFlags ();
2014-08-30 16:14:56 -04:00
if ( bits == 8 )
{
2010-01-16 19:01:00 +00:00
_assert_msg_ ( DYNA_REC , 0 , "IMUL - illegal bit size!" );
return ;
}
2014-08-30 16:14:56 -04:00
2010-01-16 19:01:00 +00:00
if ( a . IsImm ())
2008-12-08 05:30:24 +00:00
{
2010-01-16 19:01:00 +00:00
IMUL ( bits , regOp , R ( regOp ), a ) ;
2010-04-09 19:18:50 +00:00
return ;
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
if ( bits == 16 )
Write8 ( 0x66 );
2015-05-17 05:37:03 +02:00
a . WriteREX ( this , bits , bits , regOp );
2010-01-16 19:01:00 +00:00
Write8 ( 0x0F );
Write8 ( 0xAF );
a . WriteRest ( this , 0 , regOp );
}
2008-12-08 05:30:24 +00:00
2014-10-03 10:05:10 -07:00
void XEmitter :: WriteSSEOp ( u8 opPrefix , u16 op , X64Reg regOp , OpArg arg , int extrabytes )
2010-01-16 19:01:00 +00:00
{
2014-10-03 10:05:10 -07:00
if ( opPrefix )
Write8 ( opPrefix );
2010-01-16 19:01:00 +00:00
arg . operandReg = regOp ;
2015-05-17 05:37:03 +02:00
arg . WriteREX ( this , 0 , 0 );
2010-01-16 19:01:00 +00:00
Write8 ( 0x0F );
2014-10-03 10:05:10 -07:00
if ( op > 0xFF )
Write8 (( op >> 8 ) & 0xFF );
Write8 ( op & 0xFF );
2010-01-16 19:01:00 +00:00
arg . WriteRest ( this , extrabytes );
}
2008-12-08 05:30:24 +00:00
2014-10-03 10:05:10 -07:00
static int GetVEXmmmmm ( u16 op )
{
// Currently, only 0x38 and 0x3A are used as secondary escape byte.
if (( op >> 8 ) == 0x3A )
return 3 ;
else if (( op >> 8 ) == 0x38 )
return 2 ;
else
return 1 ;
}
static int GetVEXpp ( u8 opPrefix )
{
if ( opPrefix == 0x66 )
return 1 ;
else if ( opPrefix == 0xF3 )
return 2 ;
else if ( opPrefix == 0xF2 )
return 3 ;
else
return 0 ;
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteVEXOp ( u8 opPrefix , u16 op , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , int W , int extrabytes )
2013-11-04 21:37:07 +01:00
{
2014-10-03 10:05:10 -07:00
int mmmmm = GetVEXmmmmm ( op );
int pp = GetVEXpp ( opPrefix );
2014-08-24 17:39:30 -07:00
// FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size here
2015-05-17 05:38:01 +02:00
arg . WriteVEX ( this , regOp1 , regOp2 , 0 , pp , mmmmm , W );
2014-10-03 10:05:10 -07:00
Write8 ( op & 0xFF );
2013-11-04 21:37:07 +01:00
arg . WriteRest ( this , extrabytes , regOp1 );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteVEXOp4 ( u8 opPrefix , u16 op , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , X64Reg regOp3 , int W )
2014-08-24 17:39:30 -07:00
{
2015-05-17 07:07:17 +02:00
WriteVEXOp ( opPrefix , op , regOp1 , regOp2 , arg , W , 1 );
Write8 (( u8 ) regOp3 << 4 );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteAVXOp ( u8 opPrefix , u16 op , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , int W , int extrabytes )
2015-05-17 07:07:17 +02:00
{
if ( ! cpu_info . bAVX )
PanicAlert ( "Trying to use AVX on a system that doesn't support it. Bad programmer." );
WriteVEXOp ( opPrefix , op , regOp1 , regOp2 , arg , W , extrabytes );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteAVXOp4 ( u8 opPrefix , u16 op , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , X64Reg regOp3 , int W )
2015-05-17 07:07:17 +02:00
{
if ( ! cpu_info . bAVX )
PanicAlert ( "Trying to use AVX on a system that doesn't support it. Bad programmer." );
WriteVEXOp4 ( opPrefix , op , regOp1 , regOp2 , arg , regOp3 , W );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteFMA3Op ( u8 op , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , int W )
2015-05-17 07:07:17 +02:00
{
if ( ! cpu_info . bFMA )
PanicAlert ( "Trying to use FMA3 on a system that doesn't support it. Computer is v. f'n madd." );
WriteVEXOp ( 0x66 , 0x3800 | op , regOp1 , regOp2 , arg , W );
}
2015-05-17 09:20:29 +02:00
void XEmitter :: WriteFMA4Op ( u8 op , X64Reg dest , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , int W )
{
if ( ! cpu_info . bFMA4 )
PanicAlert ( "Trying to use FMA4 on a system that doesn't support it. Computer is v. f'n madd." );
WriteVEXOp4 ( 0x66 , 0x3A00 | op , dest , regOp1 , arg , regOp2 , W );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteBMIOp ( int size , u8 opPrefix , u16 op , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , int extrabytes )
2015-05-17 07:07:17 +02:00
{
2015-08-14 20:46:23 +02:00
if ( arg . IsImm ())
PanicAlert ( "BMI1/2 instructions don't support immediate operands." );
2014-08-24 17:39:30 -07:00
if ( size != 32 && size != 64 )
2015-08-14 20:46:23 +02:00
PanicAlert ( "BMI1/2 instructions only support 32-bit and 64-bit modes!" );
2015-05-17 07:07:17 +02:00
int W = size == 64 ;
WriteVEXOp ( opPrefix , op , regOp1 , regOp2 , arg , W , extrabytes );
2014-08-24 17:39:30 -07:00
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteBMI1Op ( int size , u8 opPrefix , u16 op , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , int extrabytes )
2014-08-24 17:39:30 -07:00
{
2015-08-14 06:02:22 +02:00
CheckFlags ();
2014-08-24 17:39:30 -07:00
if ( ! cpu_info . bBMI1 )
PanicAlert ( "Trying to use BMI1 on a system that doesn't support it. Bad programmer." );
2015-05-17 07:07:17 +02:00
WriteBMIOp ( size , opPrefix , op , regOp1 , regOp2 , arg , extrabytes );
2014-08-24 17:39:30 -07:00
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteBMI2Op ( int size , u8 opPrefix , u16 op , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , int extrabytes )
2014-08-24 17:39:30 -07:00
{
if ( ! cpu_info . bBMI2 )
PanicAlert ( "Trying to use BMI2 on a system that doesn't support it. Bad programmer." );
2015-05-17 07:07:17 +02:00
WriteBMIOp ( size , opPrefix , op , regOp1 , regOp2 , arg , extrabytes );
2014-08-24 17:39:30 -07:00
}
2015-05-28 21:45:39 -04:00
void XEmitter :: MOVD_xmm ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x6E , dest , arg , 0 );}
void XEmitter :: MOVD_xmm ( const OpArg & arg , X64Reg src ) { WriteSSEOp ( 0x66 , 0x7E , src , arg , 0 );}
2010-01-16 19:01:00 +00:00
2014-08-30 16:14:56 -04:00
void XEmitter :: MOVQ_xmm ( X64Reg dest , OpArg arg )
{
2010-01-16 19:01:00 +00:00
// Alternate encoding
// This does not display correctly in MSVC's debugger, it thinks it's a MOVD
2008-12-08 05:30:24 +00:00
arg . operandReg = dest ;
2010-01-16 19:01:00 +00:00
Write8 ( 0x66 );
2015-05-17 05:37:03 +02:00
arg . WriteREX ( this , 64 , 0 );
2008-12-08 05:30:24 +00:00
Write8 ( 0x0f );
2010-01-16 19:01:00 +00:00
Write8 ( 0x6E );
arg . WriteRest ( this , 0 );
}
2014-08-30 16:14:56 -04:00
void XEmitter :: MOVQ_xmm ( OpArg arg , X64Reg src )
{
2014-05-30 21:09:19 -07:00
if ( src > 7 || arg . IsSimpleReg ())
2010-01-16 19:01:00 +00:00
{
// Alternate encoding
// This does not display correctly in MSVC's debugger, it thinks it's a MOVD
arg . operandReg = src ;
Write8 ( 0x66 );
2015-05-17 05:37:03 +02:00
arg . WriteREX ( this , 64 , 0 );
2010-01-16 19:01:00 +00:00
Write8 ( 0x0f );
Write8 ( 0x7E );
arg . WriteRest ( this , 0 );
2014-08-30 16:14:56 -04:00
}
else
{
2010-01-16 19:01:00 +00:00
arg . operandReg = src ;
2015-05-17 05:37:03 +02:00
arg . WriteREX ( this , 0 , 0 );
2010-01-16 19:01:00 +00:00
Write8 ( 0x66 );
Write8 ( 0x0f );
Write8 ( 0xD6 );
2008-12-19 21:24:52 +00:00
arg . WriteRest ( this , 0 );
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
}
2008-12-08 05:30:24 +00:00
2010-01-16 19:01:00 +00:00
void XEmitter :: WriteMXCSR ( OpArg arg , int ext )
{
2013-10-29 01:23:17 -04:00
if ( arg . IsImm () || arg . IsSimpleReg ())
2010-01-16 19:01:00 +00:00
_assert_msg_ ( DYNA_REC , 0 , "MXCSR - invalid operand" );
2008-12-08 05:30:24 +00:00
2010-01-16 19:01:00 +00:00
arg . operandReg = ext ;
2015-05-17 05:37:03 +02:00
arg . WriteREX ( this , 0 , 0 );
2010-01-16 19:01:00 +00:00
Write8 ( 0x0F );
Write8 ( 0xAE );
arg . WriteRest ( this );
}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: STMXCSR ( const OpArg & memloc ) { WriteMXCSR ( memloc , 3 );}
void XEmitter :: LDMXCSR ( const OpArg & memloc ) { WriteMXCSR ( memloc , 2 );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVNTDQ ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x66 , sseMOVNTDQ , regOp , arg );}
void XEmitter :: MOVNTPS ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x00 , sseMOVNTP , regOp , arg );}
void XEmitter :: MOVNTPD ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x66 , sseMOVNTP , regOp , arg );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: ADDSS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseADD , regOp , arg );}
void XEmitter :: ADDSD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , sseADD , regOp , arg );}
void XEmitter :: SUBSS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseSUB , regOp , arg );}
void XEmitter :: SUBSD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , sseSUB , regOp , arg );}
void XEmitter :: CMPSS ( X64Reg regOp , const OpArg & arg , u8 compare ) { WriteSSEOp ( 0xF3 , sseCMP , regOp , arg , 1 ); Write8 ( compare );}
void XEmitter :: CMPSD ( X64Reg regOp , const OpArg & arg , u8 compare ) { WriteSSEOp ( 0xF2 , sseCMP , regOp , arg , 1 ); Write8 ( compare );}
void XEmitter :: MULSS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseMUL , regOp , arg );}
void XEmitter :: MULSD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , sseMUL , regOp , arg );}
void XEmitter :: DIVSS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseDIV , regOp , arg );}
void XEmitter :: DIVSD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , sseDIV , regOp , arg );}
void XEmitter :: MINSS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseMIN , regOp , arg );}
void XEmitter :: MINSD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , sseMIN , regOp , arg );}
void XEmitter :: MAXSS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseMAX , regOp , arg );}
void XEmitter :: MAXSD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , sseMAX , regOp , arg );}
void XEmitter :: SQRTSS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseSQRT , regOp , arg );}
void XEmitter :: SQRTSD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , sseSQRT , regOp , arg );}
void XEmitter :: RSQRTSS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseRSQRT , regOp , arg );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: ADDPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseADD , regOp , arg );}
void XEmitter :: ADDPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseADD , regOp , arg );}
void XEmitter :: SUBPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseSUB , regOp , arg );}
void XEmitter :: SUBPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseSUB , regOp , arg );}
void XEmitter :: CMPPS ( X64Reg regOp , const OpArg & arg , u8 compare ) { WriteSSEOp ( 0x00 , sseCMP , regOp , arg , 1 ); Write8 ( compare );}
void XEmitter :: CMPPD ( X64Reg regOp , const OpArg & arg , u8 compare ) { WriteSSEOp ( 0x66 , sseCMP , regOp , arg , 1 ); Write8 ( compare );}
void XEmitter :: ANDPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseAND , regOp , arg );}
void XEmitter :: ANDPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseAND , regOp , arg );}
void XEmitter :: ANDNPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseANDN , regOp , arg );}
void XEmitter :: ANDNPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseANDN , regOp , arg );}
void XEmitter :: ORPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseOR , regOp , arg );}
void XEmitter :: ORPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseOR , regOp , arg );}
void XEmitter :: XORPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseXOR , regOp , arg );}
void XEmitter :: XORPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseXOR , regOp , arg );}
void XEmitter :: MULPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseMUL , regOp , arg );}
void XEmitter :: MULPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseMUL , regOp , arg );}
void XEmitter :: DIVPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseDIV , regOp , arg );}
void XEmitter :: DIVPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseDIV , regOp , arg );}
void XEmitter :: MINPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseMIN , regOp , arg );}
void XEmitter :: MINPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseMIN , regOp , arg );}
void XEmitter :: MAXPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseMAX , regOp , arg );}
void XEmitter :: MAXPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseMAX , regOp , arg );}
void XEmitter :: SQRTPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseSQRT , regOp , arg );}
void XEmitter :: SQRTPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseSQRT , regOp , arg );}
void XEmitter :: RSQRTPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseRSQRT , regOp , arg );}
void XEmitter :: SHUFPS ( X64Reg regOp , const OpArg & arg , u8 shuffle ) { WriteSSEOp ( 0x00 , sseSHUF , regOp , arg , 1 ); Write8 ( shuffle );}
void XEmitter :: SHUFPD ( X64Reg regOp , const OpArg & arg , u8 shuffle ) { WriteSSEOp ( 0x66 , sseSHUF , regOp , arg , 1 ); Write8 ( shuffle );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: COMISS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseCOMIS , regOp , arg );} //weird that these should be packed
void XEmitter :: COMISD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseCOMIS , regOp , arg );} //ordered
void XEmitter :: UCOMISS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseUCOMIS , regOp , arg );} //unordered
void XEmitter :: UCOMISD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseUCOMIS , regOp , arg );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVAPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseMOVAPfromRM , regOp , arg );}
void XEmitter :: MOVAPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseMOVAPfromRM , regOp , arg );}
void XEmitter :: MOVAPS ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x00 , sseMOVAPtoRM , regOp , arg );}
void XEmitter :: MOVAPD ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x66 , sseMOVAPtoRM , regOp , arg );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVUPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseMOVUPfromRM , regOp , arg );}
void XEmitter :: MOVUPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseMOVUPfromRM , regOp , arg );}
void XEmitter :: MOVUPS ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x00 , sseMOVUPtoRM , regOp , arg );}
void XEmitter :: MOVUPD ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x66 , sseMOVUPtoRM , regOp , arg );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVDQA ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseMOVDQfromRM , regOp , arg );}
void XEmitter :: MOVDQA ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x66 , sseMOVDQtoRM , regOp , arg );}
void XEmitter :: MOVDQU ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseMOVDQfromRM , regOp , arg );}
void XEmitter :: MOVDQU ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0xF3 , sseMOVDQtoRM , regOp , arg );}
2014-10-10 17:56:17 +02:00
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVSS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , sseMOVUPfromRM , regOp , arg );}
void XEmitter :: MOVSD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , sseMOVUPfromRM , regOp , arg );}
void XEmitter :: MOVSS ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0xF3 , sseMOVUPtoRM , regOp , arg );}
void XEmitter :: MOVSD ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0xF2 , sseMOVUPtoRM , regOp , arg );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVLPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseMOVLPfromRM , regOp , arg );}
void XEmitter :: MOVLPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseMOVLPfromRM , regOp , arg );}
void XEmitter :: MOVLPS ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x00 , sseMOVLPtoRM , regOp , arg );}
void XEmitter :: MOVLPD ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x66 , sseMOVLPtoRM , regOp , arg );}
2015-01-07 11:09:51 +01:00
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVHPS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , sseMOVHPfromRM , regOp , arg );}
void XEmitter :: MOVHPD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , sseMOVHPfromRM , regOp , arg );}
void XEmitter :: MOVHPS ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x00 , sseMOVHPtoRM , regOp , arg );}
void XEmitter :: MOVHPD ( const OpArg & arg , X64Reg regOp ) { WriteSSEOp ( 0x66 , sseMOVHPtoRM , regOp , arg );}
2014-07-26 18:59:03 -07:00
2014-10-03 10:05:10 -07:00
void XEmitter :: MOVHLPS ( X64Reg regOp1 , X64Reg regOp2 ) { WriteSSEOp ( 0x00 , sseMOVHLPS , regOp1 , R ( regOp2 ));}
void XEmitter :: MOVLHPS ( X64Reg regOp1 , X64Reg regOp2 ) { WriteSSEOp ( 0x00 , sseMOVLHPS , regOp1 , R ( regOp2 ));}
2014-09-18 03:57:13 -07:00
2015-05-28 22:15:09 -04:00
void XEmitter :: CVTPS2PD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , 0x5A , regOp , arg );}
void XEmitter :: CVTPD2PS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x5A , regOp , arg );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: CVTSD2SS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , 0x5A , regOp , arg );}
void XEmitter :: CVTSS2SD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , 0x5A , regOp , arg );}
void XEmitter :: CVTSD2SI ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , 0x2D , regOp , arg );}
void XEmitter :: CVTSS2SI ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , 0x2D , regOp , arg );}
void XEmitter :: CVTSI2SD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , 0x2A , regOp , arg );}
void XEmitter :: CVTSI2SS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , 0x2A , regOp , arg );}
2008-12-18 06:46:32 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: CVTDQ2PD ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , 0xE6 , regOp , arg );}
void XEmitter :: CVTDQ2PS ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x00 , 0x5B , regOp , arg );}
void XEmitter :: CVTPD2DQ ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , 0xE6 , regOp , arg );}
void XEmitter :: CVTPS2DQ ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x5B , regOp , arg );}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: CVTTSD2SI ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF2 , 0x2C , regOp , arg );}
void XEmitter :: CVTTSS2SI ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , 0x2C , regOp , arg );}
void XEmitter :: CVTTPS2DQ ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0xF3 , 0x5B , regOp , arg );}
void XEmitter :: CVTTPD2DQ ( X64Reg regOp , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xE6 , regOp , arg );}
2010-01-16 22:44:49 +00:00
2014-10-03 10:05:10 -07:00
void XEmitter :: MASKMOVDQU ( X64Reg dest , X64Reg src ) { WriteSSEOp ( 0x66 , sseMASKMOVDQU , dest , R ( src ));}
2008-12-08 05:30:24 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVMSKPS ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x00 , 0x50 , dest , arg );}
void XEmitter :: MOVMSKPD ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x50 , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: LDDQU ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0xF2 , sseLDDQU , dest , arg );} // For integer data only
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: UNPCKLPS ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x00 , 0x14 , dest , arg );}
void XEmitter :: UNPCKHPS ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x00 , 0x15 , dest , arg );}
void XEmitter :: UNPCKLPD ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x14 , dest , arg );}
void XEmitter :: UNPCKHPD ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x15 , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-08-04 23:22:13 +02:00
// Pretty much every x86 CPU nowadays supports SSE3,
// but the SSE2 fallbacks are easy.
void XEmitter :: MOVSLDUP ( X64Reg regOp , const OpArg & arg )
{
if ( cpu_info . bSSE3 )
{
WriteSSEOp ( 0xF3 , 0x12 , regOp , arg );
}
else
{
if ( ! arg . IsSimpleReg ( regOp ))
MOVAPD ( regOp , arg );
UNPCKLPS ( regOp , R ( regOp ));
}
}
void XEmitter :: MOVSHDUP ( X64Reg regOp , const OpArg & arg )
{
if ( cpu_info . bSSE3 )
{
WriteSSEOp ( 0xF3 , 0x16 , regOp , arg );
}
else
{
if ( ! arg . IsSimpleReg ( regOp ))
MOVAPD ( regOp , arg );
UNPCKHPS ( regOp , R ( regOp ));
}
}
2015-05-28 22:15:09 -04:00
void XEmitter :: MOVDDUP ( X64Reg regOp , const OpArg & arg )
2010-01-16 19:01:00 +00:00
{
if ( cpu_info . bSSE3 )
2008-12-08 05:30:24 +00:00
{
2015-08-04 23:22:13 +02:00
WriteSSEOp ( 0xF2 , 0x12 , regOp , arg );
2008-12-08 05:30:24 +00:00
}
2010-01-16 19:01:00 +00:00
else
{
if ( ! arg . IsSimpleReg ( regOp ))
2012-06-02 10:06:47 +10:00
MOVSD ( regOp , arg );
2010-01-16 19:01:00 +00:00
UNPCKLPD ( regOp , R ( regOp ));
}
}
2008-12-08 05:30:24 +00:00
2010-01-16 19:01:00 +00:00
//There are a few more left
2013-04-19 09:21:45 -04:00
// Also some integer instructions are missing
2015-05-28 22:15:09 -04:00
void XEmitter :: PACKSSDW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x6B , dest , arg );}
void XEmitter :: PACKSSWB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x63 , dest , arg );}
void XEmitter :: PACKUSWB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x67 , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 21:45:39 -04:00
void XEmitter :: PUNPCKLBW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x60 , dest , arg );}
void XEmitter :: PUNPCKLWD ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x61 , dest , arg );}
void XEmitter :: PUNPCKLDQ ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x62 , dest , arg );}
void XEmitter :: PUNPCKLQDQ ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x6C , dest , arg );}
2010-01-16 19:01:00 +00:00
2014-08-30 16:14:56 -04:00
void XEmitter :: PSRLW ( X64Reg reg , int shift )
{
2014-10-03 10:05:10 -07:00
WriteSSEOp ( 0x66 , 0x71 , ( X64Reg ) 2 , R ( reg ));
2010-09-06 03:03:33 +00:00
Write8 ( shift );
}
2014-08-30 16:14:56 -04:00
void XEmitter :: PSRLD ( X64Reg reg , int shift )
{
2014-10-03 10:05:10 -07:00
WriteSSEOp ( 0x66 , 0x72 , ( X64Reg ) 2 , R ( reg ));
2010-09-06 03:03:33 +00:00
Write8 ( shift );
}
2014-08-30 16:14:56 -04:00
void XEmitter :: PSRLQ ( X64Reg reg , int shift )
{
2014-10-03 10:05:10 -07:00
WriteSSEOp ( 0x66 , 0x73 , ( X64Reg ) 2 , R ( reg ));
2010-09-06 03:03:33 +00:00
Write8 ( shift );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: PSRLQ ( X64Reg reg , const OpArg & arg )
2014-08-30 16:14:56 -04:00
{
2014-10-03 10:05:10 -07:00
WriteSSEOp ( 0x66 , 0xd3 , reg , arg );
2014-02-06 20:39:57 +13:00
}
2014-10-10 22:34:03 +02:00
void XEmitter :: PSRLDQ ( X64Reg reg , int shift )
{
2014-10-10 17:21:21 +02:00
WriteSSEOp ( 0x66 , 0x73 , ( X64Reg ) 3 , R ( reg ));
Write8 ( shift );
}
2014-08-30 16:14:56 -04:00
void XEmitter :: PSLLW ( X64Reg reg , int shift )
{
2014-10-03 10:05:10 -07:00
WriteSSEOp ( 0x66 , 0x71 , ( X64Reg ) 6 , R ( reg ));
2010-09-06 03:03:33 +00:00
Write8 ( shift );
}
2014-08-30 16:14:56 -04:00
void XEmitter :: PSLLD ( X64Reg reg , int shift )
{
2014-10-03 10:05:10 -07:00
WriteSSEOp ( 0x66 , 0x72 , ( X64Reg ) 6 , R ( reg ));
2010-09-06 03:03:33 +00:00
Write8 ( shift );
}
2014-08-30 16:14:56 -04:00
void XEmitter :: PSLLQ ( X64Reg reg , int shift )
{
2014-10-03 10:05:10 -07:00
WriteSSEOp ( 0x66 , 0x73 , ( X64Reg ) 6 , R ( reg ));
2010-09-06 03:03:33 +00:00
Write8 ( shift );
}
2014-10-10 22:34:03 +02:00
void XEmitter :: PSLLDQ ( X64Reg reg , int shift )
{
2014-10-10 17:21:21 +02:00
WriteSSEOp ( 0x66 , 0x73 , ( X64Reg ) 7 , R ( reg ));
Write8 ( shift );
}
2010-01-16 19:01:00 +00:00
// WARNING not REX compatible
2014-08-30 16:14:56 -04:00
void XEmitter :: PSRAW ( X64Reg reg , int shift )
{
2010-01-16 19:01:00 +00:00
if ( reg > 7 )
PanicAlert ( "The PSRAW-emitter does not support regs above 7" );
Write8 ( 0x66 );
Write8 ( 0x0f );
Write8 ( 0x71 );
Write8 ( 0xE0 | reg );
Write8 ( shift );
}
// WARNING not REX compatible
2014-08-30 16:14:56 -04:00
void XEmitter :: PSRAD ( X64Reg reg , int shift )
{
2010-01-16 19:01:00 +00:00
if ( reg > 7 )
PanicAlert ( "The PSRAD-emitter does not support regs above 7" );
Write8 ( 0x66 );
Write8 ( 0x0f );
Write8 ( 0x72 );
Write8 ( 0xE0 | reg );
Write8 ( shift );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteSSSE3Op ( u8 opPrefix , u16 op , X64Reg regOp , const OpArg & arg , int extrabytes )
2014-07-26 18:59:03 -07:00
{
if ( ! cpu_info . bSSSE3 )
PanicAlert ( "Trying to use SSSE3 on a system that doesn't support it. Bad programmer." );
2014-10-03 10:05:10 -07:00
WriteSSEOp ( opPrefix , op , regOp , arg , extrabytes );
2014-02-03 23:56:11 +01:00
}
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteSSE41Op ( u8 opPrefix , u16 op , X64Reg regOp , const OpArg & arg , int extrabytes )
2014-07-26 18:59:03 -07:00
{
if ( ! cpu_info . bSSE4_1 )
PanicAlert ( "Trying to use SSE4.1 on a system that doesn't support it. Bad programmer." );
2014-10-03 10:05:10 -07:00
WriteSSEOp ( opPrefix , op , regOp , arg , extrabytes );
2010-01-16 19:01:00 +00:00
}
2015-05-28 22:15:09 -04:00
void XEmitter :: PSHUFB ( X64Reg dest , const OpArg & arg ) { WriteSSSE3Op ( 0x66 , 0x3800 , dest , arg );}
void XEmitter :: PTEST ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3817 , dest , arg );}
void XEmitter :: PACKUSDW ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x382b , dest , arg );}
2014-07-26 18:59:03 -07:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PMOVSXBW ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3820 , dest , arg );}
void XEmitter :: PMOVSXBD ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3821 , dest , arg );}
void XEmitter :: PMOVSXBQ ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3822 , dest , arg );}
void XEmitter :: PMOVSXWD ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3823 , dest , arg );}
void XEmitter :: PMOVSXWQ ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3824 , dest , arg );}
void XEmitter :: PMOVSXDQ ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3825 , dest , arg );}
void XEmitter :: PMOVZXBW ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3830 , dest , arg );}
void XEmitter :: PMOVZXBD ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3831 , dest , arg );}
void XEmitter :: PMOVZXBQ ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3832 , dest , arg );}
void XEmitter :: PMOVZXWD ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3833 , dest , arg );}
void XEmitter :: PMOVZXWQ ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3834 , dest , arg );}
void XEmitter :: PMOVZXDQ ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3835 , dest , arg );}
2014-07-26 18:59:03 -07:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PBLENDVB ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3810 , dest , arg );}
void XEmitter :: BLENDVPS ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3814 , dest , arg );}
void XEmitter :: BLENDVPD ( X64Reg dest , const OpArg & arg ) { WriteSSE41Op ( 0x66 , 0x3815 , dest , arg );}
void XEmitter :: BLENDPS ( X64Reg dest , const OpArg & arg , u8 blend ) { WriteSSE41Op ( 0x66 , 0x3A0C , dest , arg , 1 ); Write8 ( blend );}
void XEmitter :: BLENDPD ( X64Reg dest , const OpArg & arg , u8 blend ) { WriteSSE41Op ( 0x66 , 0x3A0D , dest , arg , 1 ); Write8 ( blend );}
2014-07-26 18:59:03 -07:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PAND ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xDB , dest , arg );}
void XEmitter :: PANDN ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xDF , dest , arg );}
void XEmitter :: PXOR ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xEF , dest , arg );}
void XEmitter :: POR ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xEB , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PADDB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xFC , dest , arg );}
void XEmitter :: PADDW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xFD , dest , arg );}
void XEmitter :: PADDD ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xFE , dest , arg );}
void XEmitter :: PADDQ ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xD4 , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PADDSB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xEC , dest , arg );}
void XEmitter :: PADDSW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xED , dest , arg );}
void XEmitter :: PADDUSB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xDC , dest , arg );}
void XEmitter :: PADDUSW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xDD , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PSUBB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xF8 , dest , arg );}
void XEmitter :: PSUBW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xF9 , dest , arg );}
void XEmitter :: PSUBD ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xFA , dest , arg );}
void XEmitter :: PSUBQ ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xFB , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PSUBSB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xE8 , dest , arg );}
void XEmitter :: PSUBSW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xE9 , dest , arg );}
void XEmitter :: PSUBUSB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xD8 , dest , arg );}
void XEmitter :: PSUBUSW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xD9 , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PAVGB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xE0 , dest , arg );}
void XEmitter :: PAVGW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xE3 , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PCMPEQB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x74 , dest , arg );}
void XEmitter :: PCMPEQW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x75 , dest , arg );}
void XEmitter :: PCMPEQD ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x76 , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PCMPGTB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x64 , dest , arg );}
void XEmitter :: PCMPGTW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x65 , dest , arg );}
void XEmitter :: PCMPGTD ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0x66 , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PEXTRW ( X64Reg dest , const OpArg & arg , u8 subreg ) { WriteSSEOp ( 0x66 , 0xC5 , dest , arg ); Write8 ( subreg );}
void XEmitter :: PINSRW ( X64Reg dest , const OpArg & arg , u8 subreg ) { WriteSSEOp ( 0x66 , 0xC4 , dest , arg ); Write8 ( subreg );}
2015-06-01 19:58:27 +02:00
void XEmitter :: PINSRD ( X64Reg dest , const OpArg & arg , u8 subreg ) { WriteSSE41Op ( 0x66 , 0x3A22 , dest , arg ); Write8 ( subreg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PMADDWD ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xF5 , dest , arg ); }
void XEmitter :: PSADBW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xF6 , dest , arg );}
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PMAXSW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xEE , dest , arg ); }
void XEmitter :: PMAXUB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xDE , dest , arg ); }
void XEmitter :: PMINSW ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xEA , dest , arg ); }
void XEmitter :: PMINUB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xDA , dest , arg ); }
2010-01-16 19:01:00 +00:00
2015-05-28 22:15:09 -04:00
void XEmitter :: PMOVMSKB ( X64Reg dest , const OpArg & arg ) { WriteSSEOp ( 0x66 , 0xD7 , dest , arg ); }
void XEmitter :: PSHUFD ( X64Reg regOp , const OpArg & arg , u8 shuffle ) { WriteSSEOp ( 0x66 , 0x70 , regOp , arg , 1 ); Write8 ( shuffle );}
void XEmitter :: PSHUFLW ( X64Reg regOp , const OpArg & arg , u8 shuffle ) { WriteSSEOp ( 0xF2 , 0x70 , regOp , arg , 1 ); Write8 ( shuffle );}
void XEmitter :: PSHUFHW ( X64Reg regOp , const OpArg & arg , u8 shuffle ) { WriteSSEOp ( 0xF3 , 0x70 , regOp , arg , 1 ); Write8 ( shuffle );}
2010-01-16 19:01:00 +00:00
2013-11-04 21:37:07 +01:00
// VEX
2015-05-28 22:15:09 -04:00
void XEmitter :: VADDSD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0xF2 , sseADD , regOp1 , regOp2 , arg );}
void XEmitter :: VSUBSD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0xF2 , sseSUB , regOp1 , regOp2 , arg );}
void XEmitter :: VMULSD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0xF2 , sseMUL , regOp1 , regOp2 , arg );}
void XEmitter :: VDIVSD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0xF2 , sseDIV , regOp1 , regOp2 , arg );}
void XEmitter :: VADDPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , sseADD , regOp1 , regOp2 , arg );}
void XEmitter :: VSUBPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , sseSUB , regOp1 , regOp2 , arg );}
void XEmitter :: VMULPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , sseMUL , regOp1 , regOp2 , arg );}
void XEmitter :: VDIVPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , sseDIV , regOp1 , regOp2 , arg );}
void XEmitter :: VSQRTSD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0xF2 , sseSQRT , regOp1 , regOp2 , arg );}
void XEmitter :: VCMPPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , u8 compare ) { WriteAVXOp ( 0x66 , sseCMP , regOp1 , regOp2 , arg , 0 , 1 ); Write8 ( compare );}
void XEmitter :: VSHUFPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , u8 shuffle ) { WriteAVXOp ( 0x66 , sseSHUF , regOp1 , regOp2 , arg , 0 , 1 ); Write8 ( shuffle );}
void XEmitter :: VUNPCKLPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ){ WriteAVXOp ( 0x66 , 0x14 , regOp1 , regOp2 , arg );}
void XEmitter :: VUNPCKHPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ){ WriteAVXOp ( 0x66 , 0x15 , regOp1 , regOp2 , arg );}
void XEmitter :: VBLENDVPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg , X64Reg regOp3 ) { WriteAVXOp4 ( 0x66 , 0x3A4B , regOp1 , regOp2 , arg , regOp3 );}
2014-08-24 17:39:30 -07:00
2015-05-28 22:15:09 -04:00
void XEmitter :: VANDPS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x00 , sseAND , regOp1 , regOp2 , arg );}
void XEmitter :: VANDPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , sseAND , regOp1 , regOp2 , arg );}
void XEmitter :: VANDNPS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x00 , sseANDN , regOp1 , regOp2 , arg );}
void XEmitter :: VANDNPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , sseANDN , regOp1 , regOp2 , arg );}
void XEmitter :: VORPS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x00 , sseOR , regOp1 , regOp2 , arg );}
void XEmitter :: VORPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , sseOR , regOp1 , regOp2 , arg );}
void XEmitter :: VXORPS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x00 , sseXOR , regOp1 , regOp2 , arg );}
void XEmitter :: VXORPD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , sseXOR , regOp1 , regOp2 , arg );}
2014-12-06 16:01:09 +01:00
2015-05-28 22:15:09 -04:00
void XEmitter :: VPAND ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , 0xDB , regOp1 , regOp2 , arg );}
void XEmitter :: VPANDN ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , 0xDF , regOp1 , regOp2 , arg );}
void XEmitter :: VPOR ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , 0xEB , regOp1 , regOp2 , arg );}
void XEmitter :: VPXOR ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteAVXOp ( 0x66 , 0xEF , regOp1 , regOp2 , arg );}
2014-12-06 16:01:09 +01:00
2015-05-28 22:15:09 -04:00
void XEmitter :: VFMADD132PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x98 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMADD213PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xA8 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMADD231PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xB8 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMADD132PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x98 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMADD213PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xA8 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMADD231PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xB8 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMADD132SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x99 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMADD213SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xA9 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMADD231SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xB9 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMADD132SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x99 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMADD213SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xA9 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMADD231SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xB9 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMSUB132PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9A , regOp1 , regOp2 , arg );}
void XEmitter :: VFMSUB213PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAA , regOp1 , regOp2 , arg );}
void XEmitter :: VFMSUB231PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBA , regOp1 , regOp2 , arg );}
void XEmitter :: VFMSUB132PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9A , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMSUB213PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAA , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMSUB231PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBA , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMSUB132SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9B , regOp1 , regOp2 , arg );}
void XEmitter :: VFMSUB213SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAB , regOp1 , regOp2 , arg );}
void XEmitter :: VFMSUB231SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBB , regOp1 , regOp2 , arg );}
void XEmitter :: VFMSUB132SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9B , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMSUB213SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAB , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMSUB231SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBB , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMADD132PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9C , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMADD213PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAC , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMADD231PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBC , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMADD132PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9C , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMADD213PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAC , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMADD231PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBC , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMADD132SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9D , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMADD213SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAD , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMADD231SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBD , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMADD132SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9D , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMADD213SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAD , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMADD231SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBD , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMSUB132PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9E , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMSUB213PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAE , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMSUB231PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBE , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMSUB132PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9E , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMSUB213PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAE , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMSUB231PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBE , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMSUB132SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9F , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMSUB213SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAF , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMSUB231SS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBF , regOp1 , regOp2 , arg );}
void XEmitter :: VFNMSUB132SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x9F , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMSUB213SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xAF , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFNMSUB231SD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xBF , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMADDSUB132PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x96 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMADDSUB213PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xA6 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMADDSUB231PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xB6 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMADDSUB132PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x96 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMADDSUB213PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xA6 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMADDSUB231PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xB6 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMSUBADD132PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x97 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMSUBADD213PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xA7 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMSUBADD231PS ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xB7 , regOp1 , regOp2 , arg );}
void XEmitter :: VFMSUBADD132PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0x97 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMSUBADD213PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xA7 , regOp1 , regOp2 , arg , 1 );}
void XEmitter :: VFMSUBADD231PD ( X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteFMA3Op ( 0xB7 , regOp1 , regOp2 , arg , 1 );}
2014-09-06 03:00:09 -07:00
2015-05-17 09:20:29 +02:00
#define FMA4(name, op) \
void XEmitter::name(X64Reg dest, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA4Op(op, dest, regOp1, regOp2, arg, 1);} \
void XEmitter::name(X64Reg dest, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteFMA4Op(op, dest, regOp1, regOp2, arg, 0);}
FMA4 ( VFMADDSUBPS , 0x5C )
FMA4 ( VFMADDSUBPD , 0x5D )
FMA4 ( VFMSUBADDPS , 0x5E )
FMA4 ( VFMSUBADDPD , 0x5F )
FMA4 ( VFMADDPS , 0x68 )
FMA4 ( VFMADDPD , 0x69 )
FMA4 ( VFMADDSS , 0x6A )
FMA4 ( VFMADDSD , 0x6B )
FMA4 ( VFMSUBPS , 0x6C )
FMA4 ( VFMSUBPD , 0x6D )
FMA4 ( VFMSUBSS , 0x6E )
FMA4 ( VFMSUBSD , 0x6F )
FMA4 ( VFNMADDPS , 0x78 )
FMA4 ( VFNMADDPD , 0x79 )
FMA4 ( VFNMADDSS , 0x7A )
FMA4 ( VFNMADDSD , 0x7B )
FMA4 ( VFNMSUBPS , 0x7C )
FMA4 ( VFNMSUBPD , 0x7D )
FMA4 ( VFNMSUBSS , 0x7E )
FMA4 ( VFNMSUBSD , 0x7F )
#undef FMA4
2015-05-28 22:15:09 -04:00
void XEmitter :: SARX ( int bits , X64Reg regOp1 , const OpArg & arg , X64Reg regOp2 ) { WriteBMI2Op ( bits , 0xF3 , 0x38F7 , regOp1 , regOp2 , arg );}
void XEmitter :: SHLX ( int bits , X64Reg regOp1 , const OpArg & arg , X64Reg regOp2 ) { WriteBMI2Op ( bits , 0x66 , 0x38F7 , regOp1 , regOp2 , arg );}
void XEmitter :: SHRX ( int bits , X64Reg regOp1 , const OpArg & arg , X64Reg regOp2 ) { WriteBMI2Op ( bits , 0xF2 , 0x38F7 , regOp1 , regOp2 , arg );}
void XEmitter :: RORX ( int bits , X64Reg regOp , const OpArg & arg , u8 rotate ) { WriteBMI2Op ( bits , 0xF2 , 0x3AF0 , regOp , INVALID_REG , arg , 1 ); Write8 ( rotate );}
void XEmitter :: PEXT ( int bits , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteBMI2Op ( bits , 0xF3 , 0x38F5 , regOp1 , regOp2 , arg );}
void XEmitter :: PDEP ( int bits , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteBMI2Op ( bits , 0xF2 , 0x38F5 , regOp1 , regOp2 , arg );}
void XEmitter :: MULX ( int bits , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteBMI2Op ( bits , 0xF2 , 0x38F6 , regOp2 , regOp1 , arg );}
2015-08-14 06:02:22 +02:00
void XEmitter :: BZHI ( int bits , X64Reg regOp1 , const OpArg & arg , X64Reg regOp2 ) { CheckFlags (); WriteBMI2Op ( bits , 0x00 , 0x38F5 , regOp1 , regOp2 , arg );}
2015-05-28 22:15:09 -04:00
void XEmitter :: BLSR ( int bits , X64Reg regOp , const OpArg & arg ) { WriteBMI1Op ( bits , 0x00 , 0x38F3 , ( X64Reg ) 0x1 , regOp , arg );}
void XEmitter :: BLSMSK ( int bits , X64Reg regOp , const OpArg & arg ) { WriteBMI1Op ( bits , 0x00 , 0x38F3 , ( X64Reg ) 0x2 , regOp , arg );}
void XEmitter :: BLSI ( int bits , X64Reg regOp , const OpArg & arg ) { WriteBMI1Op ( bits , 0x00 , 0x38F3 , ( X64Reg ) 0x3 , regOp , arg );}
void XEmitter :: BEXTR ( int bits , X64Reg regOp1 , const OpArg & arg , X64Reg regOp2 ){ WriteBMI1Op ( bits , 0x00 , 0x38F7 , regOp1 , regOp2 , arg );}
void XEmitter :: ANDN ( int bits , X64Reg regOp1 , X64Reg regOp2 , const OpArg & arg ) { WriteBMI1Op ( bits , 0x00 , 0x38F2 , regOp1 , regOp2 , arg );}
2013-11-04 21:37:07 +01:00
2010-01-16 19:01:00 +00:00
// Prefixes
void XEmitter :: LOCK () { Write8 ( 0xF0 ); }
void XEmitter :: REP () { Write8 ( 0xF3 ); }
void XEmitter :: REPNE () { Write8 ( 0xF2 ); }
2014-09-15 23:03:07 -04:00
void XEmitter :: FSOverride () { Write8 ( 0x64 ); }
void XEmitter :: GSOverride () { Write8 ( 0x65 ); }
2010-01-16 19:01:00 +00:00
void XEmitter :: FWAIT ()
{
Write8 ( 0x9B );
}
2014-01-25 18:38:06 +01:00
// TODO: make this more generic
2015-05-28 22:15:09 -04:00
void XEmitter :: WriteFloatLoadStore ( int bits , FloatOp op , FloatOp op_80b , const OpArg & arg )
2014-01-25 18:38:06 +01:00
{
int mf = 0 ;
2014-09-02 08:55:38 +02:00
_assert_msg_ ( DYNA_REC , ! ( bits == 80 && op_80b == floatINVALID ), "WriteFloatLoadStore: 80 bits not supported for this instruction" );
2014-08-30 16:14:56 -04:00
switch ( bits )
{
case 32 : mf = 0 ; break ;
2014-09-02 08:55:38 +02:00
case 64 : mf = 4 ; break ;
case 80 : mf = 2 ; break ;
default : _assert_msg_ ( DYNA_REC , 0 , "WriteFloatLoadStore: invalid bits (should be 32/64/80)" );
2014-01-25 18:38:06 +01:00
}
2014-09-02 08:55:38 +02:00
Write8 ( 0xd9 | mf );
2014-01-25 18:38:06 +01:00
// x87 instructions use the reg field of the ModR/M byte as opcode:
2014-09-02 08:55:38 +02:00
if ( bits == 80 )
op = op_80b ;
2014-01-25 18:38:06 +01:00
arg . WriteRest ( this , 0 , ( X64Reg ) op );
}
2015-05-28 22:15:09 -04:00
void XEmitter :: FLD ( int bits , const OpArg & src ) { WriteFloatLoadStore ( bits , floatLD , floatLD80 , src ); }
void XEmitter :: FST ( int bits , const OpArg & dest ) { WriteFloatLoadStore ( bits , floatST , floatINVALID , dest ); }
void XEmitter :: FSTP ( int bits , const OpArg & dest ) { WriteFloatLoadStore ( bits , floatSTP , floatSTP80 , dest ); }
2014-02-03 23:56:11 +01:00
void XEmitter :: FNSTSW_AX () { Write8 ( 0xDF ); Write8 ( 0xE0 ); }
2014-01-25 18:38:06 +01:00
2014-08-26 11:27:22 +02:00
void XEmitter :: RDTSC () { Write8 ( 0x0F ); Write8 ( 0x31 ); }
2013-10-29 01:23:17 -04:00
2008-12-08 05:30:24 +00:00
}