2015-06-07 16:57:57 -05:00
// Copyright 2015 Dolphin Emulator Project
2015-05-18 01:08:10 +02:00
// Licensed under GPLv2+
2014-02-05 01:56:23 +00:00
// Refer to the license.txt file included.
2015-06-07 16:57:57 -05:00
#include <algorithm>
2015-10-22 15:32:11 -04:00
#include <cstring>
2015-06-07 16:57:57 -05:00
#include <vector>
2014-09-12 05:45:10 -05:00
2014-12-15 14:23:09 -06:00
#include "Common/Arm64Emitter.h"
2015-09-26 16:39:47 -04:00
#include "Common/Assert.h"
2015-06-07 16:57:57 -05:00
#include "Common/CommonTypes.h"
2014-12-15 14:23:09 -06:00
#include "Common/MathUtil.h"
2014-02-05 01:56:23 +00:00
namespace Arm64Gen
{
2015-06-07 16:57:57 -05:00
const int kWRegSizeInBits = 32 ;
const int kXRegSizeInBits = 64 ;
// The below few functions are taken from V8.
static int CountLeadingZeros ( uint64_t value , int width )
{
// TODO(jbramley): Optimize this for ARM64 hosts.
int count = 0 ;
uint64_t bit_test = 1ULL << ( width - 1 );
while (( count < width ) && (( bit_test & value ) == 0 ))
{
count ++ ;
bit_test >>= 1 ;
}
return count ;
}
static uint64_t LargestPowerOf2Divisor ( uint64_t value )
{
return value & - ( int64_t ) value ;
}
static bool IsPowerOfTwo ( uint64_t x )
{
return ( x != 0 ) && (( x & ( x - 1 )) == 0 );
}
#define V8_UINT64_C(x) ((uint64_t)(x))
bool IsImmArithmetic ( uint64_t input , u32 * val , bool * shift )
{
if ( input < 4096 )
{
* val = input ;
* shift = false ;
return true ;
}
else if (( input & 0xFFF000 ) == input )
{
* val = input >> 12 ;
* shift = true ;
return true ;
}
return false ;
}
bool IsImmLogical ( uint64_t value , unsigned int width , unsigned int * n , unsigned int * imm_s , unsigned int * imm_r )
{
//DCHECK((n != NULL) && (imm_s != NULL) && (imm_r != NULL));
// DCHECK((width == kWRegSizeInBits) || (width == kXRegSizeInBits));
bool negate = false ;
// Logical immediates are encoded using parameters n, imm_s and imm_r using
// the following table:
//
// N imms immr size S R
// 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr)
// 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr)
// 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr)
// 0 110sss xxxrrr 8 UInt(sss) UInt(rrr)
// 0 1110ss xxxxrr 4 UInt(ss) UInt(rr)
// 0 11110s xxxxxr 2 UInt(s) UInt(r)
// (s bits must not be all set)
//
// A pattern is constructed of size bits, where the least significant S+1 bits
// are set. The pattern is rotated right by R, and repeated across a 32 or
// 64-bit value, depending on destination register width.
//
// Put another way: the basic format of a logical immediate is a single
// contiguous stretch of 1 bits, repeated across the whole word at intervals
// given by a power of 2. To identify them quickly, we first locate the
// lowest stretch of 1 bits, then the next 1 bit above that; that combination
// is different for every logical immediate, so it gives us all the
// information we need to identify the only logical immediate that our input
// could be, and then we simply check if that's the value we actually have.
//
// (The rotation parameter does give the possibility of the stretch of 1 bits
// going 'round the end' of the word. To deal with that, we observe that in
// any situation where that happens the bitwise NOT of the value is also a
// valid logical immediate. So we simply invert the input whenever its low bit
// is set, and then we know that the rotated case can't arise.)
if ( value & 1 )
{
// If the low bit is 1, negate the value, and set a flag to remember that we
// did (so that we can adjust the return values appropriately).
negate = true ;
value = ~ value ;
}
if ( width == kWRegSizeInBits )
{
// To handle 32-bit logical immediates, the very easiest thing is to repeat
// the input value twice to make a 64-bit word. The correct encoding of that
// as a logical immediate will also be the correct encoding of the 32-bit
// value.
// The most-significant 32 bits may not be zero (ie. negate is true) so
// shift the value left before duplicating it.
value <<= kWRegSizeInBits ;
value |= value >> kWRegSizeInBits ;
}
// The basic analysis idea: imagine our input word looks like this.
//
// 0011111000111110001111100011111000111110001111100011111000111110
// c b a
// |<--d-->|
//
// We find the lowest set bit (as an actual power-of-2 value, not its index)
// and call it a. Then we add a to our original number, which wipes out the
// bottommost stretch of set bits and replaces it with a 1 carried into the
// next zero bit. Then we look for the new lowest set bit, which is in
// position b, and subtract it, so now our number is just like the original
// but with the lowest stretch of set bits completely gone. Now we find the
// lowest set bit again, which is position c in the diagram above. Then we'll
// measure the distance d between bit positions a and c (using CLZ), and that
// tells us that the only valid logical immediate that could possibly be equal
// to this number is the one in which a stretch of bits running from a to just
// below b is replicated every d bits.
uint64_t a = LargestPowerOf2Divisor ( value );
uint64_t value_plus_a = value + a ;
uint64_t b = LargestPowerOf2Divisor ( value_plus_a );
uint64_t value_plus_a_minus_b = value_plus_a - b ;
uint64_t c = LargestPowerOf2Divisor ( value_plus_a_minus_b );
int d , clz_a , out_n ;
uint64_t mask ;
if ( c != 0 )
{
// The general case, in which there is more than one stretch of set bits.
// Compute the repeat distance d, and set up a bitmask covering the basic
// unit of repetition (i.e. a word with the bottom d bits set). Also, in all
// of these cases the N bit of the output will be zero.
clz_a = CountLeadingZeros ( a , kXRegSizeInBits );
int clz_c = CountLeadingZeros ( c , kXRegSizeInBits );
d = clz_a - clz_c ;
mask = (( V8_UINT64_C ( 1 ) << d ) - 1 );
out_n = 0 ;
}
else
{
// Handle degenerate cases.
//
// If any of those 'find lowest set bit' operations didn't find a set bit at
// all, then the word will have been zero thereafter, so in particular the
// last lowest_set_bit operation will have returned zero. So we can test for
// all the special case conditions in one go by seeing if c is zero.
if ( a == 0 )
{
// The input was zero (or all 1 bits, which will come to here too after we
// inverted it at the start of the function), for which we just return
// false.
return false ;
}
else
{
// Otherwise, if c was zero but a was not, then there's just one stretch
// of set bits in our word, meaning that we have the trivial case of
// d == 64 and only one 'repetition'. Set up all the same variables as in
// the general case above, and set the N bit in the output.
clz_a = CountLeadingZeros ( a , kXRegSizeInBits );
d = 64 ;
mask = ~ V8_UINT64_C ( 0 );
out_n = 1 ;
}
}
// If the repeat period d is not a power of two, it can't be encoded.
if ( ! IsPowerOfTwo ( d ))
return false ;
// If the bit stretch (b - a) does not fit within the mask derived from the
// repeat period, then fail.
if ((( b - a ) & ~ mask ) != 0 )
return false ;
// The only possible option is b - a repeated every d bits. Now we're going to
// actually construct the valid logical immediate derived from that
// specification, and see if it equals our original input.
//
// To repeat a value every d bits, we multiply it by a number of the form
// (1 + 2^d + 2^(2d) + ...), i.e. 0x0001000100010001 or similar. These can
// be derived using a table lookup on CLZ(d).
static const std :: array < uint64_t , 6 > multipliers =
{
0x0000000000000001UL ,
0x0000000100000001UL ,
0x0001000100010001UL ,
0x0101010101010101UL ,
0x1111111111111111UL ,
0x5555555555555555UL ,
};
int multiplier_idx = CountLeadingZeros ( d , kXRegSizeInBits ) - 57 ;
// Ensure that the index to the multipliers array is within bounds.
_dbg_assert_ ( DYNA_REC , ( multiplier_idx >= 0 ) &&
( static_cast < size_t > ( multiplier_idx ) < multipliers . size ()));
uint64_t multiplier = multipliers [ multiplier_idx ];
uint64_t candidate = ( b - a ) * multiplier ;
// The candidate pattern doesn't match our input value, so fail.
if ( value != candidate )
return false ;
// We have a match! This is a valid logical immediate, so now we have to
// construct the bits and pieces of the instruction encoding that generates
// it.
// Count the set bits in our basic stretch. The special case of clz(0) == -1
// makes the answer come out right for stretches that reach the very top of
// the word (e.g. numbers like 0xffffc00000000000).
int clz_b = ( b == 0 ) ? - 1 : CountLeadingZeros ( b , kXRegSizeInBits );
int s = clz_a - clz_b ;
// Decide how many bits to rotate right by, to put the low bit of that basic
// stretch in position a.
int r ;
if ( negate )
{
// If we inverted the input right at the start of this function, here's
// where we compensate: the number of set bits becomes the number of clear
// bits, and the rotation count is based on position b rather than position
// a (since b is the location of the 'lowest' 1 bit after inversion).
s = d - s ;
r = ( clz_b + 1 ) & ( d - 1 );
}
else
{
r = ( clz_a + 1 ) & ( d - 1 );
}
// Now we're done, except for having to encode the S output in such a way that
// it gives both the number of set bits and the length of the repeated
// segment. The s field is encoded like this:
//
// imms size S
// ssssss 64 UInt(ssssss)
// 0sssss 32 UInt(sssss)
// 10ssss 16 UInt(ssss)
// 110sss 8 UInt(sss)
// 1110ss 4 UInt(ss)
// 11110s 2 UInt(s)
//
// So we 'or' (-d << 1) with our computed s to form imms.
* n = out_n ;
* imm_s = (( - d << 1 ) | ( s - 1 )) & 0x3f ;
* imm_r = r ;
return true ;
}
2015-08-15 10:26:59 +02:00
void ARM64XEmitter :: SetCodePtrUnsafe ( u8 * ptr )
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
m_code = ptr ;
2015-08-15 10:26:59 +02:00
}
void ARM64XEmitter :: SetCodePtr ( u8 * ptr )
{
SetCodePtrUnsafe ( ptr );
m_lastCacheFlushEnd = ptr ;
2014-02-05 01:56:23 +00:00
}
2014-09-08 22:52:52 -04:00
const u8 * ARM64XEmitter :: GetCodePtr () const
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
return m_code ;
2014-02-05 01:56:23 +00:00
}
2014-09-08 22:52:52 -04:00
u8 * ARM64XEmitter :: GetWritableCodePtr ()
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
return m_code ;
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: ReserveCodeSpace ( u32 bytes )
{
for ( u32 i = 0 ; i < bytes / 4 ; i ++ )
BRK ( 0 );
}
2014-09-08 22:52:52 -04:00
const u8 * ARM64XEmitter :: AlignCode16 ()
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
int c = int (( u64 ) m_code & 15 );
2014-02-05 01:56:23 +00:00
if ( c )
ReserveCodeSpace ( 16 - c );
2014-09-08 22:52:52 -04:00
return m_code ;
2014-02-05 01:56:23 +00:00
}
2014-09-08 22:52:52 -04:00
const u8 * ARM64XEmitter :: AlignCodePage ()
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
int c = int (( u64 ) m_code & 4095 );
2014-02-05 01:56:23 +00:00
if ( c )
ReserveCodeSpace ( 4096 - c );
2014-09-08 22:52:52 -04:00
return m_code ;
2014-02-05 01:56:23 +00:00
}
2015-10-22 15:32:11 -04:00
void ARM64XEmitter :: Write32 ( u32 value )
{
std :: memcpy ( m_code , & value , sizeof ( u32 ));
m_code += sizeof ( u32 );
}
2014-02-05 01:56:23 +00:00
void ARM64XEmitter :: FlushIcache ()
{
2014-09-08 22:52:52 -04:00
FlushIcacheSection ( m_lastCacheFlushEnd , m_code );
m_lastCacheFlushEnd = m_code ;
2014-02-05 01:56:23 +00:00
}
2014-09-08 22:52:52 -04:00
void ARM64XEmitter :: FlushIcacheSection ( u8 * start , u8 * end )
2014-02-05 01:56:23 +00:00
{
2015-07-11 12:22:13 +02:00
if ( start == end )
return ;
2014-02-05 01:56:23 +00:00
#if defined(IOS)
// Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
sys_cache_control ( kCacheFunctionPrepareForExecution , start , end - start );
#else
#ifdef __clang__
__clear_cache ( start , end );
#else
__builtin___clear_cache ( start , end );
#endif
#endif
}
// Exception generation
2014-11-25 23:12:15 -05:00
static const u32 ExcEnc [][ 3 ] = {
2014-02-05 01:56:23 +00:00
{ 0 , 0 , 1 }, // SVC
{ 0 , 0 , 2 }, // HVC
{ 0 , 0 , 3 }, // SMC
{ 1 , 0 , 0 }, // BRK
{ 2 , 0 , 0 }, // HLT
{ 5 , 0 , 1 }, // DCPS1
{ 5 , 0 , 2 }, // DCPS2
{ 5 , 0 , 3 }, // DCPS3
};
// Arithmetic generation
2014-11-25 23:12:15 -05:00
static const u32 ArithEnc [] = {
2014-02-05 01:56:23 +00:00
0x058 , // ADD
0x258 , // SUB
};
// Conditional Select
2014-11-25 23:12:15 -05:00
static const u32 CondSelectEnc [][ 2 ] = {
2014-02-05 01:56:23 +00:00
{ 0 , 0 }, // CSEL
{ 0 , 1 }, // CSINC
{ 1 , 0 }, // CSINV
{ 1 , 1 }, // CSNEG
};
// Data-Processing (1 source)
2014-11-25 23:12:15 -05:00
static const u32 Data1SrcEnc [][ 2 ] = {
2014-02-05 01:56:23 +00:00
{ 0 , 0 }, // RBIT
{ 0 , 1 }, // REV16
{ 0 , 2 }, // REV32
{ 0 , 3 }, // REV64
{ 0 , 4 }, // CLZ
{ 0 , 5 }, // CLS
};
// Data-Processing (2 source)
2014-11-25 23:12:15 -05:00
static const u32 Data2SrcEnc [] = {
2014-02-05 01:56:23 +00:00
0x02 , // UDIV
0x03 , // SDIV
0x08 , // LSLV
0x09 , // LSRV
0x0A , // ASRV
0x0B , // RORV
0x10 , // CRC32B
0x11 , // CRC32H
0x12 , // CRC32W
0x14 , // CRC32CB
0x15 , // CRC32CH
0x16 , // CRC32CW
0x13 , // CRC32X (64bit Only)
0x17 , // XRC32CX (64bit Only)
};
// Data-Processing (3 source)
2014-11-25 23:12:15 -05:00
static const u32 Data3SrcEnc [][ 2 ] = {
2014-02-05 01:56:23 +00:00
{ 0 , 0 }, // MADD
{ 0 , 1 }, // MSUB
{ 1 , 0 }, // SMADDL (64Bit Only)
{ 1 , 1 }, // SMSUBL (64Bit Only)
{ 2 , 0 }, // SMULH (64Bit Only)
{ 5 , 0 }, // UMADDL (64Bit Only)
{ 5 , 1 }, // UMSUBL (64Bit Only)
{ 6 , 0 }, // UMULH (64Bit Only)
};
// Logical (shifted register)
2014-11-25 23:12:15 -05:00
static const u32 LogicalEnc [][ 2 ] = {
2014-02-05 01:56:23 +00:00
{ 0 , 0 }, // AND
{ 0 , 1 }, // BIC
{ 1 , 0 }, // OOR
{ 1 , 1 }, // ORN
{ 2 , 0 }, // EOR
{ 2 , 1 }, // EON
{ 3 , 0 }, // ANDS
{ 3 , 1 }, // BICS
};
// Load/Store Exclusive
2015-07-02 11:09:01 -04:00
static const u32 LoadStoreExcEnc [][ 5 ] = {
2014-02-05 01:56:23 +00:00
{ 0 , 0 , 0 , 0 , 0 }, // STXRB
{ 0 , 0 , 0 , 0 , 1 }, // STLXRB
{ 0 , 0 , 1 , 0 , 0 }, // LDXRB
{ 0 , 0 , 1 , 0 , 1 }, // LDAXRB
{ 0 , 1 , 0 , 0 , 1 }, // STLRB
{ 0 , 1 , 1 , 0 , 1 }, // LDARB
{ 1 , 0 , 0 , 0 , 0 }, // STXRH
{ 1 , 0 , 0 , 0 , 1 }, // STLXRH
{ 1 , 0 , 1 , 0 , 0 }, // LDXRH
{ 1 , 0 , 1 , 0 , 1 }, // LDAXRH
{ 1 , 1 , 0 , 0 , 1 }, // STLRH
{ 1 , 1 , 1 , 0 , 1 }, // LDARH
{ 2 , 0 , 0 , 0 , 0 }, // STXR
{ 3 , 0 , 0 , 0 , 0 }, // (64bit) STXR
{ 2 , 0 , 0 , 0 , 1 }, // STLXR
{ 3 , 0 , 0 , 0 , 1 }, // (64bit) STLXR
{ 2 , 0 , 0 , 1 , 0 }, // STXP
{ 3 , 0 , 0 , 1 , 0 }, // (64bit) STXP
{ 2 , 0 , 0 , 1 , 1 }, // STLXP
{ 3 , 0 , 0 , 1 , 1 }, // (64bit) STLXP
{ 2 , 0 , 1 , 0 , 0 }, // LDXR
{ 3 , 0 , 1 , 0 , 0 }, // (64bit) LDXR
{ 2 , 0 , 1 , 0 , 1 }, // LDAXR
{ 3 , 0 , 1 , 0 , 1 }, // (64bit) LDAXR
{ 2 , 0 , 1 , 1 , 0 }, // LDXP
{ 3 , 0 , 1 , 1 , 0 }, // (64bit) LDXP
{ 2 , 0 , 1 , 1 , 1 }, // LDAXP
{ 3 , 0 , 1 , 1 , 1 }, // (64bit) LDAXP
{ 2 , 1 , 0 , 0 , 1 }, // STLR
{ 3 , 1 , 0 , 0 , 1 }, // (64bit) STLR
{ 2 , 1 , 1 , 0 , 1 }, // LDAR
{ 3 , 1 , 1 , 0 , 1 }, // (64bit) LDAR
};
void ARM64XEmitter :: EncodeCompareBranchInst ( u32 op , ARM64Reg Rt , const void * ptr )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
2015-02-12 18:43:50 -06:00
s64 distance = ( s64 ) ptr - ( s64 ) m_code ;
2014-02-05 01:56:23 +00:00
_assert_msg_ ( DYNA_REC , ! ( distance & 0x3 ), "%s: distance must be a multiple of 4: %lx" , __FUNCTION__ , distance );
distance >>= 2 ;
2015-06-07 16:57:57 -05:00
_assert_msg_ ( DYNA_REC , distance >= - 0x40000 && distance <= 0x3FFFF , "%s: Received too large distance: %lx" , __FUNCTION__ , distance );
2014-02-05 01:56:23 +00:00
Rt = DecodeReg ( Rt );
Write32 (( b64Bit << 31 ) | ( 0x34 << 24 ) | ( op << 24 ) | \
2015-02-12 18:43:50 -06:00
((( u32 ) distance << 5 ) & 0xFFFFE0 ) | Rt );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: EncodeTestBranchInst ( u32 op , ARM64Reg Rt , u8 bits , const void * ptr )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
2015-02-12 18:43:50 -06:00
s64 distance = ( s64 ) ptr - ( s64 ) m_code ;
2014-02-05 01:56:23 +00:00
_assert_msg_ ( DYNA_REC , ! ( distance & 0x3 ), "%s: distance must be a multiple of 4: %lx" , __FUNCTION__ , distance );
distance >>= 2 ;
_assert_msg_ ( DYNA_REC , distance >= - 0x3FFF && distance < 0x3FFF , "%s: Received too large distance: %lx" , __FUNCTION__ , distance );
Rt = DecodeReg ( Rt );
Write32 (( b64Bit << 31 ) | ( 0x36 << 24 ) | ( op << 24 ) | \
2015-09-07 13:38:58 -05:00
( bits << 19 ) | ((( u32 ) distance << 5 ) & 0x7FFE0 ) | Rt );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: EncodeUnconditionalBranchInst ( u32 op , const void * ptr )
{
2014-09-08 22:52:52 -04:00
s64 distance = ( s64 ) ptr - s64 ( m_code );
2014-02-05 01:56:23 +00:00
_assert_msg_ ( DYNA_REC , ! ( distance & 0x3 ), "%s: distance must be a multiple of 4: %lx" , __FUNCTION__ , distance );
distance >>= 2 ;
2015-06-07 16:57:57 -05:00
_assert_msg_ ( DYNA_REC , distance >= - 0x2000000LL && distance <= 0x1FFFFFFLL , "%s: Received too large distance: %lx" , __FUNCTION__ , distance );
2014-02-05 01:56:23 +00:00
Write32 (( op << 31 ) | ( 0x5 << 26 ) | ( distance & 0x3FFFFFF ));
}
void ARM64XEmitter :: EncodeUnconditionalBranchInst ( u32 opc , u32 op2 , u32 op3 , u32 op4 , ARM64Reg Rn )
{
Rn = DecodeReg ( Rn );
Write32 (( 0x6B << 25 ) | ( opc << 21 ) | ( op2 << 16 ) | ( op3 << 10 ) | ( Rn << 5 ) | op4 );
}
void ARM64XEmitter :: EncodeExceptionInst ( u32 instenc , u32 imm )
{
_assert_msg_ ( DYNA_REC , ! ( imm & ~ 0xFFFF ), "%s: Exception instruction too large immediate: %d" , __FUNCTION__ , imm );
Write32 (( 0xD4 << 24 ) | ( ExcEnc [ instenc ][ 0 ] << 21 ) | ( imm << 5 ) | ( ExcEnc [ instenc ][ 1 ] << 2 ) | ExcEnc [ instenc ][ 2 ]);
}
void ARM64XEmitter :: EncodeSystemInst ( u32 op0 , u32 op1 , u32 CRn , u32 CRm , u32 op2 , ARM64Reg Rt )
{
Write32 (( 0x354 << 22 ) | ( op0 << 19 ) | ( op1 << 16 ) | ( CRn << 12 ) | ( CRm << 8 ) | ( op2 << 5 ) | Rt );
}
void ARM64XEmitter :: EncodeArithmeticInst ( u32 instenc , bool flags , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Option )
{
2015-01-18 16:25:40 -06:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
2015-01-18 16:25:40 -06:00
Write32 (( b64Bit << 31 ) | ( flags << 29 ) | ( ArithEnc [ instenc ] << 21 ) | \
2015-06-07 16:57:57 -05:00
( Option . GetType () == ArithOption :: TYPE_EXTENDEDREG ? ( 1 << 21 ) : 0 ) | ( Rm << 16 ) | Option . GetData () | ( Rn << 5 ) | Rd );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: EncodeArithmeticCarryInst ( u32 op , bool flags , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
Rd = DecodeReg ( Rd );
Rm = DecodeReg ( Rm );
Rn = DecodeReg ( Rn );
Write32 (( b64Bit << 31 ) | ( op << 30 ) | ( flags << 29 ) | \
( 0xD0 << 21 ) | ( Rm << 16 ) | ( Rn << 5 ) | Rd );
}
void ARM64XEmitter :: EncodeCondCompareImmInst ( u32 op , ARM64Reg Rn , u32 imm , u32 nzcv , CCFlags cond )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rn );
2014-02-05 01:56:23 +00:00
_assert_msg_ ( DYNA_REC , ! ( imm & ~ 0x1F ), "%s: too large immediate: %d" , __FUNCTION__ , imm )
_assert_msg_ ( DYNA_REC , ! ( nzcv & ~ 0xF ), "%s: Flags out of range: %d" , __FUNCTION__ , nzcv )
Rn = DecodeReg ( Rn );
Write32 (( b64Bit << 31 ) | ( op << 30 ) | ( 1 << 29 ) | ( 0xD2 << 21 ) | \
( imm << 16 ) | ( cond << 12 ) | ( 1 << 11 ) | ( Rn << 5 ) | nzcv );
}
void ARM64XEmitter :: EncodeCondCompareRegInst ( u32 op , ARM64Reg Rn , ARM64Reg Rm , u32 nzcv , CCFlags cond )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rm );
2014-02-05 01:56:23 +00:00
_assert_msg_ ( DYNA_REC , ! ( nzcv & ~ 0xF ), "%s: Flags out of range: %d" , __FUNCTION__ , nzcv )
Rm = DecodeReg ( Rm );
Rn = DecodeReg ( Rn );
Write32 (( b64Bit << 31 ) | ( op << 30 ) | ( 1 << 29 ) | ( 0xD2 << 21 ) | \
( Rm << 16 ) | ( cond << 12 ) | ( Rn << 5 ) | nzcv );
}
void ARM64XEmitter :: EncodeCondSelectInst ( u32 instenc , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , CCFlags cond )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
Rd = DecodeReg ( Rd );
Rm = DecodeReg ( Rm );
Rn = DecodeReg ( Rn );
Write32 (( b64Bit << 31 ) | ( CondSelectEnc [ instenc ][ 0 ] << 30 ) | \
( 0xD4 << 21 ) | ( Rm << 16 ) | ( cond << 12 ) | ( CondSelectEnc [ instenc ][ 1 ] << 10 ) | \
( Rn << 5 ) | Rd );
}
void ARM64XEmitter :: EncodeData1SrcInst ( u32 instenc , ARM64Reg Rd , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Write32 (( b64Bit << 31 ) | ( 0x2D6 << 21 ) | \
( Data1SrcEnc [ instenc ][ 0 ] << 16 ) | ( Data1SrcEnc [ instenc ][ 1 ] << 10 ) | \
( Rn << 5 ) | Rd );
}
void ARM64XEmitter :: EncodeData2SrcInst ( u32 instenc , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
Rd = DecodeReg ( Rd );
Rm = DecodeReg ( Rm );
Rn = DecodeReg ( Rn );
Write32 (( b64Bit << 31 ) | ( 0x0D6 << 21 ) | \
( Rm << 16 ) | ( Data2SrcEnc [ instenc ] << 10 ) | \
( Rn << 5 ) | Rd );
}
void ARM64XEmitter :: EncodeData3SrcInst ( u32 instenc , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
Rd = DecodeReg ( Rd );
Rm = DecodeReg ( Rm );
Rn = DecodeReg ( Rn );
Ra = DecodeReg ( Ra );
Write32 (( b64Bit << 31 ) | ( 0xD8 << 21 ) | ( Data3SrcEnc [ instenc ][ 0 ] << 21 ) | \
( Rm << 16 ) | ( Data3SrcEnc [ instenc ][ 1 ] << 15 ) | \
( Ra << 10 ) | ( Rn << 5 ) | Rd );
}
void ARM64XEmitter :: EncodeLogicalInst ( u32 instenc , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Shift )
{
2015-01-18 16:25:40 -06:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
Rd = DecodeReg ( Rd );
Rm = DecodeReg ( Rm );
Rn = DecodeReg ( Rn );
2015-06-07 16:57:57 -05:00
Write32 (( b64Bit << 31 ) | ( LogicalEnc [ instenc ][ 0 ] << 29 ) | ( 0x5 << 25 ) | ( LogicalEnc [ instenc ][ 1 ] << 21 ) | \
2014-02-05 01:56:23 +00:00
Shift . GetData () | ( Rm << 16 ) | ( Rn << 5 ) | Rd );
}
void ARM64XEmitter :: EncodeLoadRegisterInst ( u32 bitop , ARM64Reg Rt , u32 imm )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
bool bVec = IsVector ( Rt );
2014-02-05 01:56:23 +00:00
_assert_msg_ ( DYNA_REC , ! ( imm & 0xFFFFF ), "%s: offset too large %d" , __FUNCTION__ , imm );
Rt = DecodeReg ( Rt );
if ( b64Bit && bitop != 0x2 ) // LDRSW(0x2) uses 64bit reg, doesn't have 64bit bit set
bitop |= 0x1 ;
Write32 (( bitop << 30 ) | ( bVec << 26 ) | ( 0x18 << 24 ) | ( imm << 5 ) | Rt );
}
void ARM64XEmitter :: EncodeLoadStoreExcInst ( u32 instenc ,
ARM64Reg Rs , ARM64Reg Rt2 , ARM64Reg Rn , ARM64Reg Rt )
{
Rs = DecodeReg ( Rs );
Rt2 = DecodeReg ( Rt2 );
Rn = DecodeReg ( Rn );
Rt = DecodeReg ( Rt );
Write32 (( LoadStoreExcEnc [ instenc ][ 0 ] << 30 ) | ( 0x8 << 24 ) | ( LoadStoreExcEnc [ instenc ][ 1 ] << 23 ) | \
( LoadStoreExcEnc [ instenc ][ 2 ] << 22 ) | ( LoadStoreExcEnc [ instenc ][ 3 ] << 21 ) | ( Rs << 16 ) | \
( LoadStoreExcEnc [ instenc ][ 4 ] << 15 ) | ( Rt2 << 10 ) | ( Rn << 5 ) | Rt );
}
void ARM64XEmitter :: EncodeLoadStorePairedInst ( u32 op , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , u32 imm )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
2015-01-07 13:05:55 -06:00
bool b128Bit = IsQuad ( Rt );
2014-09-08 22:52:52 -04:00
bool bVec = IsVector ( Rt );
2014-02-05 01:56:23 +00:00
if ( b128Bit )
imm >>= 4 ;
else if ( b64Bit )
imm >>= 3 ;
else
imm >>= 2 ;
_assert_msg_ ( DYNA_REC , ! ( imm & ~ 0xF ), "%s: offset too large %d" , __FUNCTION__ , imm );
u32 opc = 0 ;
if ( b128Bit )
opc = 2 ;
else if ( b64Bit && bVec )
opc = 1 ;
else if ( b64Bit && ! bVec )
opc = 2 ;
Rt = DecodeReg ( Rt );
Rt2 = DecodeReg ( Rt2 );
Rn = DecodeReg ( Rn );
Write32 (( opc << 30 ) | ( bVec << 26 ) | ( op << 22 ) | ( imm << 15 ) | ( Rt2 << 10 ) | ( Rn << 5 ) | Rt );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: EncodeLoadStoreIndexedInst ( u32 op , u32 op2 , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
bool bVec = IsVector ( Rt );
2014-02-05 01:56:23 +00:00
2014-12-15 14:23:09 -06:00
u32 offset = imm & 0x1FF ;
2014-02-05 01:56:23 +00:00
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! ( imm < - 256 || imm > 255 ), "%s: offset too large %d" , __FUNCTION__ , imm );
2014-02-05 01:56:23 +00:00
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
2014-12-15 14:23:09 -06:00
Write32 (( b64Bit << 30 ) | ( op << 22 ) | ( bVec << 26 ) | ( offset << 12 ) | ( op2 << 10 ) | ( Rn << 5 ) | Rt );
2014-02-05 01:56:23 +00:00
}
2015-01-07 12:58:37 -06:00
void ARM64XEmitter :: EncodeLoadStoreIndexedInst ( u32 op , ARM64Reg Rt , ARM64Reg Rn , s32 imm , u8 size )
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
bool bVec = IsVector ( Rt );
2014-02-05 01:56:23 +00:00
2015-01-07 12:58:37 -06:00
if ( size == 64 )
2014-02-05 01:56:23 +00:00
imm >>= 3 ;
2015-01-07 12:58:37 -06:00
else if ( size == 32 )
2014-02-05 01:56:23 +00:00
imm >>= 2 ;
2015-01-07 12:58:37 -06:00
else if ( size == 16 )
imm >>= 1 ;
2014-02-05 01:56:23 +00:00
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , imm >= 0 , "%s(INDEX_UNSIGNED): offset must be positive %d" , __FUNCTION__ , imm );
2014-02-05 01:56:23 +00:00
_assert_msg_ ( DYNA_REC , ! ( imm & ~ 0xFFF ), "%s(INDEX_UNSIGNED): offset too large %d" , __FUNCTION__ , imm );
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
Write32 (( b64Bit << 30 ) | ( op << 22 ) | ( bVec << 26 ) | ( imm << 10 ) | ( Rn << 5 ) | Rt );
}
void ARM64XEmitter :: EncodeMOVWideInst ( u32 op , ARM64Reg Rd , u32 imm , ShiftAmount pos )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
_assert_msg_ ( DYNA_REC , ! ( imm & ~ 0xFFFF ), "%s: immediate out of range: %d" , __FUNCTION__ , imm );
Rd = DecodeReg ( Rd );
Write32 (( b64Bit << 31 ) | ( op << 29 ) | ( 0x25 << 23 ) | ( pos << 21 ) | ( imm << 5 ) | Rd );
}
void ARM64XEmitter :: EncodeBitfieldMOVInst ( u32 op , ARM64Reg Rd , ARM64Reg Rn , u32 immr , u32 imms )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Write32 (( b64Bit << 31 ) | ( op << 29 ) | ( 0x26 << 23 ) | ( b64Bit << 22 ) | \
( immr << 16 ) | ( imms << 10 ) | ( Rn << 5 ) | Rd );
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: EncodeLoadStoreRegisterOffset ( u32 size , u32 opc , ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
2015-01-18 16:25:40 -06:00
ARM64Reg decoded_Rm = DecodeReg ( Rm . GetReg ());
2014-02-05 01:56:23 +00:00
2015-01-18 16:25:40 -06:00
Write32 (( size << 30 ) | ( opc << 22 ) | ( 0x1C1 << 21 ) | ( decoded_Rm << 16 ) | \
Rm . GetData () | ( 1 << 11 ) | ( Rn << 5 ) | Rt );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: EncodeAddSubImmInst ( u32 op , bool flags , u32 shift , u32 imm , ARM64Reg Rn , ARM64Reg Rd )
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rd );
2014-02-05 01:56:23 +00:00
_assert_msg_ ( DYNA_REC , ! ( imm & ~ 0xFFF ), "%s: immediate too large: %x" , __FUNCTION__ , imm );
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Write32 (( b64Bit << 31 ) | ( op << 30 ) | ( flags << 29 ) | ( 0x11 << 24 ) | ( shift << 22 ) | \
( imm << 10 ) | ( Rn << 5 ) | Rd );
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: EncodeLogicalImmInst ( u32 op , ARM64Reg Rd , ARM64Reg Rn , u32 immr , u32 imms , int n )
2014-02-05 01:56:23 +00:00
{
// Sometimes Rd is fixed to SP, but can still be 32bit or 64bit.
// Use Rn to determine bitness here.
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rn );
2014-02-05 01:56:23 +00:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
2015-06-07 16:57:57 -05:00
Write32 (( b64Bit << 31 ) | ( op << 29 ) | ( 0x24 << 23 ) | ( n << 22 ) | \
2014-02-05 01:56:23 +00:00
( immr << 16 ) | ( imms << 10 ) | ( Rn << 5 ) | Rd );
}
2014-12-02 18:08:40 -06:00
void ARM64XEmitter :: EncodeLoadStorePair ( u32 op , u32 load , IndexType type , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , s32 imm )
{
bool b64Bit = Is64Bit ( Rt );
u32 type_encode = 0 ;
switch ( type )
{
2015-08-30 23:05:59 -05:00
case INDEX_SIGNED :
2014-12-02 18:08:40 -06:00
type_encode = 0b010 ;
break ;
case INDEX_POST :
type_encode = 0b001 ;
break ;
case INDEX_PRE :
type_encode = 0b011 ;
break ;
2015-08-30 23:05:59 -05:00
case INDEX_UNSIGNED :
_assert_msg_ ( DYNA_REC , false , "%s doesn't support INDEX_UNSIGNED!" , __FUNCTION__ );
2015-03-02 03:41:19 -06:00
break ;
2014-12-02 18:08:40 -06:00
}
if ( b64Bit )
{
op |= 0b10 ;
imm >>= 3 ;
}
else
{
imm >>= 2 ;
}
Rt = DecodeReg ( Rt );
Rt2 = DecodeReg ( Rt2 );
Rn = DecodeReg ( Rn );
Write32 (( op << 30 ) | ( 0b101 << 27 ) | ( type_encode << 23 ) | ( load << 22 ) | \
(( imm & 0x7F ) << 15 ) | ( Rt2 << 10 ) | ( Rn << 5 ) | Rt );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: EncodeAddressInst ( u32 op , ARM64Reg Rd , s32 imm )
{
Rd = DecodeReg ( Rd );
2015-06-07 16:57:57 -05:00
Write32 (( op << 31 ) | (( imm & 0x3 ) << 29 ) | ( 0x10 << 24 ) | \
2014-12-15 14:23:09 -06:00
(( imm & 0x1FFFFC ) << 3 ) | Rd );
}
2015-02-16 22:00:43 -06:00
void ARM64XEmitter :: EncodeLoadStoreUnscaled ( u32 size , u32 op , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
_assert_msg_ ( DYNA_REC , ! ( imm < - 256 || imm > 255 ), "%s received too large offset: %d" , __FUNCTION__ , imm );
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
Write32 (( size << 30 ) | ( 0b111 << 27 ) | ( op << 22 ) | (( imm & 0x1FF ) << 12 ) | ( Rn << 5 ) | Rt );
}
2015-10-22 15:20:35 -04:00
static constexpr bool IsInRangeImm19 ( s64 distance )
2015-06-07 16:57:57 -05:00
{
return ( distance >= - 0x40000 && distance <= 0x3FFFF );
}
2015-10-22 15:20:35 -04:00
static constexpr bool IsInRangeImm14 ( s64 distance )
2015-06-07 16:57:57 -05:00
{
return ( distance >= - 0x2000 && distance <= 0x1FFF );
}
2015-10-22 15:20:35 -04:00
static constexpr bool IsInRangeImm26 ( s64 distance )
2015-06-07 16:57:57 -05:00
{
return ( distance >= - 0x2000000 && distance <= 0x1FFFFFF );
}
2015-10-22 15:20:35 -04:00
static constexpr u32 MaskImm19 ( s64 distance )
2015-06-07 16:57:57 -05:00
{
return distance & 0x7FFFF ;
}
2015-10-22 15:20:35 -04:00
static constexpr u32 MaskImm14 ( s64 distance )
2015-06-07 16:57:57 -05:00
{
return distance & 0x3FFF ;
}
2015-10-22 15:20:35 -04:00
static constexpr u32 MaskImm26 ( s64 distance )
2015-06-07 16:57:57 -05:00
{
return distance & 0x3FFFFFF ;
}
2014-02-05 01:56:23 +00:00
// FixupBranch branching
2014-09-08 22:52:52 -04:00
void ARM64XEmitter :: SetJumpTarget ( FixupBranch const & branch )
2014-02-05 01:56:23 +00:00
{
bool Not = false ;
u32 inst = 0 ;
2014-09-08 22:52:52 -04:00
s64 distance = ( s64 )( m_code - branch . ptr );
2014-02-05 01:56:23 +00:00
distance >>= 2 ;
switch ( branch . type )
{
case 1 : // CBNZ
Not = true ;
case 0 : // CBZ
{
2015-06-07 16:57:57 -05:00
_assert_msg_ ( DYNA_REC , IsInRangeImm19 ( distance ), "%s(%d): Received too large distance: %lx" , __FUNCTION__ , branch . type , distance );
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( branch . reg );
2014-02-05 01:56:23 +00:00
ARM64Reg reg = DecodeReg ( branch . reg );
2015-06-07 16:57:57 -05:00
inst = ( b64Bit << 31 ) | ( 0x1A << 25 ) | ( Not << 24 ) | ( MaskImm19 ( distance ) << 5 ) | reg ;
2014-02-05 01:56:23 +00:00
}
break ;
case 2 : // B (conditional)
2015-06-07 16:57:57 -05:00
_assert_msg_ ( DYNA_REC , IsInRangeImm19 ( distance ), "%s(%d): Received too large distance: %lx" , __FUNCTION__ , branch . type , distance );
inst = ( 0x2A << 25 ) | ( MaskImm19 ( distance ) << 5 ) | branch . cond ;
2014-02-05 01:56:23 +00:00
break ;
case 4 : // TBNZ
Not = true ;
case 3 : // TBZ
{
2015-06-07 16:57:57 -05:00
_assert_msg_ ( DYNA_REC , IsInRangeImm14 ( distance ), "%s(%d): Received too large distance: %lx" , __FUNCTION__ , branch . type , distance );
2014-02-05 01:56:23 +00:00
ARM64Reg reg = DecodeReg ( branch . reg );
2015-06-07 16:57:57 -05:00
inst = (( branch . bit & 0x20 ) << 26 ) | ( 0x1B << 25 ) | ( Not << 24 ) | (( branch . bit & 0x1F ) << 19 ) | ( MaskImm14 ( distance ) << 5 ) | reg ;
2014-02-05 01:56:23 +00:00
}
break ;
case 5 : // B (uncoditional)
2015-06-07 16:57:57 -05:00
_assert_msg_ ( DYNA_REC , IsInRangeImm26 ( distance ), "%s(%d): Received too large distance: %lx" , __FUNCTION__ , branch . type , distance );
inst = ( 0x5 << 26 ) | MaskImm26 ( distance );
2014-02-05 01:56:23 +00:00
break ;
case 6 : // BL (unconditional)
2015-06-07 16:57:57 -05:00
_assert_msg_ ( DYNA_REC , IsInRangeImm26 ( distance ), "%s(%d): Received too large distance: %lx" , __FUNCTION__ , branch . type , distance );
inst = ( 0x25 << 26 ) | MaskImm26 ( distance );
2014-02-05 01:56:23 +00:00
break ;
}
* ( u32 * ) branch . ptr = inst ;
}
FixupBranch ARM64XEmitter :: CBZ ( ARM64Reg Rt )
{
FixupBranch branch ;
2014-09-08 22:52:52 -04:00
branch . ptr = m_code ;
2014-02-05 01:56:23 +00:00
branch . type = 0 ;
branch . reg = Rt ;
HINT ( HINT_NOP );
return branch ;
}
FixupBranch ARM64XEmitter :: CBNZ ( ARM64Reg Rt )
{
FixupBranch branch ;
2014-09-08 22:52:52 -04:00
branch . ptr = m_code ;
2014-02-05 01:56:23 +00:00
branch . type = 1 ;
branch . reg = Rt ;
HINT ( HINT_NOP );
return branch ;
}
FixupBranch ARM64XEmitter :: B ( CCFlags cond )
{
FixupBranch branch ;
2014-09-08 22:52:52 -04:00
branch . ptr = m_code ;
2014-02-05 01:56:23 +00:00
branch . type = 2 ;
branch . cond = cond ;
HINT ( HINT_NOP );
return branch ;
}
FixupBranch ARM64XEmitter :: TBZ ( ARM64Reg Rt , u8 bit )
{
FixupBranch branch ;
2014-09-08 22:52:52 -04:00
branch . ptr = m_code ;
2014-02-05 01:56:23 +00:00
branch . type = 3 ;
branch . reg = Rt ;
branch . bit = bit ;
HINT ( HINT_NOP );
return branch ;
}
FixupBranch ARM64XEmitter :: TBNZ ( ARM64Reg Rt , u8 bit )
{
FixupBranch branch ;
2014-09-08 22:52:52 -04:00
branch . ptr = m_code ;
2014-02-05 01:56:23 +00:00
branch . type = 4 ;
branch . reg = Rt ;
branch . bit = bit ;
HINT ( HINT_NOP );
return branch ;
}
FixupBranch ARM64XEmitter :: B ()
{
FixupBranch branch ;
2014-09-08 22:52:52 -04:00
branch . ptr = m_code ;
2014-02-05 01:56:23 +00:00
branch . type = 5 ;
HINT ( HINT_NOP );
return branch ;
}
FixupBranch ARM64XEmitter :: BL ()
{
FixupBranch branch ;
2014-09-08 22:52:52 -04:00
branch . ptr = m_code ;
2014-02-05 01:56:23 +00:00
branch . type = 6 ;
HINT ( HINT_NOP );
return branch ;
}
// Compare and Branch
void ARM64XEmitter :: CBZ ( ARM64Reg Rt , const void * ptr )
{
EncodeCompareBranchInst ( 0 , Rt , ptr );
}
void ARM64XEmitter :: CBNZ ( ARM64Reg Rt , const void * ptr )
{
EncodeCompareBranchInst ( 1 , Rt , ptr );
}
// Conditional Branch
void ARM64XEmitter :: B ( CCFlags cond , const void * ptr )
{
2015-06-07 16:57:57 -05:00
s64 distance = ( s64 ) ptr - ( s64 ) m_code ;
2014-02-05 01:56:23 +00:00
distance >>= 2 ;
2015-06-07 16:57:57 -05:00
_assert_msg_ ( DYNA_REC , IsInRangeImm19 ( distance ), "%s: Received too large distance: %p->%p %ld %lx" , __FUNCTION__ , m_code , ptr , distance , distance );
Write32 (( 0x54 << 24 ) | ( MaskImm19 ( distance ) << 5 ) | cond );
2014-02-05 01:56:23 +00:00
}
// Test and Branch
void ARM64XEmitter :: TBZ ( ARM64Reg Rt , u8 bits , const void * ptr )
{
EncodeTestBranchInst ( 0 , Rt , bits , ptr );
}
void ARM64XEmitter :: TBNZ ( ARM64Reg Rt , u8 bits , const void * ptr )
{
EncodeTestBranchInst ( 1 , Rt , bits , ptr );
}
// Unconditional Branch
2014-09-08 22:52:52 -04:00
void ARM64XEmitter :: B ( const void * ptr )
2014-02-05 01:56:23 +00:00
{
EncodeUnconditionalBranchInst ( 0 , ptr );
}
2014-09-08 22:52:52 -04:00
void ARM64XEmitter :: BL ( const void * ptr )
2014-02-05 01:56:23 +00:00
{
EncodeUnconditionalBranchInst ( 1 , ptr );
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: QuickCallFunction ( ARM64Reg scratchreg , const void * func )
{
s64 distance = ( s64 ) func - ( s64 ) m_code ;
distance >>= 2 ; // Can only branch to opcode-aligned (4) addresses
if ( ! IsInRangeImm26 ( distance ))
{
// WARN_LOG(DYNA_REC, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func);
MOVI2R ( scratchreg , ( uintptr_t ) func );
BLR ( scratchreg );
}
else
{
BL ( func );
}
}
2014-02-05 01:56:23 +00:00
// Unconditional Branch (register)
void ARM64XEmitter :: BR ( ARM64Reg Rn )
{
EncodeUnconditionalBranchInst ( 0 , 0x1F , 0 , 0 , Rn );
}
void ARM64XEmitter :: BLR ( ARM64Reg Rn )
{
EncodeUnconditionalBranchInst ( 1 , 0x1F , 0 , 0 , Rn );
}
void ARM64XEmitter :: RET ( ARM64Reg Rn )
{
EncodeUnconditionalBranchInst ( 2 , 0x1F , 0 , 0 , Rn );
}
void ARM64XEmitter :: ERET ()
{
EncodeUnconditionalBranchInst ( 4 , 0x1F , 0 , 0 , SP );
}
void ARM64XEmitter :: DRPS ()
{
EncodeUnconditionalBranchInst ( 5 , 0x1F , 0 , 0 , SP );
}
// Exception generation
void ARM64XEmitter :: SVC ( u32 imm )
{
EncodeExceptionInst ( 0 , imm );
}
void ARM64XEmitter :: HVC ( u32 imm )
{
EncodeExceptionInst ( 1 , imm );
}
void ARM64XEmitter :: SMC ( u32 imm )
{
EncodeExceptionInst ( 2 , imm );
}
void ARM64XEmitter :: BRK ( u32 imm )
{
EncodeExceptionInst ( 3 , imm );
}
void ARM64XEmitter :: HLT ( u32 imm )
{
EncodeExceptionInst ( 4 , imm );
}
void ARM64XEmitter :: DCPS1 ( u32 imm )
{
EncodeExceptionInst ( 5 , imm );
}
void ARM64XEmitter :: DCPS2 ( u32 imm )
{
EncodeExceptionInst ( 6 , imm );
}
void ARM64XEmitter :: DCPS3 ( u32 imm )
{
EncodeExceptionInst ( 7 , imm );
}
// System
void ARM64XEmitter :: _MSR ( PStateField field , u8 imm )
{
u32 op1 = 0 , op2 = 0 ;
switch ( field )
{
2015-06-07 16:57:57 -05:00
case FIELD_SPSel : op1 = 0 ; op2 = 5 ; break ;
case FIELD_DAIFSet : op1 = 3 ; op2 = 6 ; break ;
case FIELD_DAIFClr : op1 = 3 ; op2 = 7 ; break ;
default :
_assert_msg_ ( DYNA_REC , false , "Invalid PStateField to do a imm move to" );
break ;
}
EncodeSystemInst ( 0 , op1 , 4 , imm , op2 , WSP );
}
static void GetSystemReg ( PStateField field , int & o0 , int & op1 , int & CRn , int & CRm , int & op2 )
{
switch ( field )
{
case FIELD_NZCV :
o0 = 3 ; op1 = 3 ; CRn = 4 ; CRm = 2 ; op2 = 0 ;
2014-02-05 01:56:23 +00:00
break ;
2015-06-07 16:57:57 -05:00
case FIELD_FPCR :
o0 = 3 ; op1 = 3 ; CRn = 4 ; CRm = 4 ; op2 = 0 ;
2014-02-05 01:56:23 +00:00
break ;
2015-06-07 16:57:57 -05:00
case FIELD_FPSR :
o0 = 3 ; op1 = 3 ; CRn = 4 ; CRm = 4 ; op2 = 1 ;
break ;
2015-08-07 02:32:16 -05:00
case FIELD_PMCR_EL0 :
o0 = 3 ; op1 = 3 ; CRn = 9 ; CRm = 6 ; op2 = 0 ;
break ;
case FIELD_PMCCNTR_EL0 :
o0 = 3 ; op1 = 3 ; CRn = 9 ; CRm = 7 ; op2 = 0 ;
break ;
2015-06-07 16:57:57 -05:00
default :
_assert_msg_ ( DYNA_REC , false , "Invalid PStateField to do a register move from/to" );
2014-02-05 01:56:23 +00:00
break ;
}
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: _MSR ( PStateField field , ARM64Reg Rt )
{
int o0 = 0 , op1 = 0 , CRn = 0 , CRm = 0 , op2 = 0 ;
_assert_msg_ ( DYNA_REC , Is64Bit ( Rt ), "MSR: Rt must be 64-bit" );
GetSystemReg ( field , o0 , op1 , CRn , CRm , op2 );
EncodeSystemInst ( o0 , op1 , CRn , CRm , op2 , DecodeReg ( Rt ));
}
void ARM64XEmitter :: MRS ( ARM64Reg Rt , PStateField field )
{
int o0 = 0 , op1 = 0 , CRn = 0 , CRm = 0 , op2 = 0 ;
_assert_msg_ ( DYNA_REC , Is64Bit ( Rt ), "MRS: Rt must be 64-bit" );
GetSystemReg ( field , o0 , op1 , CRn , CRm , op2 );
EncodeSystemInst ( o0 | 4 , op1 , CRn , CRm , op2 , DecodeReg ( Rt ));
}
2014-02-05 01:56:23 +00:00
void ARM64XEmitter :: HINT ( SystemHint op )
{
EncodeSystemInst ( 0 , 3 , 2 , 0 , op , WSP );
}
void ARM64XEmitter :: CLREX ()
{
EncodeSystemInst ( 0 , 3 , 3 , 0 , 2 , WSP );
}
void ARM64XEmitter :: DSB ( BarrierType type )
{
EncodeSystemInst ( 0 , 3 , 3 , type , 4 , WSP );
}
void ARM64XEmitter :: DMB ( BarrierType type )
{
EncodeSystemInst ( 0 , 3 , 3 , type , 5 , WSP );
}
void ARM64XEmitter :: ISB ( BarrierType type )
{
EncodeSystemInst ( 0 , 3 , 3 , type , 6 , WSP );
}
// Add/Subtract (extended register)
void ARM64XEmitter :: ADD ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
ADD ( Rd , Rn , Rm , ArithOption ( Rd , ST_LSL , 0 ));
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: ADD ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Option )
{
EncodeArithmeticInst ( 0 , false , Rd , Rn , Rm , Option );
}
void ARM64XEmitter :: ADDS ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EncodeArithmeticInst ( 0 , true , Rd , Rn , Rm , ArithOption ( Rd , ST_LSL , 0 ));
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: ADDS ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Option )
{
EncodeArithmeticInst ( 0 , true , Rd , Rn , Rm , Option );
}
void ARM64XEmitter :: SUB ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
SUB ( Rd , Rn , Rm , ArithOption ( Rd , ST_LSL , 0 ));
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: SUB ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Option )
{
EncodeArithmeticInst ( 1 , false , Rd , Rn , Rm , Option );
}
void ARM64XEmitter :: SUBS ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EncodeArithmeticInst ( 1 , true , Rd , Rn , Rm , ArithOption ( Rd , ST_LSL , 0 ));
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: SUBS ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Option )
{
EncodeArithmeticInst ( 1 , true , Rd , Rn , Rm , Option );
}
void ARM64XEmitter :: CMN ( ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
CMN ( Rn , Rm , ArithOption ( Rn , ST_LSL , 0 ));
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: CMN ( ARM64Reg Rn , ARM64Reg Rm , ArithOption Option )
{
2015-06-07 16:57:57 -05:00
EncodeArithmeticInst ( 0 , true , Is64Bit ( Rn ) ? ZR : WZR , Rn , Rm , Option );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: CMP ( ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
CMP ( Rn , Rm , ArithOption ( Rn , ST_LSL , 0 ));
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: CMP ( ARM64Reg Rn , ARM64Reg Rm , ArithOption Option )
{
2015-06-07 16:57:57 -05:00
EncodeArithmeticInst ( 1 , true , Is64Bit ( Rn ) ? ZR : WZR , Rn , Rm , Option );
2014-02-05 01:56:23 +00:00
}
// Add/Subtract (with carry)
void ARM64XEmitter :: ADC ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeArithmeticCarryInst ( 0 , false , Rd , Rn , Rm );
}
void ARM64XEmitter :: ADCS ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeArithmeticCarryInst ( 0 , true , Rd , Rn , Rm );
}
void ARM64XEmitter :: SBC ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeArithmeticCarryInst ( 1 , false , Rd , Rn , Rm );
}
void ARM64XEmitter :: SBCS ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeArithmeticCarryInst ( 1 , true , Rd , Rn , Rm );
}
// Conditional Compare (immediate)
void ARM64XEmitter :: CCMN ( ARM64Reg Rn , u32 imm , u32 nzcv , CCFlags cond )
{
EncodeCondCompareImmInst ( 0 , Rn , imm , nzcv , cond );
}
void ARM64XEmitter :: CCMP ( ARM64Reg Rn , u32 imm , u32 nzcv , CCFlags cond )
{
EncodeCondCompareImmInst ( 1 , Rn , imm , nzcv , cond );
}
// Conditiona Compare (register)
void ARM64XEmitter :: CCMN ( ARM64Reg Rn , ARM64Reg Rm , u32 nzcv , CCFlags cond )
{
EncodeCondCompareRegInst ( 0 , Rn , Rm , nzcv , cond );
}
void ARM64XEmitter :: CCMP ( ARM64Reg Rn , ARM64Reg Rm , u32 nzcv , CCFlags cond )
{
EncodeCondCompareRegInst ( 1 , Rn , Rm , nzcv , cond );
}
// Conditional Select
void ARM64XEmitter :: CSEL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , CCFlags cond )
{
EncodeCondSelectInst ( 0 , Rd , Rn , Rm , cond );
}
void ARM64XEmitter :: CSINC ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , CCFlags cond )
{
EncodeCondSelectInst ( 1 , Rd , Rn , Rm , cond );
}
void ARM64XEmitter :: CSINV ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , CCFlags cond )
{
EncodeCondSelectInst ( 2 , Rd , Rn , Rm , cond );
}
void ARM64XEmitter :: CSNEG ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , CCFlags cond )
{
EncodeCondSelectInst ( 3 , Rd , Rn , Rm , cond );
}
// Data-Processing 1 source
void ARM64XEmitter :: RBIT ( ARM64Reg Rd , ARM64Reg Rn )
{
EncodeData1SrcInst ( 0 , Rd , Rn );
}
void ARM64XEmitter :: REV16 ( ARM64Reg Rd , ARM64Reg Rn )
{
EncodeData1SrcInst ( 1 , Rd , Rn );
}
void ARM64XEmitter :: REV32 ( ARM64Reg Rd , ARM64Reg Rn )
{
EncodeData1SrcInst ( 2 , Rd , Rn );
}
void ARM64XEmitter :: REV64 ( ARM64Reg Rd , ARM64Reg Rn )
{
EncodeData1SrcInst ( 3 , Rd , Rn );
}
void ARM64XEmitter :: CLZ ( ARM64Reg Rd , ARM64Reg Rn )
{
EncodeData1SrcInst ( 4 , Rd , Rn );
}
void ARM64XEmitter :: CLS ( ARM64Reg Rd , ARM64Reg Rn )
{
EncodeData1SrcInst ( 5 , Rd , Rn );
}
// Data-Processing 2 source
void ARM64XEmitter :: UDIV ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 0 , Rd , Rn , Rm );
}
void ARM64XEmitter :: SDIV ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 1 , Rd , Rn , Rm );
}
void ARM64XEmitter :: LSLV ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 2 , Rd , Rn , Rm );
}
void ARM64XEmitter :: LSRV ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 3 , Rd , Rn , Rm );
}
void ARM64XEmitter :: ASRV ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 4 , Rd , Rn , Rm );
}
void ARM64XEmitter :: RORV ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 5 , Rd , Rn , Rm );
}
void ARM64XEmitter :: CRC32B ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 6 , Rd , Rn , Rm );
}
void ARM64XEmitter :: CRC32H ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 7 , Rd , Rn , Rm );
}
void ARM64XEmitter :: CRC32W ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 8 , Rd , Rn , Rm );
}
void ARM64XEmitter :: CRC32CB ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 9 , Rd , Rn , Rm );
}
void ARM64XEmitter :: CRC32CH ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 10 , Rd , Rn , Rm );
}
void ARM64XEmitter :: CRC32CW ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 11 , Rd , Rn , Rm );
}
void ARM64XEmitter :: CRC32X ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 12 , Rd , Rn , Rm );
}
void ARM64XEmitter :: CRC32CX ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData2SrcInst ( 13 , Rd , Rn , Rm );
}
// Data-Processing 3 source
void ARM64XEmitter :: MADD ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EncodeData3SrcInst ( 0 , Rd , Rn , Rm , Ra );
}
void ARM64XEmitter :: MSUB ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EncodeData3SrcInst ( 1 , Rd , Rn , Rm , Ra );
}
void ARM64XEmitter :: SMADDL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EncodeData3SrcInst ( 2 , Rd , Rn , Rm , Ra );
}
2015-02-12 18:47:06 -06:00
void ARM64XEmitter :: SMULL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
SMADDL ( Rd , Rn , Rm , SP );
}
2014-02-05 01:56:23 +00:00
void ARM64XEmitter :: SMSUBL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EncodeData3SrcInst ( 3 , Rd , Rn , Rm , Ra );
}
2015-01-22 18:08:49 -06:00
void ARM64XEmitter :: SMULH ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
2014-02-05 01:56:23 +00:00
{
2015-01-22 18:08:49 -06:00
EncodeData3SrcInst ( 4 , Rd , Rn , Rm , SP );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: UMADDL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EncodeData3SrcInst ( 5 , Rd , Rn , Rm , Ra );
}
void ARM64XEmitter :: UMSUBL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EncodeData3SrcInst ( 6 , Rd , Rn , Rm , Ra );
}
2015-01-22 18:08:49 -06:00
void ARM64XEmitter :: UMULH ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
2014-02-05 01:56:23 +00:00
{
2015-01-22 18:08:49 -06:00
EncodeData3SrcInst ( 7 , Rd , Rn , Rm , SP );
2014-02-05 01:56:23 +00:00
}
2015-01-07 13:03:01 -06:00
void ARM64XEmitter :: MUL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData3SrcInst ( 0 , Rd , Rn , Rm , SP );
}
void ARM64XEmitter :: MNEG ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EncodeData3SrcInst ( 1 , Rd , Rn , Rm , SP );
}
2014-02-05 01:56:23 +00:00
// Logical (shifted register)
void ARM64XEmitter :: AND ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Shift )
{
EncodeLogicalInst ( 0 , Rd , Rn , Rm , Shift );
}
void ARM64XEmitter :: BIC ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Shift )
{
EncodeLogicalInst ( 1 , Rd , Rn , Rm , Shift );
}
void ARM64XEmitter :: ORR ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Shift )
{
EncodeLogicalInst ( 2 , Rd , Rn , Rm , Shift );
}
void ARM64XEmitter :: ORN ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Shift )
{
EncodeLogicalInst ( 3 , Rd , Rn , Rm , Shift );
}
void ARM64XEmitter :: EOR ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Shift )
{
EncodeLogicalInst ( 4 , Rd , Rn , Rm , Shift );
}
void ARM64XEmitter :: EON ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Shift )
{
EncodeLogicalInst ( 5 , Rd , Rn , Rm , Shift );
}
void ARM64XEmitter :: ANDS ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Shift )
{
EncodeLogicalInst ( 6 , Rd , Rn , Rm , Shift );
}
void ARM64XEmitter :: BICS ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ArithOption Shift )
{
EncodeLogicalInst ( 7 , Rd , Rn , Rm , Shift );
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: MOV ( ARM64Reg Rd , ARM64Reg Rm , ArithOption Shift )
{
ORR ( Rd , Is64Bit ( Rd ) ? ZR : WZR , Rm , Shift );
}
2014-09-18 16:30:40 -05:00
void ARM64XEmitter :: MOV ( ARM64Reg Rd , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
if ( IsGPR ( Rd ) && IsGPR ( Rm ))
ORR ( Rd , Is64Bit ( Rd ) ? ZR : WZR , Rm , ArithOption ( Rm , ST_LSL , 0 ));
else
_assert_msg_ ( DYNA_REC , false , "Non-GPRs not supported in MOV" );
2014-09-18 16:30:40 -05:00
}
void ARM64XEmitter :: MVN ( ARM64Reg Rd , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
ORN ( Rd , Is64Bit ( Rd ) ? ZR : WZR , Rm , ArithOption ( Rm , ST_LSL , 0 ));
}
void ARM64XEmitter :: LSL ( ARM64Reg Rd , ARM64Reg Rm , int shift )
{
ORR ( Rd , Is64Bit ( Rd ) ? ZR : WZR , Rm , ArithOption ( Rm , ST_LSL , shift ));
}
void ARM64XEmitter :: LSR ( ARM64Reg Rd , ARM64Reg Rm , int shift )
{
ORR ( Rd , Is64Bit ( Rd ) ? ZR : WZR , Rm , ArithOption ( Rm , ST_LSR , shift ));
}
void ARM64XEmitter :: ASR ( ARM64Reg Rd , ARM64Reg Rm , int shift )
{
ORR ( Rd , Is64Bit ( Rd ) ? ZR : WZR , Rm , ArithOption ( Rm , ST_ASR , shift ));
}
void ARM64XEmitter :: ROR ( ARM64Reg Rd , ARM64Reg Rm , int shift )
{
ORR ( Rd , Is64Bit ( Rd ) ? ZR : WZR , Rm , ArithOption ( Rm , ST_ROR , shift ));
2014-09-18 16:30:40 -05:00
}
2014-02-05 01:56:23 +00:00
// Logical (immediate)
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: AND ( ARM64Reg Rd , ARM64Reg Rn , u32 immr , u32 imms , bool invert )
2014-02-05 01:56:23 +00:00
{
2015-06-07 16:57:57 -05:00
EncodeLogicalImmInst ( 0 , Rd , Rn , immr , imms , invert );
2014-02-05 01:56:23 +00:00
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: ANDS ( ARM64Reg Rd , ARM64Reg Rn , u32 immr , u32 imms , bool invert )
2014-02-05 01:56:23 +00:00
{
2015-06-07 16:57:57 -05:00
EncodeLogicalImmInst ( 3 , Rd , Rn , immr , imms , invert );
2014-02-05 01:56:23 +00:00
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: EOR ( ARM64Reg Rd , ARM64Reg Rn , u32 immr , u32 imms , bool invert )
2014-02-05 01:56:23 +00:00
{
2015-06-07 16:57:57 -05:00
EncodeLogicalImmInst ( 2 , Rd , Rn , immr , imms , invert );
2014-02-05 01:56:23 +00:00
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: ORR ( ARM64Reg Rd , ARM64Reg Rn , u32 immr , u32 imms , bool invert )
2014-02-05 01:56:23 +00:00
{
2015-06-07 16:57:57 -05:00
EncodeLogicalImmInst ( 1 , Rd , Rn , immr , imms , invert );
2014-02-05 01:56:23 +00:00
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: TST ( ARM64Reg Rn , u32 immr , u32 imms , bool invert )
2014-02-05 01:56:23 +00:00
{
2015-06-07 16:57:57 -05:00
EncodeLogicalImmInst ( 3 , Is64Bit ( Rn ) ? ZR : WZR , Rn , immr , imms , invert );
2014-02-05 01:56:23 +00:00
}
// Add/subtract (immediate)
void ARM64XEmitter :: ADD ( ARM64Reg Rd , ARM64Reg Rn , u32 imm , bool shift )
{
EncodeAddSubImmInst ( 0 , false , shift , imm , Rn , Rd );
}
void ARM64XEmitter :: ADDS ( ARM64Reg Rd , ARM64Reg Rn , u32 imm , bool shift )
{
EncodeAddSubImmInst ( 0 , true , shift , imm , Rn , Rd );
}
void ARM64XEmitter :: SUB ( ARM64Reg Rd , ARM64Reg Rn , u32 imm , bool shift )
{
EncodeAddSubImmInst ( 1 , false , shift , imm , Rn , Rd );
}
void ARM64XEmitter :: SUBS ( ARM64Reg Rd , ARM64Reg Rn , u32 imm , bool shift )
{
EncodeAddSubImmInst ( 1 , true , shift , imm , Rn , Rd );
}
void ARM64XEmitter :: CMP ( ARM64Reg Rn , u32 imm , bool shift )
{
2014-09-08 22:52:52 -04:00
EncodeAddSubImmInst ( 1 , true , shift , imm , Rn , Is64Bit ( Rn ) ? SP : WSP );
2014-02-05 01:56:23 +00:00
}
// Data Processing (Immediate)
void ARM64XEmitter :: MOVZ ( ARM64Reg Rd , u32 imm , ShiftAmount pos )
{
EncodeMOVWideInst ( 2 , Rd , imm , pos );
}
void ARM64XEmitter :: MOVN ( ARM64Reg Rd , u32 imm , ShiftAmount pos )
{
EncodeMOVWideInst ( 0 , Rd , imm , pos );
}
void ARM64XEmitter :: MOVK ( ARM64Reg Rd , u32 imm , ShiftAmount pos )
{
EncodeMOVWideInst ( 3 , Rd , imm , pos );
}
// Bitfield move
void ARM64XEmitter :: BFM ( ARM64Reg Rd , ARM64Reg Rn , u32 immr , u32 imms )
{
EncodeBitfieldMOVInst ( 1 , Rd , Rn , immr , imms );
}
void ARM64XEmitter :: SBFM ( ARM64Reg Rd , ARM64Reg Rn , u32 immr , u32 imms )
{
EncodeBitfieldMOVInst ( 0 , Rd , Rn , immr , imms );
}
void ARM64XEmitter :: UBFM ( ARM64Reg Rd , ARM64Reg Rn , u32 immr , u32 imms )
{
EncodeBitfieldMOVInst ( 2 , Rd , Rn , immr , imms );
}
2015-06-29 19:00:22 -05:00
void ARM64XEmitter :: BFI ( ARM64Reg Rd , ARM64Reg Rn , u32 lsb , u32 width )
{
u32 size = Is64Bit ( Rn ) ? 64 : 32 ;
_assert_msg_ ( DYNA_REC , ( lsb + width ) <= size , "%s passed lsb %d and width %d which is greater than the register size!" ,
__FUNCTION__ , lsb , width );
EncodeBitfieldMOVInst ( 1 , Rd , Rn , ( size - lsb ) % size , width - 1 );
}
void ARM64XEmitter :: UBFIZ ( ARM64Reg Rd , ARM64Reg Rn , u32 lsb , u32 width )
{
u32 size = Is64Bit ( Rn ) ? 64 : 32 ;
_assert_msg_ ( DYNA_REC , ( lsb + width ) <= size , "%s passed lsb %d and width %d which is greater than the register size!" ,
__FUNCTION__ , lsb , width );
EncodeBitfieldMOVInst ( 2 , Rd , Rn , ( size - lsb ) % size , width - 1 );
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: EXTR ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , u32 shift )
{
bool sf = Is64Bit ( Rd );
bool N = sf ;
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
Write32 (( sf << 31 ) | ( 0x27 << 23 ) | ( N << 22 ) | ( Rm << 16 ) | ( shift << 10 ) | ( Rm << 5 ) | Rd );
}
2014-09-10 17:52:54 -05:00
void ARM64XEmitter :: SXTB ( ARM64Reg Rd , ARM64Reg Rn )
{
SBFM ( Rd , Rn , 0 , 7 );
}
void ARM64XEmitter :: SXTH ( ARM64Reg Rd , ARM64Reg Rn )
{
SBFM ( Rd , Rn , 0 , 15 );
}
void ARM64XEmitter :: SXTW ( ARM64Reg Rd , ARM64Reg Rn )
{
_assert_msg_ ( DYNA_REC , Is64Bit ( Rd ), "%s requires 64bit register as destination" , __FUNCTION__ );
SBFM ( Rd , Rn , 0 , 31 );
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: UXTB ( ARM64Reg Rd , ARM64Reg Rn )
{
UBFM ( Rd , Rn , 0 , 7 );
}
void ARM64XEmitter :: UXTH ( ARM64Reg Rd , ARM64Reg Rn )
{
UBFM ( Rd , Rn , 0 , 15 );
}
2014-02-05 01:56:23 +00:00
// Load Register (Literal)
void ARM64XEmitter :: LDR ( ARM64Reg Rt , u32 imm )
{
EncodeLoadRegisterInst ( 0 , Rt , imm );
}
void ARM64XEmitter :: LDRSW ( ARM64Reg Rt , u32 imm )
{
EncodeLoadRegisterInst ( 2 , Rt , imm );
}
void ARM64XEmitter :: PRFM ( ARM64Reg Rt , u32 imm )
{
EncodeLoadRegisterInst ( 3 , Rt , imm );
}
2014-12-02 18:08:40 -06:00
// Load/Store pair
void ARM64XEmitter :: LDP ( IndexType type , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , s32 imm )
{
EncodeLoadStorePair ( 0 , 1 , type , Rt , Rt2 , Rn , imm );
}
void ARM64XEmitter :: LDPSW ( IndexType type , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , s32 imm )
{
EncodeLoadStorePair ( 1 , 1 , type , Rt , Rt2 , Rn , imm );
}
void ARM64XEmitter :: STP ( IndexType type , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , s32 imm )
{
EncodeLoadStorePair ( 0 , 0 , type , Rt , Rt2 , Rn , imm );
}
2014-02-05 01:56:23 +00:00
// Load/Store Exclusive
void ARM64XEmitter :: STXRB ( ARM64Reg Rs , ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 0 , Rs , SP , Rt , Rn );
}
void ARM64XEmitter :: STLXRB ( ARM64Reg Rs , ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 1 , Rs , SP , Rt , Rn );
}
void ARM64XEmitter :: LDXRB ( ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 2 , SP , SP , Rt , Rn );
}
void ARM64XEmitter :: LDAXRB ( ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 3 , SP , SP , Rt , Rn );
}
void ARM64XEmitter :: STLRB ( ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 4 , SP , SP , Rt , Rn );
}
void ARM64XEmitter :: LDARB ( ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 5 , SP , SP , Rt , Rn );
}
void ARM64XEmitter :: STXRH ( ARM64Reg Rs , ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 6 , Rs , SP , Rt , Rn );
}
void ARM64XEmitter :: STLXRH ( ARM64Reg Rs , ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 7 , Rs , SP , Rt , Rn );
}
void ARM64XEmitter :: LDXRH ( ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 8 , SP , SP , Rt , Rn );
}
void ARM64XEmitter :: LDAXRH ( ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 9 , SP , SP , Rt , Rn );
}
void ARM64XEmitter :: STLRH ( ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 10 , SP , SP , Rt , Rn );
}
void ARM64XEmitter :: LDARH ( ARM64Reg Rt , ARM64Reg Rn )
{
EncodeLoadStoreExcInst ( 11 , SP , SP , Rt , Rn );
}
void ARM64XEmitter :: STXR ( ARM64Reg Rs , ARM64Reg Rt , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 12 + Is64Bit ( Rt ), Rs , SP , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: STLXR ( ARM64Reg Rs , ARM64Reg Rt , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 14 + Is64Bit ( Rt ), Rs , SP , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: STXP ( ARM64Reg Rs , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 16 + Is64Bit ( Rt ), Rs , Rt2 , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: STLXP ( ARM64Reg Rs , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 18 + Is64Bit ( Rt ), Rs , Rt2 , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: LDXR ( ARM64Reg Rt , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 20 + Is64Bit ( Rt ), SP , SP , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: LDAXR ( ARM64Reg Rt , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 22 + Is64Bit ( Rt ), SP , SP , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: LDXP ( ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 24 + Is64Bit ( Rt ), SP , Rt2 , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: LDAXP ( ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 26 + Is64Bit ( Rt ), SP , Rt2 , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: STLR ( ARM64Reg Rt , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 28 + Is64Bit ( Rt ), SP , SP , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
void ARM64XEmitter :: LDAR ( ARM64Reg Rt , ARM64Reg Rn )
{
2014-09-08 22:52:52 -04:00
EncodeLoadStoreExcInst ( 30 + Is64Bit ( Rt ), SP , SP , Rt , Rn );
2014-02-05 01:56:23 +00:00
}
// Load/Store no-allocate pair (offset)
void ARM64XEmitter :: STNP ( ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , u32 imm )
{
EncodeLoadStorePairedInst ( 0xA0 , Rt , Rt2 , Rn , imm );
}
void ARM64XEmitter :: LDNP ( ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , u32 imm )
{
EncodeLoadStorePairedInst ( 0xA1 , Rt , Rt2 , Rn , imm );
}
// Load/Store register (immediate post-indexed)
// XXX: Most of these support vectors
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: STRB ( IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
if ( type == INDEX_UNSIGNED )
2015-01-07 12:58:37 -06:00
EncodeLoadStoreIndexedInst ( 0x0E4 , Rt , Rn , imm , 8 );
2014-02-05 01:56:23 +00:00
else
EncodeLoadStoreIndexedInst ( 0x0E0 ,
type == INDEX_POST ? 1 : 3 , Rt , Rn , imm );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: LDRB ( IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
if ( type == INDEX_UNSIGNED )
2015-01-07 12:58:37 -06:00
EncodeLoadStoreIndexedInst ( 0x0E5 , Rt , Rn , imm , 8 );
2014-02-05 01:56:23 +00:00
else
EncodeLoadStoreIndexedInst ( 0x0E1 ,
type == INDEX_POST ? 1 : 3 , Rt , Rn , imm );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: LDRSB ( IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
if ( type == INDEX_UNSIGNED )
2015-01-07 12:58:37 -06:00
EncodeLoadStoreIndexedInst ( Is64Bit ( Rt ) ? 0x0E6 : 0x0E7 , Rt , Rn , imm , 8 );
2014-02-05 01:56:23 +00:00
else
2014-09-08 22:52:52 -04:00
EncodeLoadStoreIndexedInst ( Is64Bit ( Rt ) ? 0x0E2 : 0x0E3 ,
2014-02-05 01:56:23 +00:00
type == INDEX_POST ? 1 : 3 , Rt , Rn , imm );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: STRH ( IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
if ( type == INDEX_UNSIGNED )
2015-01-07 12:58:37 -06:00
EncodeLoadStoreIndexedInst ( 0x1E4 , Rt , Rn , imm , 16 );
2014-02-05 01:56:23 +00:00
else
EncodeLoadStoreIndexedInst ( 0x1E0 ,
type == INDEX_POST ? 1 : 3 , Rt , Rn , imm );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: LDRH ( IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
if ( type == INDEX_UNSIGNED )
2015-01-07 12:58:37 -06:00
EncodeLoadStoreIndexedInst ( 0x1E5 , Rt , Rn , imm , 16 );
2014-02-05 01:56:23 +00:00
else
EncodeLoadStoreIndexedInst ( 0x1E1 ,
type == INDEX_POST ? 1 : 3 , Rt , Rn , imm );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: LDRSH ( IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
if ( type == INDEX_UNSIGNED )
2015-01-07 12:58:37 -06:00
EncodeLoadStoreIndexedInst ( Is64Bit ( Rt ) ? 0x1E6 : 0x1E7 , Rt , Rn , imm , 16 );
2014-02-05 01:56:23 +00:00
else
2014-09-08 22:52:52 -04:00
EncodeLoadStoreIndexedInst ( Is64Bit ( Rt ) ? 0x1E2 : 0x1E3 ,
2014-02-05 01:56:23 +00:00
type == INDEX_POST ? 1 : 3 , Rt , Rn , imm );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: STR ( IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
if ( type == INDEX_UNSIGNED )
2015-01-07 12:58:37 -06:00
EncodeLoadStoreIndexedInst ( Is64Bit ( Rt ) ? 0x3E4 : 0x2E4 , Rt , Rn , imm , Is64Bit ( Rt ) ? 64 : 32 );
2014-02-05 01:56:23 +00:00
else
2014-09-08 22:52:52 -04:00
EncodeLoadStoreIndexedInst ( Is64Bit ( Rt ) ? 0x3E0 : 0x2E0 ,
2014-02-05 01:56:23 +00:00
type == INDEX_POST ? 1 : 3 , Rt , Rn , imm );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: LDR ( IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
if ( type == INDEX_UNSIGNED )
2015-01-07 12:58:37 -06:00
EncodeLoadStoreIndexedInst ( Is64Bit ( Rt ) ? 0x3E5 : 0x2E5 , Rt , Rn , imm , Is64Bit ( Rt ) ? 64 : 32 );
2014-02-05 01:56:23 +00:00
else
2014-09-08 22:52:52 -04:00
EncodeLoadStoreIndexedInst ( Is64Bit ( Rt ) ? 0x3E1 : 0x2E1 ,
2014-02-05 01:56:23 +00:00
type == INDEX_POST ? 1 : 3 , Rt , Rn , imm );
}
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: LDRSW ( IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
2014-02-05 01:56:23 +00:00
{
if ( type == INDEX_UNSIGNED )
2015-01-07 12:58:37 -06:00
EncodeLoadStoreIndexedInst ( 0x2E6 , Rt , Rn , imm , 32 );
2014-02-05 01:56:23 +00:00
else
EncodeLoadStoreIndexedInst ( 0x2E2 ,
type == INDEX_POST ? 1 : 3 , Rt , Rn , imm );
}
// Load/Store register (register offset)
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: STRB ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 0 , 0 , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: LDRB ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 0 , 1 , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: LDRSB ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 0 , 3 - b64Bit , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: STRH ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 1 , 0 , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: LDRH ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 1 , 1 , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: LDRSH ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 1 , 3 - b64Bit , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: STR ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 2 + b64Bit , 0 , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: LDR ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2014-09-08 22:52:52 -04:00
bool b64Bit = Is64Bit ( Rt );
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 2 + b64Bit , 1 , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: LDRSW ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 2 , 2 , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-01-18 16:25:40 -06:00
void ARM64XEmitter :: PRFM ( ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
2014-02-05 01:56:23 +00:00
{
2015-01-18 16:25:40 -06:00
EncodeLoadStoreRegisterOffset ( 3 , 2 , Rt , Rn , Rm );
2014-02-05 01:56:23 +00:00
}
2015-02-16 22:00:43 -06:00
// Load/Store register (unscaled offset)
void ARM64XEmitter :: STURB ( ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EncodeLoadStoreUnscaled ( 0 , 0 , Rt , Rn , imm );
}
void ARM64XEmitter :: LDURB ( ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EncodeLoadStoreUnscaled ( 0 , 1 , Rt , Rn , imm );
}
void ARM64XEmitter :: LDURSB ( ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EncodeLoadStoreUnscaled ( 0 , Is64Bit ( Rt ) ? 2 : 3 , Rt , Rn , imm );
}
void ARM64XEmitter :: STURH ( ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EncodeLoadStoreUnscaled ( 1 , 0 , Rt , Rn , imm );
}
void ARM64XEmitter :: LDURH ( ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EncodeLoadStoreUnscaled ( 1 , 1 , Rt , Rn , imm );
}
void ARM64XEmitter :: LDURSH ( ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EncodeLoadStoreUnscaled ( 1 , Is64Bit ( Rt ) ? 2 : 3 , Rt , Rn , imm );
}
void ARM64XEmitter :: STUR ( ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EncodeLoadStoreUnscaled ( Is64Bit ( Rt ) ? 3 : 2 , 0 , Rt , Rn , imm );
}
void ARM64XEmitter :: LDUR ( ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EncodeLoadStoreUnscaled ( Is64Bit ( Rt ) ? 3 : 2 , 1 , Rt , Rn , imm );
}
void ARM64XEmitter :: LDURSW ( ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
_assert_msg_ ( DYNA_REC , ! Is64Bit ( Rt ), "%s must have a 64bit destination register!" , __FUNCTION__ );
EncodeLoadStoreUnscaled ( 2 , 2 , Rt , Rn , imm );
}
2014-12-15 14:23:09 -06:00
// Address of label/page PC-relative
void ARM64XEmitter :: ADR ( ARM64Reg Rd , s32 imm )
{
EncodeAddressInst ( 0 , Rd , imm );
}
void ARM64XEmitter :: ADRP ( ARM64Reg Rd , s32 imm )
{
EncodeAddressInst ( 1 , Rd , imm >> 12 );
}
2015-06-07 16:57:57 -05:00
// Wrapper around MOVZ+MOVK (and later MOVN)
2014-02-05 01:56:23 +00:00
void ARM64XEmitter :: MOVI2R ( ARM64Reg Rd , u64 imm , bool optimize )
{
2015-06-07 16:57:57 -05:00
unsigned int parts = Is64Bit ( Rd ) ? 4 : 2 ;
2014-12-15 14:23:09 -06:00
BitSet32 upload_part ( 0 );
2015-06-07 16:57:57 -05:00
// Always start with a movz! Kills the dependency on the register.
bool use_movz = true ;
2014-02-05 01:56:23 +00:00
2014-09-12 05:45:10 -05:00
if ( ! imm )
{
2015-06-07 16:57:57 -05:00
// Zero immediate, just clear the register. EOR is pointless when we have MOVZ, which looks clearer in disasm too.
MOVZ ( Rd , 0 , SHIFT_0 );
2014-09-12 05:45:10 -05:00
return ;
}
if (( Is64Bit ( Rd ) && imm == std :: numeric_limits < u64 >:: max ()) ||
( ! Is64Bit ( Rd ) && imm == std :: numeric_limits < u32 >:: max ()))
{
2015-06-07 16:57:57 -05:00
// Max unsigned value (or if signed, -1)
2014-09-12 05:45:10 -05:00
// Set to ~ZR
ARM64Reg ZR = Is64Bit ( Rd ) ? SP : WSP ;
2015-01-07 13:00:39 -06:00
ORN ( Rd , ZR , ZR , ArithOption ( ZR , ST_LSL , 0 ));
2014-09-12 05:45:10 -05:00
return ;
}
2015-06-07 16:57:57 -05:00
// TODO: Make some more systemic use of MOVN, but this will take care of most cases.
// Small negative integer. Use MOVN
if ( ! Is64Bit ( Rd ) && ( imm | 0xFFFF0000 ) == imm )
{
MOVN ( Rd , ~ imm , SHIFT_0 );
return ;
}
// XXX: Use MOVN when possible.
2014-02-05 01:56:23 +00:00
// XXX: Optimize more
// XXX: Support rotating immediates to save instructions
if ( optimize )
{
2015-06-07 16:57:57 -05:00
for ( unsigned int i = 0 ; i < parts ; ++ i )
2014-02-05 01:56:23 +00:00
{
if (( imm >> ( i * 16 )) & 0xFFFF )
2014-12-15 14:23:09 -06:00
upload_part [ i ] = 1 ;
2014-02-05 01:56:23 +00:00
}
}
2014-12-15 14:23:09 -06:00
u64 aligned_pc = ( u64 ) GetCodePtr () & ~ 0xFFF ;
s64 aligned_offset = ( s64 ) imm - ( s64 ) aligned_pc ;
2015-06-07 16:57:57 -05:00
if ( upload_part . Count () > 1 && std :: abs ( aligned_offset ) < 0xFFFFFFFFLL )
2014-12-15 14:23:09 -06:00
{
// Immediate we are loading is within 4GB of our aligned range
// Most likely a address that we can load in one or two instructions
if ( ! ( std :: abs ( aligned_offset ) & 0xFFF ))
{
// Aligned ADR
ADRP ( Rd , ( s32 ) aligned_offset );
return ;
}
else
{
// If the address is within 1MB of PC we can load it in a single instruction still
s64 offset = ( s64 ) imm - ( s64 ) GetCodePtr ();
if ( offset >= - 0xFFFFF && offset <= 0xFFFFF )
{
ADR ( Rd , ( s32 ) offset );
return ;
}
else
{
ADRP ( Rd , ( s32 )( aligned_offset & ~ 0xFFF ));
ADD ( Rd , Rd , imm & 0xFFF );
return ;
}
}
}
2014-02-05 01:56:23 +00:00
for ( unsigned i = 0 ; i < parts ; ++ i )
{
2015-06-07 16:57:57 -05:00
if ( use_movz && upload_part [ i ])
2014-02-05 01:56:23 +00:00
{
MOVZ ( Rd , ( imm >> ( i * 16 )) & 0xFFFF , ( ShiftAmount ) i );
2015-06-07 16:57:57 -05:00
use_movz = false ;
2014-02-05 01:56:23 +00:00
}
else
{
if ( upload_part [ i ] || ! optimize )
MOVK ( Rd , ( imm >> ( i * 16 )) & 0xFFFF , ( ShiftAmount ) i );
}
}
2014-12-15 14:23:09 -06:00
}
2014-02-05 01:56:23 +00:00
2014-12-15 14:23:09 -06:00
void ARM64XEmitter :: ABI_PushRegisters ( BitSet32 registers )
{
int num_regs = registers . Count ();
if ( num_regs % 2 )
{
bool first = true ;
// Stack is required to be quad-word aligned.
u32 stack_size = ROUND_UP ( num_regs * 8 , 16 );
u32 current_offset = 0 ;
std :: vector < ARM64Reg > reg_pair ;
for ( auto it : registers )
{
if ( first )
{
2015-06-07 16:57:57 -05:00
STR ( INDEX_PRE , ( ARM64Reg )( X0 + it ), SP , - ( s32 ) stack_size );
2014-12-15 14:23:09 -06:00
first = false ;
current_offset += 16 ;
}
else
{
reg_pair . push_back (( ARM64Reg )( X0 + it ));
if ( reg_pair . size () == 2 )
{
2015-08-30 23:05:59 -05:00
STP ( INDEX_SIGNED , reg_pair [ 0 ], reg_pair [ 1 ], SP , current_offset );
2014-12-15 14:23:09 -06:00
reg_pair . clear ();
current_offset += 16 ;
}
}
}
}
else
{
std :: vector < ARM64Reg > reg_pair ;
for ( auto it : registers )
{
reg_pair . push_back (( ARM64Reg )( X0 + it ));
if ( reg_pair . size () == 2 )
{
STP ( INDEX_PRE , reg_pair [ 0 ], reg_pair [ 1 ], SP , - 16 );
reg_pair . clear ();
}
}
}
}
void ARM64XEmitter :: ABI_PopRegisters ( BitSet32 registers , BitSet32 ignore_mask )
{
int num_regs = registers . Count ();
if ( num_regs % 2 )
{
bool first = true ;
std :: vector < ARM64Reg > reg_pair ;
for ( auto it : registers )
{
if ( ignore_mask [ it ])
it = WSP ;
if ( first )
{
LDR ( INDEX_POST , ( ARM64Reg )( X0 + it ), SP , 16 );
first = false ;
}
else
{
reg_pair . push_back (( ARM64Reg )( X0 + it ));
if ( reg_pair . size () == 2 )
{
LDP ( INDEX_POST , reg_pair [ 0 ], reg_pair [ 1 ], SP , 16 );
reg_pair . clear ();
}
}
}
}
else
{
std :: vector < ARM64Reg > reg_pair ;
for ( int i = 31 ; i >= 0 ; -- i )
{
if ( ! registers [ i ])
continue ;
int reg = i ;
if ( ignore_mask [ reg ])
reg = WSP ;
reg_pair . push_back (( ARM64Reg )( X0 + reg ));
if ( reg_pair . size () == 2 )
{
LDP ( INDEX_POST , reg_pair [ 1 ], reg_pair [ 0 ], SP , 16 );
reg_pair . clear ();
}
}
}
2014-02-05 01:56:23 +00:00
}
2015-01-07 13:42:36 -06:00
// Float Emitter
void ARM64FloatEmitter :: EmitLoadStoreImmediate ( u8 size , u32 opc , IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
u32 encoded_size = 0 ;
u32 encoded_imm = 0 ;
if ( size == 8 )
encoded_size = 0 ;
else if ( size == 16 )
encoded_size = 1 ;
else if ( size == 32 )
encoded_size = 2 ;
else if ( size == 64 )
encoded_size = 3 ;
else if ( size == 128 )
encoded_size = 0 ;
if ( type == INDEX_UNSIGNED )
{
2015-06-07 16:57:57 -05:00
_assert_msg_ ( DYNA_REC , ! ( imm & (( size - 1 ) >> 3 )), "%s(INDEX_UNSIGNED) immediate offset must be aligned to size! (%d) (%p)" , __FUNCTION__ , imm , m_emit -> GetCodePtr ());
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , imm >= 0 , "%s(INDEX_UNSIGNED) immediate offset must be positive!" , __FUNCTION__ );
2015-01-07 13:42:36 -06:00
if ( size == 16 )
imm >>= 1 ;
else if ( size == 32 )
imm >>= 2 ;
else if ( size == 64 )
imm >>= 3 ;
else if ( size == 128 )
imm >>= 4 ;
encoded_imm = ( imm & 0xFFF );
}
else
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! ( imm < - 256 || imm > 255 ), "%s immediate offset must be within range of -256 to 256!" , __FUNCTION__ );
2015-01-07 13:42:36 -06:00
encoded_imm = ( imm & 0x1FF ) << 2 ;
if ( type == INDEX_POST )
encoded_imm |= 1 ;
else
encoded_imm |= 3 ;
}
2015-06-07 16:57:57 -05:00
Write32 (( encoded_size << 30 ) | ( 0xF << 26 ) | ( type == INDEX_UNSIGNED ? ( 1 << 24 ) : 0 ) | \
2015-01-07 13:42:36 -06:00
( size == 128 ? ( 1 << 23 ) : 0 ) | ( opc << 22 ) | ( encoded_imm << 10 ) | ( Rn << 5 ) | Rt );
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: EmitScalar2Source ( bool M , bool S , u32 type , u32 opcode , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
2015-01-07 13:42:36 -06:00
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsQuad ( Rd ), "%s only supports double and single registers!" , __FUNCTION__ );
2015-01-07 13:42:36 -06:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
Write32 (( M << 31 ) | ( S << 29 ) | ( 0b11110001 << 21 ) | ( type << 22 ) | ( Rm << 16 ) | \
( opcode << 12 ) | ( 1 << 11 ) | ( Rn << 5 ) | Rd );
}
void ARM64FloatEmitter :: EmitThreeSame ( bool U , u32 size , u32 opcode , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsSingle ( Rd ), "%s doesn't support singles!" , __FUNCTION__ );
2015-01-07 13:42:36 -06:00
bool quad = IsQuad ( Rd );
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
Write32 (( quad << 30 ) | ( U << 29 ) | ( 0b1110001 << 21 ) | ( size << 22 ) | \
( Rm << 16 ) | ( opcode << 11 ) | ( 1 << 10 ) | ( Rn << 5 ) | Rd );
}
void ARM64FloatEmitter :: EmitCopy ( bool Q , u32 op , u32 imm5 , u32 imm4 , ARM64Reg Rd , ARM64Reg Rn )
{
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Write32 (( Q << 30 ) | ( op << 29 ) | ( 0b111 << 25 ) | ( imm5 << 16 ) | ( imm4 << 11 ) | \
( 1 << 10 ) | ( Rn << 5 ) | Rd );
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: Emit2RegMisc ( bool Q , bool U , u32 size , u32 opcode , ARM64Reg Rd , ARM64Reg Rn )
2015-01-07 13:42:36 -06:00
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsSingle ( Rd ), "%s doesn't support singles!" , __FUNCTION__ );
2015-01-07 13:42:36 -06:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
2015-06-07 16:57:57 -05:00
Write32 (( Q << 30 ) | ( U << 29 ) | ( 0b1110001 << 21 ) | ( size << 22 ) | \
2015-01-07 13:42:36 -06:00
( opcode << 12 ) | ( 1 << 11 ) | ( Rn << 5 ) | Rd );
}
void ARM64FloatEmitter :: EmitLoadStoreSingleStructure ( bool L , bool R , u32 opcode , bool S , u32 size , ARM64Reg Rt , ARM64Reg Rn )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsSingle ( Rt ), "%s doesn't support singles!" , __FUNCTION__ );
2015-01-07 13:42:36 -06:00
bool quad = IsQuad ( Rt );
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
Write32 (( quad << 30 ) | ( 0b1101 << 24 ) | ( L << 22 ) | ( R << 21 ) | ( opcode << 13 ) | \
( S << 12 ) | ( size << 10 ) | ( Rn << 5 ) | Rt );
}
2015-01-18 16:25:40 -06:00
void ARM64FloatEmitter :: EmitLoadStoreSingleStructure ( bool L , bool R , u32 opcode , bool S , u32 size , ARM64Reg Rt , ARM64Reg Rn , ARM64Reg Rm )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsSingle ( Rt ), "%s doesn't support singles!" , __FUNCTION__ );
2015-01-18 16:25:40 -06:00
bool quad = IsQuad ( Rt );
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
2015-06-07 16:57:57 -05:00
Write32 (( quad << 30 ) | ( 0x1B << 23 ) | ( L << 22 ) | ( R << 21 ) | ( Rm << 16 ) | \
2015-01-18 16:25:40 -06:00
( opcode << 13 ) | ( S << 12 ) | ( size << 10 ) | ( Rn << 5 ) | Rt );
}
2015-01-07 13:42:36 -06:00
void ARM64FloatEmitter :: Emit1Source ( bool M , bool S , u32 type , u32 opcode , ARM64Reg Rd , ARM64Reg Rn )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsQuad ( Rd ), "%s doesn't support vector!" , __FUNCTION__ );
2015-01-07 13:42:36 -06:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
2015-06-07 16:57:57 -05:00
Write32 (( M << 31 ) | ( S << 29 ) | ( 0xF1 << 21 ) | ( type << 22 ) | ( opcode << 15 ) | \
2015-01-07 13:42:36 -06:00
( 1 << 14 ) | ( Rn << 5 ) | Rd );
}
void ARM64FloatEmitter :: EmitConversion ( bool sf , bool S , u32 type , u32 rmode , u32 opcode , ARM64Reg Rd , ARM64Reg Rn )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , Rn <= SP , "%s only supports GPR as source!" , __FUNCTION__ );
2015-01-07 13:42:36 -06:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
2015-06-07 16:57:57 -05:00
Write32 (( sf << 31 ) | ( S << 29 ) | ( 0xF1 << 21 ) | ( type << 22 ) | ( rmode << 19 ) | \
2015-01-07 13:42:36 -06:00
( opcode << 16 ) | ( Rn << 5 ) | Rd );
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: EmitConvertScalarToInt ( ARM64Reg Rd , ARM64Reg Rn , RoundingMode round , bool sign )
{
_dbg_assert_msg_ ( DYNA_REC , IsScalar ( Rn ), "fcvts: Rn must be floating point" );
if ( IsGPR ( Rd ))
{
// Use the encoding that transfers the result to a GPR.
bool sf = Is64Bit ( Rd );
int type = IsDouble ( Rn ) ? 1 : 0 ;
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
int opcode = ( sign ? 1 : 0 );
int rmode = 0 ;
switch ( round )
{
case ROUND_A : rmode = 0 ; opcode |= 4 ; break ;
case ROUND_P : rmode = 1 ; break ;
case ROUND_M : rmode = 2 ; break ;
case ROUND_Z : rmode = 3 ; break ;
case ROUND_N : rmode = 0 ; break ;
}
EmitConversion2 ( sf , 0 , true , type , rmode , opcode , 0 , Rd , Rn );
}
else
{
// Use the encoding (vector, single) that keeps the result in the fp register.
int sz = IsDouble ( Rn );
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
int opcode = 0 ;
switch ( round )
{
case ROUND_A : opcode = 0x1C ; break ;
case ROUND_N : opcode = 0x1A ; break ;
case ROUND_M : opcode = 0x1B ; break ;
case ROUND_P : opcode = 0x1A ; sz |= 2 ; break ;
case ROUND_Z : opcode = 0x1B ; sz |= 2 ; break ;
}
Write32 (( 0x5E << 24 ) | ( sign << 29 ) | ( sz << 22 ) | ( 1 << 21 ) | ( opcode << 12 ) | ( 2 << 10 ) | ( Rn << 5 ) | Rd );
}
}
void ARM64FloatEmitter :: FCVTS ( ARM64Reg Rd , ARM64Reg Rn , RoundingMode round )
{
EmitConvertScalarToInt ( Rd , Rn , round , false );
}
void ARM64FloatEmitter :: FCVTU ( ARM64Reg Rd , ARM64Reg Rn , RoundingMode round )
{
EmitConvertScalarToInt ( Rd , Rn , round , true );
}
void ARM64FloatEmitter :: EmitConversion2 ( bool sf , bool S , bool direction , u32 type , u32 rmode , u32 opcode , int scale , ARM64Reg Rd , ARM64Reg Rn )
{
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Write32 (( sf << 31 ) | ( S << 29 ) | ( 0xF0 << 21 ) | ( direction << 21 ) | ( type << 22 ) | ( rmode << 19 ) | \
( opcode << 16 ) | ( scale << 10 ) | ( Rn << 5 ) | Rd );
}
2015-01-07 13:42:36 -06:00
void ARM64FloatEmitter :: EmitCompare ( bool M , bool S , u32 op , u32 opcode2 , ARM64Reg Rn , ARM64Reg Rm )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsQuad ( Rn ), "%s doesn't support vector!" , __FUNCTION__ );
2015-01-25 03:19:36 -06:00
bool is_double = IsDouble ( Rn );
2015-01-07 13:42:36 -06:00
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
2015-06-07 16:57:57 -05:00
Write32 (( M << 31 ) | ( S << 29 ) | ( 0xF1 << 21 ) | ( is_double << 22 ) | ( Rm << 16 ) | \
2015-01-07 13:42:36 -06:00
( op << 14 ) | ( 1 << 13 ) | ( Rn << 5 ) | opcode2 );
}
void ARM64FloatEmitter :: EmitCondSelect ( bool M , bool S , CCFlags cond , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsQuad ( Rd ), "%s doesn't support vector!" , __FUNCTION__ );
2015-01-25 03:19:36 -06:00
bool is_double = IsDouble ( Rd );
2015-01-07 13:42:36 -06:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
2015-06-07 16:57:57 -05:00
Write32 (( M << 31 ) | ( S << 29 ) | ( 0xF1 << 21 ) | ( is_double << 22 ) | ( Rm << 16 ) | \
( cond << 12 ) | ( 3 << 10 ) | ( Rn << 5 ) | Rd );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: EmitPermute ( u32 size , u32 op , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsSingle ( Rd ), "%s doesn't support singles!" , __FUNCTION__ );
2015-01-07 13:42:36 -06:00
bool quad = IsQuad ( Rd );
u32 encoded_size = 0 ;
if ( size == 16 )
encoded_size = 1 ;
else if ( size == 32 )
encoded_size = 2 ;
else if ( size == 64 )
encoded_size = 3 ;
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
2015-06-07 16:57:57 -05:00
Write32 (( quad << 30 ) | ( 7 << 25 ) | ( encoded_size << 22 ) | ( Rm << 16 ) | ( op << 12 ) | \
2015-01-07 13:42:36 -06:00
( 1 << 11 ) | ( Rn << 5 ) | Rd );
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: EmitScalarImm ( bool M , bool S , u32 type , u32 imm5 , ARM64Reg Rd , u32 imm8 )
2015-01-18 16:25:40 -06:00
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsQuad ( Rd ), "%s doesn't support vector!" , __FUNCTION__ );
2015-01-18 16:25:40 -06:00
bool is_double = ! IsSingle ( Rd );
Rd = DecodeReg ( Rd );
2015-06-07 16:57:57 -05:00
Write32 (( M << 31 ) | ( S << 29 ) | ( 0xF1 << 21 ) | ( is_double << 22 ) | ( type << 22 ) | \
( imm8 << 13 ) | ( 1 << 12 ) | ( imm5 << 5 ) | Rd );
2015-01-18 16:25:40 -06:00
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: EmitShiftImm ( bool Q , bool U , u32 immh , u32 immb , u32 opcode , ARM64Reg Rd , ARM64Reg Rn )
2015-01-18 16:25:40 -06:00
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , immh , "%s bad encoding! Can't have zero immh" , __FUNCTION__ );
2015-01-18 16:25:40 -06:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
2015-06-07 16:57:57 -05:00
Write32 (( Q << 30 ) | ( U << 29 ) | ( 0xF << 24 ) | ( immh << 19 ) | ( immb << 16 ) | \
2015-01-18 16:25:40 -06:00
( opcode << 11 ) | ( 1 << 10 ) | ( Rn << 5 ) | Rd );
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: EmitScalarShiftImm ( bool U , u32 immh , u32 immb , u32 opcode , ARM64Reg Rd , ARM64Reg Rn )
{
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Write32 (( 2 << 30 ) | ( U << 29 ) | ( 0x3E << 23 ) | ( immh << 19 ) | ( immb << 16 ) | ( opcode << 11 ) | ( 1 << 10 ) | ( Rn << 5 ) | Rd );
}
2015-01-18 16:25:40 -06:00
void ARM64FloatEmitter :: EmitLoadStoreMultipleStructure ( u32 size , bool L , u32 opcode , ARM64Reg Rt , ARM64Reg Rn )
{
bool quad = IsQuad ( Rt );
u32 encoded_size = 0 ;
if ( size == 16 )
encoded_size = 1 ;
else if ( size == 32 )
encoded_size = 2 ;
else if ( size == 64 )
encoded_size = 3 ;
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
Write32 (( quad << 30 ) | ( 3 << 26 ) | ( L << 22 ) | ( opcode << 12 ) | \
( encoded_size << 10 ) | ( Rn << 5 ) | Rt );
}
2015-02-28 04:39:15 -06:00
void ARM64FloatEmitter :: EmitLoadStoreMultipleStructurePost ( u32 size , bool L , u32 opcode , ARM64Reg Rt , ARM64Reg Rn , ARM64Reg Rm )
{
bool quad = IsQuad ( Rt );
u32 encoded_size = 0 ;
if ( size == 16 )
encoded_size = 1 ;
else if ( size == 32 )
encoded_size = 2 ;
else if ( size == 64 )
encoded_size = 3 ;
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
Write32 (( quad << 30 ) | ( 0b11001 << 23 ) | ( L << 22 ) | ( Rm << 16 ) | ( opcode << 12 ) | \
( encoded_size << 10 ) | ( Rn << 5 ) | Rt );
}
2015-01-20 16:34:32 -06:00
void ARM64FloatEmitter :: EmitScalar1Source ( bool M , bool S , u32 type , u32 opcode , ARM64Reg Rd , ARM64Reg Rn )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! IsQuad ( Rd ), "%s doesn't support vector!" , __FUNCTION__ );
2015-01-20 16:34:32 -06:00
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
2015-06-07 16:57:57 -05:00
Write32 (( M << 31 ) | ( S << 29 ) | ( 0xF1 << 21 ) | ( type << 22 ) | \
2015-01-20 16:34:32 -06:00
( opcode << 15 ) | ( 1 << 14 ) | ( Rn << 5 ) | Rd );
}
2015-02-12 18:47:06 -06:00
void ARM64FloatEmitter :: EmitVectorxElement ( bool U , u32 size , bool L , u32 opcode , bool H , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
bool quad = IsQuad ( Rd );
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
2015-06-07 16:57:57 -05:00
Write32 (( quad << 30 ) | ( U << 29 ) | ( 0xF << 24 ) | ( size << 22 ) | ( L << 21 ) | \
2015-02-12 18:47:06 -06:00
( Rm << 16 ) | ( opcode << 12 ) | ( H << 11 ) | ( Rn << 5 ) | Rd );
}
2015-02-16 22:00:43 -06:00
void ARM64FloatEmitter :: EmitLoadStoreUnscaled ( u32 size , u32 op , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
_assert_msg_ ( DYNA_REC , ! ( imm < - 256 || imm > 255 ), "%s received too large offset: %d" , __FUNCTION__ , imm );
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
2015-06-07 16:57:57 -05:00
Write32 (( size << 30 ) | ( 0xF << 26 ) | ( op << 22 ) | (( imm & 0x1FF ) << 12 ) | ( Rn << 5 ) | Rt );
2015-02-16 22:00:43 -06:00
}
2015-03-02 03:41:19 -06:00
void ARM64FloatEmitter :: EncodeLoadStorePair ( u32 size , bool load , IndexType type , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , s32 imm )
{
u32 type_encode = 0 ;
u32 opc = 0 ;
switch ( type )
{
case INDEX_SIGNED :
type_encode = 0b010 ;
break ;
case INDEX_POST :
type_encode = 0b001 ;
break ;
case INDEX_PRE :
type_encode = 0b011 ;
break ;
case INDEX_UNSIGNED :
_assert_msg_ ( DYNA_REC , false , "%s doesn't support INDEX_UNSIGNED!" , __FUNCTION__ );
break ;
}
if ( size == 128 )
{
_assert_msg_ ( DYNA_REC , ! ( imm & 0xF ), "%s received invalid offset 0x%x!" , __FUNCTION__ , imm );
opc = 2 ;
imm >>= 4 ;
}
else if ( size == 64 )
{
_assert_msg_ ( DYNA_REC , ! ( imm & 0x7 ), "%s received invalid offset 0x%x!" , __FUNCTION__ , imm );
opc = 1 ;
imm >>= 3 ;
}
else if ( size == 32 )
{
_assert_msg_ ( DYNA_REC , ! ( imm & 0x3 ), "%s received invalid offset 0x%x!" , __FUNCTION__ , imm );
opc = 0 ;
imm >>= 2 ;
}
Rt = DecodeReg ( Rt );
Rt2 = DecodeReg ( Rt2 );
Rn = DecodeReg ( Rn );
Write32 (( opc << 30 ) | ( 0b1011 << 26 ) | ( type_encode << 23 ) | ( load << 22 ) | \
(( imm & 0x7F ) << 15 ) | ( Rt2 << 10 ) | ( Rn << 5 ) | Rt );
}
2015-06-07 19:53:05 -05:00
void ARM64FloatEmitter :: EncodeLoadStoreRegisterOffset ( u32 size , bool load , ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
{
_assert_msg_ ( DYNA_REC , Rm . GetType () == ArithOption :: TYPE_EXTENDEDREG , "%s must contain an extended reg as Rm!" , __FUNCTION__ );
u32 encoded_size = 0 ;
u32 encoded_op = 0 ;
if ( size == 8 )
{
encoded_size = 0 ;
encoded_op = 0 ;
}
else if ( size == 16 )
{
encoded_size = 1 ;
encoded_op = 0 ;
}
else if ( size == 32 )
{
encoded_size = 2 ;
encoded_op = 0 ;
}
else if ( size == 64 )
{
encoded_size = 3 ;
encoded_op = 0 ;
}
else if ( size == 128 )
{
encoded_size = 0 ;
encoded_op = 2 ;
}
if ( load )
encoded_op |= 1 ;
Rt = DecodeReg ( Rt );
Rn = DecodeReg ( Rn );
ARM64Reg decoded_Rm = DecodeReg ( Rm . GetReg ());
Write32 (( encoded_size << 30 ) | ( encoded_op << 22 ) | ( 0b111100001 << 21 ) | ( decoded_Rm << 16 ) | \
Rm . GetData () | ( 1 << 11 ) | ( Rn << 5 ) | Rt );
}
2015-08-23 15:34:53 -05:00
void ARM64FloatEmitter :: EncodeModImm ( bool Q , u8 op , u8 cmode , u8 o2 , ARM64Reg Rd , u8 abcdefgh )
{
union
{
u8 hex ;
struct
{
unsigned defgh : 5 ;
unsigned abc : 3 ;
};
} v ;
v . hex = abcdefgh ;
Rd = DecodeReg ( Rd );
Write32 (( Q << 30 ) | ( op << 29 ) | ( 0xF << 24 ) | ( v . abc << 16 ) | ( cmode << 12 ) | \
( o2 << 11 ) | ( 1 << 10 ) | ( v . defgh << 5 ) | Rd );
}
2015-01-07 13:42:36 -06:00
void ARM64FloatEmitter :: LDR ( u8 size , IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EmitLoadStoreImmediate ( size , 1 , type , Rt , Rn , imm );
}
void ARM64FloatEmitter :: STR ( u8 size , IndexType type , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
EmitLoadStoreImmediate ( size , 0 , type , Rt , Rn , imm );
}
2015-02-16 22:00:43 -06:00
// Loadstore unscaled
void ARM64FloatEmitter :: LDUR ( u8 size , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
u32 encoded_size = 0 ;
u32 encoded_op = 0 ;
if ( size == 8 )
{
encoded_size = 0 ;
encoded_op = 1 ;
}
else if ( size == 16 )
{
encoded_size = 1 ;
encoded_op = 1 ;
}
else if ( size == 32 )
{
encoded_size = 2 ;
encoded_op = 1 ;
}
else if ( size == 64 )
{
encoded_size = 3 ;
encoded_op = 1 ;
}
else if ( size == 128 )
{
encoded_size = 0 ;
encoded_op = 3 ;
}
EmitLoadStoreUnscaled ( encoded_size , encoded_op , Rt , Rn , imm );
}
void ARM64FloatEmitter :: STUR ( u8 size , ARM64Reg Rt , ARM64Reg Rn , s32 imm )
{
u32 encoded_size = 0 ;
u32 encoded_op = 0 ;
if ( size == 8 )
{
encoded_size = 0 ;
encoded_op = 0 ;
}
else if ( size == 16 )
{
encoded_size = 1 ;
encoded_op = 0 ;
}
else if ( size == 32 )
{
encoded_size = 2 ;
encoded_op = 0 ;
}
else if ( size == 64 )
{
encoded_size = 3 ;
encoded_op = 0 ;
}
else if ( size == 128 )
{
encoded_size = 0 ;
encoded_op = 2 ;
}
EmitLoadStoreUnscaled ( encoded_size , encoded_op , Rt , Rn , imm );
}
2015-01-07 13:42:36 -06:00
// Loadstore single structure
2015-01-18 16:25:40 -06:00
void ARM64FloatEmitter :: LD1 ( u8 size , ARM64Reg Rt , u8 index , ARM64Reg Rn )
{
bool S = 0 ;
u32 opcode = 0 ;
u32 encoded_size = 0 ;
ARM64Reg encoded_reg = INVALID_REG ;
if ( size == 8 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 4 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 0 ;
encoded_size = index & 3 ;
if ( index & 8 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 16 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 2 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 2 ;
encoded_size = ( index & 1 ) << 1 ;
if ( index & 4 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 32 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 1 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 4 ;
encoded_size = 0 ;
if ( index & 2 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 64 )
{
S = 0 ;
opcode = 4 ;
encoded_size = 1 ;
if ( index == 1 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
EmitLoadStoreSingleStructure ( 1 , 0 , opcode , S , encoded_size , encoded_reg , Rn );
}
void ARM64FloatEmitter :: LD1 ( u8 size , ARM64Reg Rt , u8 index , ARM64Reg Rn , ARM64Reg Rm )
{
bool S = 0 ;
u32 opcode = 0 ;
u32 encoded_size = 0 ;
ARM64Reg encoded_reg = INVALID_REG ;
if ( size == 8 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 4 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 0 ;
encoded_size = index & 3 ;
if ( index & 8 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 16 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 2 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 2 ;
encoded_size = ( index & 1 ) << 1 ;
if ( index & 4 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 32 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 1 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 4 ;
encoded_size = 0 ;
if ( index & 2 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 64 )
{
S = 0 ;
opcode = 4 ;
encoded_size = 1 ;
if ( index == 1 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
EmitLoadStoreSingleStructure ( 1 , 0 , opcode , S , encoded_size , encoded_reg , Rn , Rm );
}
2015-01-07 13:42:36 -06:00
void ARM64FloatEmitter :: LD1R ( u8 size , ARM64Reg Rt , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
EmitLoadStoreSingleStructure ( 1 , 0 , 6 , 0 , size >> 4 , Rt , Rn );
2015-01-07 13:42:36 -06:00
}
2015-06-09 17:42:15 -05:00
void ARM64FloatEmitter :: LD2R ( u8 size , ARM64Reg Rt , ARM64Reg Rn )
{
EmitLoadStoreSingleStructure ( 1 , 1 , 6 , 0 , size >> 4 , Rt , Rn );
}
void ARM64FloatEmitter :: LD1R ( u8 size , ARM64Reg Rt , ARM64Reg Rn , ARM64Reg Rm )
{
EmitLoadStoreSingleStructure ( 1 , 0 , 6 , 0 , size >> 4 , Rt , Rn , Rm );
}
void ARM64FloatEmitter :: LD2R ( u8 size , ARM64Reg Rt , ARM64Reg Rn , ARM64Reg Rm )
{
EmitLoadStoreSingleStructure ( 1 , 1 , 6 , 0 , size >> 4 , Rt , Rn , Rm );
}
2015-01-07 13:42:36 -06:00
2015-01-18 16:25:40 -06:00
void ARM64FloatEmitter :: ST1 ( u8 size , ARM64Reg Rt , u8 index , ARM64Reg Rn )
{
bool S = 0 ;
u32 opcode = 0 ;
u32 encoded_size = 0 ;
ARM64Reg encoded_reg = INVALID_REG ;
if ( size == 8 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 4 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 0 ;
encoded_size = index & 3 ;
if ( index & 8 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 16 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 2 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 2 ;
encoded_size = ( index & 1 ) << 1 ;
if ( index & 4 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 32 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 1 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 4 ;
encoded_size = 0 ;
if ( index & 2 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 64 )
{
S = 0 ;
opcode = 4 ;
encoded_size = 1 ;
if ( index == 1 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
EmitLoadStoreSingleStructure ( 0 , 0 , opcode , S , encoded_size , encoded_reg , Rn );
}
void ARM64FloatEmitter :: ST1 ( u8 size , ARM64Reg Rt , u8 index , ARM64Reg Rn , ARM64Reg Rm )
{
bool S = 0 ;
u32 opcode = 0 ;
u32 encoded_size = 0 ;
ARM64Reg encoded_reg = INVALID_REG ;
if ( size == 8 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 4 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 0 ;
encoded_size = index & 3 ;
if ( index & 8 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 16 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 2 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 2 ;
encoded_size = ( index & 1 ) << 1 ;
if ( index & 4 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 32 )
{
2015-06-07 16:57:57 -05:00
S = ( index & 1 ) != 0 ;
2015-01-18 16:25:40 -06:00
opcode = 4 ;
encoded_size = 0 ;
if ( index & 2 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
else if ( size == 64 )
{
S = 0 ;
opcode = 4 ;
encoded_size = 1 ;
if ( index == 1 )
encoded_reg = EncodeRegToQuad ( Rt );
else
encoded_reg = EncodeRegToDouble ( Rt );
}
EmitLoadStoreSingleStructure ( 0 , 0 , opcode , S , encoded_size , encoded_reg , Rn , Rm );
}
// Loadstore multiple structure
void ARM64FloatEmitter :: LD1 ( u8 size , u8 count , ARM64Reg Rt , ARM64Reg Rn )
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , ! ( count == 0 || count > 4 ), "%s must have a count of 1 to 4 registers!" , __FUNCTION__ );
2015-01-18 16:25:40 -06:00
u32 opcode = 0 ;
if ( count == 1 )
opcode = 0b111 ;
else if ( count == 2 )
opcode = 0b1010 ;
else if ( count == 3 )
opcode = 0b0110 ;
else if ( count == 4 )
opcode = 0b0010 ;
EmitLoadStoreMultipleStructure ( size , 1 , opcode , Rt , Rn );
}
2015-02-28 04:39:15 -06:00
void ARM64FloatEmitter :: LD1 ( u8 size , u8 count , IndexType type , ARM64Reg Rt , ARM64Reg Rn , ARM64Reg Rm )
{
_assert_msg_ ( DYNA_REC , ! ( count == 0 || count > 4 ), "%s must have a count of 1 to 4 registers!" , __FUNCTION__ );
_assert_msg_ ( DYNA_REC , type == INDEX_POST , "%s only supports post indexing!" , __FUNCTION__ );
u32 opcode = 0 ;
if ( count == 1 )
opcode = 0b111 ;
else if ( count == 2 )
opcode = 0b1010 ;
else if ( count == 3 )
opcode = 0b0110 ;
else if ( count == 4 )
opcode = 0b0010 ;
EmitLoadStoreMultipleStructurePost ( size , 1 , opcode , Rt , Rn , Rm );
}
2015-02-12 18:47:06 -06:00
void ARM64FloatEmitter :: ST1 ( u8 size , u8 count , ARM64Reg Rt , ARM64Reg Rn )
{
_assert_msg_ ( DYNA_REC , ! ( count == 0 || count > 4 ), "%s must have a count of 1 to 4 registers!" , __FUNCTION__ );
u32 opcode = 0 ;
if ( count == 1 )
opcode = 0b111 ;
else if ( count == 2 )
opcode = 0b1010 ;
else if ( count == 3 )
opcode = 0b0110 ;
else if ( count == 4 )
opcode = 0b0010 ;
EmitLoadStoreMultipleStructure ( size , 0 , opcode , Rt , Rn );
}
2015-02-28 04:39:15 -06:00
void ARM64FloatEmitter :: ST1 ( u8 size , u8 count , IndexType type , ARM64Reg Rt , ARM64Reg Rn , ARM64Reg Rm )
{
_assert_msg_ ( DYNA_REC , ! ( count == 0 || count > 4 ), "%s must have a count of 1 to 4 registers!" , __FUNCTION__ );
_assert_msg_ ( DYNA_REC , type == INDEX_POST , "%s only supports post indexing!" , __FUNCTION__ );
u32 opcode = 0 ;
if ( count == 1 )
opcode = 0b111 ;
else if ( count == 2 )
opcode = 0b1010 ;
else if ( count == 3 )
opcode = 0b0110 ;
else if ( count == 4 )
opcode = 0b0010 ;
EmitLoadStoreMultipleStructurePost ( size , 0 , opcode , Rt , Rn , Rm );
}
2015-02-12 18:47:06 -06:00
2015-06-07 16:57:57 -05:00
// Scalar - 1 Source
void ARM64FloatEmitter :: FMOV ( ARM64Reg Rd , ARM64Reg Rn , bool top )
{
if ( IsScalar ( Rd ) && IsScalar ( Rn ))
{
EmitScalar1Source ( 0 , 0 , IsDouble ( Rd ), 0 , Rd , Rn );
}
else
{
_assert_msg_ ( DYNA_REC , ! IsQuad ( Rd ) && ! IsQuad ( Rn ), "FMOV can't move to/from quads" );
int rmode = 0 ;
int opcode = 6 ;
int sf = 0 ;
if ( IsSingle ( Rd ) && ! Is64Bit ( Rn ) && ! top )
{
// GPR to scalar single
opcode |= 1 ;
}
else if ( ! Is64Bit ( Rd ) && IsSingle ( Rn ) && ! top )
{
// Scalar single to GPR - defaults are correct
}
else
{
// TODO
_assert_msg_ ( DYNA_REC , 0 , "FMOV: Unhandled case" );
}
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Write32 (( sf << 31 ) | ( 0x1e2 << 20 ) | ( rmode << 19 ) | ( opcode << 16 ) | ( Rn << 5 ) | Rd );
}
}
2015-03-02 03:41:19 -06:00
// Loadstore paired
void ARM64FloatEmitter :: LDP ( u8 size , IndexType type , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , s32 imm )
{
EncodeLoadStorePair ( size , true , type , Rt , Rt2 , Rn , imm );
}
void ARM64FloatEmitter :: STP ( u8 size , IndexType type , ARM64Reg Rt , ARM64Reg Rt2 , ARM64Reg Rn , s32 imm )
{
EncodeLoadStorePair ( size , false , type , Rt , Rt2 , Rn , imm );
}
2015-06-07 19:53:05 -05:00
// Loadstore register offset
void ARM64FloatEmitter :: STR ( u8 size , ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
{
EncodeLoadStoreRegisterOffset ( size , false , Rt , Rn , Rm );
}
void ARM64FloatEmitter :: LDR ( u8 size , ARM64Reg Rt , ARM64Reg Rn , ArithOption Rm )
{
EncodeLoadStoreRegisterOffset ( size , true , Rt , Rn , Rm );
}
2015-01-20 16:34:32 -06:00
void ARM64FloatEmitter :: FABS ( ARM64Reg Rd , ARM64Reg Rn )
{
EmitScalar1Source ( 0 , 0 , IsDouble ( Rd ), 1 , Rd , Rn );
}
void ARM64FloatEmitter :: FNEG ( ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
EmitScalar1Source ( 0 , 0 , IsDouble ( Rd ), 2 , Rd , Rn );
2015-01-20 16:34:32 -06:00
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: FSQRT ( ARM64Reg Rd , ARM64Reg Rn )
{
EmitScalar1Source ( 0 , 0 , IsDouble ( Rd ), 3 , Rd , Rn );
}
2015-01-18 16:25:40 -06:00
2015-01-07 13:42:36 -06:00
// Scalar - 2 Source
2015-01-20 16:34:32 -06:00
void ARM64FloatEmitter :: FADD ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitScalar2Source ( 0 , 0 , IsDouble ( Rd ), 2 , Rd , Rn , Rm );
2015-01-20 16:34:32 -06:00
}
2015-01-07 13:42:36 -06:00
void ARM64FloatEmitter :: FMUL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitScalar2Source ( 0 , 0 , IsDouble ( Rd ), 0 , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
2015-01-20 16:34:32 -06:00
void ARM64FloatEmitter :: FSUB ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitScalar2Source ( 0 , 0 , IsDouble ( Rd ), 3 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: FDIV ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitScalar2Source ( 0 , 0 , IsDouble ( Rd ), 1 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: FMAX ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitScalar2Source ( 0 , 0 , IsDouble ( Rd ), 4 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: FMIN ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitScalar2Source ( 0 , 0 , IsDouble ( Rd ), 5 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: FMAXNM ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitScalar2Source ( 0 , 0 , IsDouble ( Rd ), 6 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: FMINNM ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitScalar2Source ( 0 , 0 , IsDouble ( Rd ), 7 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: FNMUL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitScalar2Source ( 0 , 0 , IsDouble ( Rd ), 8 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: FMADD ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EmitScalar3Source ( IsDouble ( Rd ), Rd , Rn , Rm , Ra , 0 );
}
void ARM64FloatEmitter :: FMSUB ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EmitScalar3Source ( IsDouble ( Rd ), Rd , Rn , Rm , Ra , 1 );
}
void ARM64FloatEmitter :: FNMADD ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EmitScalar3Source ( IsDouble ( Rd ), Rd , Rn , Rm , Ra , 2 );
}
void ARM64FloatEmitter :: FNMSUB ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra )
{
EmitScalar3Source ( IsDouble ( Rd ), Rd , Rn , Rm , Ra , 3 );
}
void ARM64FloatEmitter :: EmitScalar3Source ( bool isDouble , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , ARM64Reg Ra , int opcode )
{
int type = isDouble ? 1 : 0 ;
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
Rm = DecodeReg ( Rm );
Ra = DecodeReg ( Ra );
int o1 = opcode >> 1 ;
int o0 = opcode & 1 ;
m_emit -> Write32 (( 0x1F << 24 ) | ( type << 22 ) | ( o1 << 21 ) | ( Rm << 16 ) | ( o0 << 15 ) | ( Ra << 10 ) | ( Rn << 5 ) | Rd );
2015-01-20 16:34:32 -06:00
}
2015-01-07 13:42:36 -06:00
2015-01-18 16:25:40 -06:00
// Scalar floating point immediate
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: FMOV ( ARM64Reg Rd , uint8_t imm8 )
2015-01-18 16:25:40 -06:00
{
2015-06-07 16:57:57 -05:00
EmitScalarImm ( 0 , 0 , 0 , 0 , Rd , imm8 );
2015-01-18 16:25:40 -06:00
}
2015-01-07 13:42:36 -06:00
// Vector
void ARM64FloatEmitter :: AND ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 0 , 0 , 3 , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: BSL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 1 , 1 , 3 , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: DUP ( u8 size , ARM64Reg Rd , ARM64Reg Rn , u8 index )
{
u32 imm5 = 0 ;
if ( size == 8 )
{
imm5 = 1 ;
imm5 |= index << 1 ;
}
else if ( size == 16 )
{
imm5 = 2 ;
imm5 |= index << 2 ;
}
else if ( size == 32 )
{
imm5 = 4 ;
imm5 |= index << 3 ;
}
else if ( size == 64 )
{
imm5 = 8 ;
imm5 |= index << 4 ;
}
EmitCopy ( IsQuad ( Rd ), 0 , imm5 , 0 , Rd , Rn );
}
void ARM64FloatEmitter :: FABS ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 0 , 2 | ( size >> 6 ), 0xF , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FADD ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 0 , size >> 6 , 0x1A , Rd , Rn , Rm );
}
2015-06-09 17:42:15 -05:00
void ARM64FloatEmitter :: FMAX ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitThreeSame ( 0 , size >> 6 , 0b11110 , Rd , Rn , Rm );
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: FMLA ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitThreeSame ( 0 , size >> 6 , 0x19 , Rd , Rn , Rm );
2015-06-09 17:42:15 -05:00
}
void ARM64FloatEmitter :: FMIN ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitThreeSame ( 0 , 2 | size >> 6 , 0b11110 , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCVTL ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( false , 0 , size >> 6 , 0x17 , Rd , Rn );
}
void ARM64FloatEmitter :: FCVTL2 ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
Emit2RegMisc ( true , 0 , size >> 6 , 0x17 , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
2015-01-18 16:25:40 -06:00
void ARM64FloatEmitter :: FCVTN ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 0 , dest_size >> 5 , 0x16 , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
void ARM64FloatEmitter :: FCVTZS ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 0 , 2 | ( size >> 6 ), 0x1B , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
void ARM64FloatEmitter :: FCVTZU ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 1 , 2 | ( size >> 6 ), 0x1B , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
2015-01-07 13:42:36 -06:00
void ARM64FloatEmitter :: FDIV ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 1 , size >> 6 , 0x1F , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FMUL ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 1 , size >> 6 , 0x1B , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FNEG ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 1 , 2 | ( size >> 6 ), 0xF , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FRSQRTE ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 1 , 2 | ( size >> 6 ), 0x1D , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FSUB ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 0 , 2 | ( size >> 6 ), 0x1A , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: FMLS ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitThreeSame ( 0 , 2 | ( size >> 6 ), 0x19 , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: NOT ( ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 1 , 0 , 5 , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: ORR ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 0 , 2 , 3 , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: REV16 ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 0 , size >> 4 , 1 , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: REV32 ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 1 , size >> 4 , 0 , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: REV64 ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 0 , size >> 4 , 0 , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
2015-01-18 16:25:40 -06:00
void ARM64FloatEmitter :: SCVTF ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 0 , size >> 6 , 0x1D , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
void ARM64FloatEmitter :: UCVTF ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 1 , size >> 6 , 0x1D , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: SCVTF ( u8 size , ARM64Reg Rd , ARM64Reg Rn , int scale )
{
int imm = size * 2 - scale ;
EmitShiftImm ( IsQuad ( Rd ), 0 , imm >> 3 , imm & 7 , 0x1C , Rd , Rn );
}
void ARM64FloatEmitter :: UCVTF ( u8 size , ARM64Reg Rd , ARM64Reg Rn , int scale )
{
int imm = size * 2 - scale ;
EmitShiftImm ( IsQuad ( Rd ), 1 , imm >> 3 , imm & 7 , 0x1C , Rd , Rn );
}
2015-06-13 23:16:17 -05:00
void ARM64FloatEmitter :: SQXTN ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn )
{
Emit2RegMisc ( false , 0 , dest_size >> 4 , 0b10100 , Rd , Rn );
}
void ARM64FloatEmitter :: SQXTN2 ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn )
{
Emit2RegMisc ( true , 0 , dest_size >> 4 , 0b10100 , Rd , Rn );
}
void ARM64FloatEmitter :: UQXTN ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn )
{
Emit2RegMisc ( false , 1 , dest_size >> 4 , 0b10100 , Rd , Rn );
}
void ARM64FloatEmitter :: UQXTN2 ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn )
{
Emit2RegMisc ( true , 1 , dest_size >> 4 , 0b10100 , Rd , Rn );
}
2015-01-18 16:25:40 -06:00
void ARM64FloatEmitter :: XTN ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-13 23:16:17 -05:00
Emit2RegMisc ( false , 0 , dest_size >> 4 , 0b10010 , Rd , Rn );
}
void ARM64FloatEmitter :: XTN2 ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn )
{
Emit2RegMisc ( true , 0 , dest_size >> 4 , 0b10010 , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
2015-01-07 13:42:36 -06:00
// Move
void ARM64FloatEmitter :: DUP ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
u32 imm5 = 0 ;
if ( size == 8 )
imm5 = 1 ;
else if ( size == 16 )
imm5 = 2 ;
else if ( size == 32 )
imm5 = 4 ;
else if ( size == 64 )
imm5 = 8 ;
2015-06-07 16:57:57 -05:00
EmitCopy ( IsQuad ( Rd ), 0 , imm5 , 1 , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: INS ( u8 size , ARM64Reg Rd , u8 index , ARM64Reg Rn )
{
u32 imm5 = 0 ;
if ( size == 8 )
{
imm5 = 1 ;
imm5 |= index << 1 ;
}
else if ( size == 16 )
{
imm5 = 2 ;
imm5 |= index << 2 ;
}
else if ( size == 32 )
{
imm5 = 4 ;
imm5 |= index << 3 ;
}
else if ( size == 64 )
{
imm5 = 8 ;
imm5 |= index << 4 ;
}
2015-06-07 16:57:57 -05:00
EmitCopy ( 1 , 0 , imm5 , 3 , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: INS ( u8 size , ARM64Reg Rd , u8 index1 , ARM64Reg Rn , u8 index2 )
{
u32 imm5 = 0 , imm4 = 0 ;
if ( size == 8 )
{
imm5 = 1 ;
imm5 |= index1 << 1 ;
imm4 = index2 ;
}
else if ( size == 16 )
{
imm5 = 2 ;
imm5 |= index1 << 2 ;
imm4 = index2 << 1 ;
}
else if ( size == 32 )
{
imm5 = 4 ;
imm5 |= index1 << 3 ;
imm4 = index2 << 2 ;
}
else if ( size == 64 )
{
imm5 = 8 ;
imm5 |= index1 << 4 ;
imm4 = index2 << 3 ;
}
EmitCopy ( 1 , 1 , imm5 , imm4 , Rd , Rn );
}
2015-01-18 16:25:40 -06:00
void ARM64FloatEmitter :: UMOV ( u8 size , ARM64Reg Rd , ARM64Reg Rn , u8 index )
{
bool b64Bit = Is64Bit ( Rd );
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , Rd < SP , "%s destination must be a GPR!" , __FUNCTION__ );
_assert_msg_ ( DYNA_REC , ! ( b64Bit && size != 64 ), "%s must have a size of 64 when destination is 64bit!" , __FUNCTION__ );
2015-01-18 16:25:40 -06:00
u32 imm5 = 0 ;
if ( size == 8 )
{
imm5 = 1 ;
imm5 |= index << 1 ;
}
else if ( size == 16 )
{
imm5 = 2 ;
imm5 |= index << 2 ;
}
else if ( size == 32 )
{
imm5 = 4 ;
imm5 |= index << 3 ;
}
else if ( size == 64 )
{
imm5 = 8 ;
imm5 |= index << 4 ;
}
2015-06-07 16:57:57 -05:00
EmitCopy ( b64Bit , 0 , imm5 , 7 , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
void ARM64FloatEmitter :: SMOV ( u8 size , ARM64Reg Rd , ARM64Reg Rn , u8 index )
{
bool b64Bit = Is64Bit ( Rd );
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , Rd < SP , "%s destination must be a GPR!" , __FUNCTION__ );
_assert_msg_ ( DYNA_REC , size != 64 , "%s doesn't support 64bit destination. Use UMOV!" , __FUNCTION__ );
2015-01-18 16:25:40 -06:00
u32 imm5 = 0 ;
if ( size == 8 )
{
imm5 = 1 ;
imm5 |= index << 1 ;
}
else if ( size == 16 )
{
imm5 = 2 ;
imm5 |= index << 2 ;
}
else if ( size == 32 )
{
imm5 = 4 ;
imm5 |= index << 3 ;
}
2015-06-07 16:57:57 -05:00
EmitCopy ( b64Bit , 0 , imm5 , 5 , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
2015-01-07 13:42:36 -06:00
// One source
void ARM64FloatEmitter :: FCVT ( u8 size_to , u8 size_from , ARM64Reg Rd , ARM64Reg Rn )
{
u32 dst_encoding = 0 ;
u32 src_encoding = 0 ;
if ( size_to == 16 )
dst_encoding = 3 ;
else if ( size_to == 32 )
dst_encoding = 0 ;
else if ( size_to == 64 )
dst_encoding = 1 ;
if ( size_from == 16 )
src_encoding = 3 ;
else if ( size_from == 32 )
src_encoding = 0 ;
else if ( size_from == 64 )
src_encoding = 1 ;
2015-06-07 16:57:57 -05:00
Emit1Source ( 0 , 0 , src_encoding , 4 | dst_encoding , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
2015-01-18 16:25:40 -06:00
void ARM64FloatEmitter :: SCVTF ( ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
if ( IsScalar ( Rn ))
{
// Source is in FP register (like destination!). We must use a vector encoding.
bool sign = false ;
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
int sz = IsDouble ( Rn );
Write32 (( 0x5e << 24 ) | ( sign << 29 ) | ( sz << 22 ) | ( 0x876 << 10 ) | ( Rn << 5 ) | Rd );
}
else
{
bool sf = Is64Bit ( Rn );
u32 type = 0 ;
if ( IsDouble ( Rd ))
type = 1 ;
EmitConversion ( sf , 0 , type , 0 , 2 , Rd , Rn );
}
2015-01-18 16:25:40 -06:00
}
void ARM64FloatEmitter :: UCVTF ( ARM64Reg Rd , ARM64Reg Rn )
2015-06-07 16:57:57 -05:00
{
if ( IsScalar ( Rn ))
{
// Source is in FP register (like destination!). We must use a vector encoding.
bool sign = true ;
Rd = DecodeReg ( Rd );
Rn = DecodeReg ( Rn );
int sz = IsDouble ( Rn );
Write32 (( 0x5e << 24 ) | ( sign << 29 ) | ( sz << 22 ) | ( 0x876 << 10 ) | ( Rn << 5 ) | Rd );
}
else
{
bool sf = Is64Bit ( Rn );
u32 type = 0 ;
if ( IsDouble ( Rd ))
type = 1 ;
EmitConversion ( sf , 0 , type , 0 , 3 , Rd , Rn );
}
}
void ARM64FloatEmitter :: SCVTF ( ARM64Reg Rd , ARM64Reg Rn , int scale )
2015-01-18 16:25:40 -06:00
{
bool sf = Is64Bit ( Rn );
u32 type = 0 ;
if ( IsDouble ( Rd ))
type = 1 ;
2015-06-07 16:57:57 -05:00
EmitConversion2 ( sf , 0 , false , type , 0 , 2 , 64 - scale , Rd , Rn );
}
void ARM64FloatEmitter :: UCVTF ( ARM64Reg Rd , ARM64Reg Rn , int scale )
{
bool sf = Is64Bit ( Rn );
u32 type = 0 ;
if ( IsDouble ( Rd ))
type = 1 ;
EmitConversion2 ( sf , 0 , false , type , 0 , 3 , 64 - scale , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
2015-01-07 13:42:36 -06:00
void ARM64FloatEmitter :: FCMP ( ARM64Reg Rn , ARM64Reg Rm )
{
EmitCompare ( 0 , 0 , 0 , 0 , Rn , Rm );
}
void ARM64FloatEmitter :: FCMP ( ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
EmitCompare ( 0 , 0 , 0 , 8 , Rn , ( ARM64Reg ) 0 );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMPE ( ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitCompare ( 0 , 0 , 0 , 0x10 , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMPE ( ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
EmitCompare ( 0 , 0 , 0 , 0x18 , Rn , ( ARM64Reg ) 0 );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMEQ ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 0 , size >> 6 , 0x1C , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMEQ ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-08-10 19:38:10 -04:00
Emit2RegMisc ( IsQuad ( Rd ), 0 , 2 | ( size >> 6 ), 0xD , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMGE ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 1 , size >> 6 , 0x1C , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMGE ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-08-09 14:54:55 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 1 , 2 | ( size >> 6 ), 0x0C , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMGT ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
2015-06-07 16:57:57 -05:00
EmitThreeSame ( 1 , 2 | ( size >> 6 ), 0x1C , Rd , Rn , Rm );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMGT ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 0 , 2 | ( size >> 6 ), 0x0C , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMLE ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 1 , 2 | ( size >> 6 ), 0xD , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCMLT ( u8 size , ARM64Reg Rd , ARM64Reg Rn )
{
2015-06-07 16:57:57 -05:00
Emit2RegMisc ( IsQuad ( Rd ), 0 , 2 | ( size >> 6 ), 0xE , Rd , Rn );
2015-01-07 13:42:36 -06:00
}
void ARM64FloatEmitter :: FCSEL ( ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , CCFlags cond )
{
EmitCondSelect ( 0 , 0 , cond , Rd , Rn , Rm );
}
// Permute
void ARM64FloatEmitter :: UZP1 ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitPermute ( size , 0b001 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: TRN1 ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitPermute ( size , 0b010 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: ZIP1 ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitPermute ( size , 0b011 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: UZP2 ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitPermute ( size , 0b101 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: TRN2 ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitPermute ( size , 0b110 , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: ZIP2 ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm )
{
EmitPermute ( size , 0b111 , Rd , Rn , Rm );
}
2015-01-18 16:25:40 -06:00
// Shift by immediate
void ARM64FloatEmitter :: SSHLL ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn , u32 shift )
{
2015-06-07 16:57:57 -05:00
SSHLL ( src_size , Rd , Rn , shift , false );
}
void ARM64FloatEmitter :: SSHLL2 ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn , u32 shift )
{
SSHLL ( src_size , Rd , Rn , shift , true );
}
void ARM64FloatEmitter :: SHRN ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn , u32 shift )
{
SHRN ( dest_size , Rd , Rn , shift , false );
}
void ARM64FloatEmitter :: SHRN2 ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn , u32 shift )
{
SHRN ( dest_size , Rd , Rn , shift , true );
}
void ARM64FloatEmitter :: USHLL ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn , u32 shift )
{
USHLL ( src_size , Rd , Rn , shift , false );
}
void ARM64FloatEmitter :: USHLL2 ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn , u32 shift )
{
USHLL ( src_size , Rd , Rn , shift , true );
}
void ARM64FloatEmitter :: SXTL ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn )
{
SXTL ( src_size , Rd , Rn , false );
}
void ARM64FloatEmitter :: SXTL2 ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn )
{
SXTL ( src_size , Rd , Rn , true );
}
void ARM64FloatEmitter :: UXTL ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn )
{
UXTL ( src_size , Rd , Rn , false );
}
void ARM64FloatEmitter :: UXTL2 ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn )
{
UXTL ( src_size , Rd , Rn , true );
2015-01-18 16:25:40 -06:00
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: SSHLL ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn , u32 shift , bool upper )
2015-01-18 16:25:40 -06:00
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , shift < src_size , "%s shift amount must less than the element size!" , __FUNCTION__ );
2015-01-18 16:25:40 -06:00
u32 immh = 0 ;
u32 immb = shift & 0xFFF ;
if ( src_size == 8 )
{
immh = 1 ;
}
else if ( src_size == 16 )
{
immh = 2 | (( shift >> 3 ) & 1 );
}
else if ( src_size == 32 )
{
immh = 4 | (( shift >> 3 ) & 3 );;
}
2015-06-07 16:57:57 -05:00
EmitShiftImm ( upper , 0 , immh , immb , 0b10100 , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: USHLL ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn , u32 shift , bool upper )
{
_assert_msg_ ( DYNA_REC , shift < src_size , "%s shift amount must less than the element size!" , __FUNCTION__ );
u32 immh = 0 ;
u32 immb = shift & 0xFFF ;
if ( src_size == 8 )
{
immh = 1 ;
}
else if ( src_size == 16 )
{
immh = 2 | (( shift >> 3 ) & 1 );
}
else if ( src_size == 32 )
{
immh = 4 | (( shift >> 3 ) & 3 );;
}
EmitShiftImm ( upper , 1 , immh , immb , 0b10100 , Rd , Rn );
}
void ARM64FloatEmitter :: SHRN ( u8 dest_size , ARM64Reg Rd , ARM64Reg Rn , u32 shift , bool upper )
2015-01-18 16:25:40 -06:00
{
2015-02-12 18:43:50 -06:00
_assert_msg_ ( DYNA_REC , shift < dest_size , "%s shift amount must less than the element size!" , __FUNCTION__ );
2015-01-18 16:25:40 -06:00
u32 immh = 0 ;
u32 immb = shift & 0xFFF ;
if ( dest_size == 8 )
{
immh = 1 ;
}
else if ( dest_size == 16 )
{
immh = 2 | (( shift >> 3 ) & 1 );
}
else if ( dest_size == 32 )
{
immh = 4 | (( shift >> 3 ) & 3 );;
}
2015-06-07 16:57:57 -05:00
EmitShiftImm ( upper , 1 , immh , immb , 0b10000 , Rd , Rn );
2015-01-18 16:25:40 -06:00
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: SXTL ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn , bool upper )
2015-01-18 16:25:40 -06:00
{
2015-06-07 16:57:57 -05:00
SSHLL ( src_size , Rd , Rn , 0 , upper );
2015-01-18 16:25:40 -06:00
}
2015-06-07 16:57:57 -05:00
void ARM64FloatEmitter :: UXTL ( u8 src_size , ARM64Reg Rd , ARM64Reg Rn , bool upper )
2015-01-18 16:25:40 -06:00
{
2015-06-07 16:57:57 -05:00
USHLL ( src_size , Rd , Rn , 0 , upper );
2015-01-18 16:25:40 -06:00
}
2015-02-12 18:47:06 -06:00
// vector x indexed element
void ARM64FloatEmitter :: FMUL ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , u8 index )
{
_assert_msg_ ( DYNA_REC , size == 32 || size == 64 , "%s only supports 32bit or 64bit size!" , __FUNCTION__ );
bool L = false ;
bool H = false ;
if ( size == 32 )
{
L = index & 1 ;
H = ( index >> 1 ) & 1 ;
}
else if ( size == 64 )
{
H = index == 1 ;
}
2015-06-07 16:57:57 -05:00
EmitVectorxElement ( 0 , 2 | ( size >> 6 ), L , 0x9 , H , Rd , Rn , Rm );
}
void ARM64FloatEmitter :: FMLA ( u8 size , ARM64Reg Rd , ARM64Reg Rn , ARM64Reg Rm , u8 index )
{
_assert_msg_ ( DYNA_REC , size == 32 || size == 64 , "%s only supports 32bit or 64bit size!" , __FUNCTION__ );
bool L = false ;
bool H = false ;
if ( size == 32 )
{
L = index & 1 ;
H = ( index >> 1 ) & 1 ;
}
else if ( size == 64 )
{
H = index == 1 ;
}
EmitVectorxElement ( 0 , 2 | ( size >> 6 ), L , 1 , H , Rd , Rn , Rm );
2015-02-12 18:47:06 -06:00
}
2015-08-23 15:34:53 -05:00
// Modified Immediate
void ARM64FloatEmitter :: MOVI ( u8 size , ARM64Reg Rd , u64 imm , u8 shift )
{
bool Q = IsQuad ( Rd );
u8 cmode = 0 ;
u8 op = 0 ;
u8 abcdefgh = imm & 0xFF ;
if ( size == 8 )
{
_assert_msg_ ( DYNA_REC , shift == 0 , "%s(size8) doesn't support shift!" , __FUNCTION__ );
_assert_msg_ ( DYNA_REC , ! ( imm & ~ 0xFFULL ), "%s(size8) only supports 8bit values!" , __FUNCTION__ );
}
else if ( size == 16 )
{
_assert_msg_ ( DYNA_REC , shift == 0 || shift == 8 , "%s(size16) only supports shift of {0, 8}!" , __FUNCTION__ );
_assert_msg_ ( DYNA_REC , ! ( imm & ~ 0xFFULL ), "%s(size16) only supports 8bit values!" , __FUNCTION__ );
if ( shift == 8 )
cmode |= 2 ;
}
else if ( size == 32 )
{
_assert_msg_ ( DYNA_REC ,
shift == 0 || shift == 8 || shift == 16 || shift == 24 ,
"%s(size32) only supports shift of {0, 8, 16, 24}!" , __FUNCTION__ );
// XXX: Implement support for MOVI - shifting ones variant
_assert_msg_ ( DYNA_REC , ! ( imm & ~ 0xFFULL ), "%s(size32) only supports 8bit values!" , __FUNCTION__ );
switch ( shift )
{
case 8 : cmode |= 2 ; break ;
case 16 : cmode |= 4 ; break ;
case 24 : cmode |= 6 ; break ;
default : break ;
}
}
else // 64
{
_assert_msg_ ( DYNA_REC , shift == 0 , "%s(size64) doesn't support shift!" , __FUNCTION__ );
op = 1 ;
cmode = 0xE ;
abcdefgh = 0 ;
for ( int i = 0 ; i < 8 ; ++ i )
{
u8 tmp = ( imm >> ( i << 3 )) & 0xFF ;
_assert_msg_ ( DYNA_REC , tmp == 0xFF || tmp == 0 , "%s(size64) Invalid immediate!" , __FUNCTION__ );
if ( tmp == 0xFF )
abcdefgh |= ( 1 << i );
}
}
EncodeModImm ( Q , op , cmode , 0 , Rd , abcdefgh );
}
void ARM64FloatEmitter :: BIC ( u8 size , ARM64Reg Rd , u8 imm , u8 shift )
{
bool Q = IsQuad ( Rd );
u8 cmode = 1 ;
u8 op = 1 ;
if ( size == 16 )
{
_assert_msg_ ( DYNA_REC , shift == 0 || shift == 8 , "%s(size16) only supports shift of {0, 8}!" , __FUNCTION__ );
if ( shift == 8 )
cmode |= 2 ;
}
else if ( size == 32 )
{
_assert_msg_ ( DYNA_REC ,
shift == 0 || shift == 8 || shift == 16 || shift == 24 ,
"%s(size32) only supports shift of {0, 8, 16, 24}!" , __FUNCTION__ );
// XXX: Implement support for MOVI - shifting ones variant
switch ( shift )
{
case 8 : cmode |= 2 ; break ;
case 16 : cmode |= 4 ; break ;
case 24 : cmode |= 6 ; break ;
default : break ;
}
}
else
_assert_msg_ ( DYNA_REC , false , "%s only supports size of {16, 32}!" , __FUNCTION__ );
EncodeModImm ( Q , op , cmode , 0 , Rd , imm );
}
2015-03-02 11:21:15 -06:00
void ARM64FloatEmitter :: ABI_PushRegisters ( BitSet32 registers , ARM64Reg tmp )
2015-01-07 13:42:36 -06:00
{
2015-02-28 04:39:15 -06:00
bool bundled_loadstore = false ;
2015-03-02 03:41:45 -06:00
2015-02-28 04:39:15 -06:00
for ( int i = 0 ; i < 32 ; ++ i )
2015-01-07 13:42:36 -06:00
{
if ( ! registers [ i ])
continue ;
2015-02-28 04:39:15 -06:00
int count = 0 ;
while ( ++ count < 4 && ( i + count ) < 32 && registers [ i + count ]) {}
if ( count > 1 )
{
bundled_loadstore = true ;
break ;
}
}
2015-03-02 11:21:15 -06:00
if ( bundled_loadstore && tmp != INVALID_REG )
2015-02-28 04:39:15 -06:00
{
2015-03-02 23:50:33 -06:00
int num_regs = registers . Count ();
2015-02-28 04:39:15 -06:00
m_emit -> SUB ( SP , SP , num_regs * 16 );
2015-03-02 11:21:15 -06:00
m_emit -> ADD ( tmp , SP , 0 );
2015-03-02 23:50:33 -06:00
std :: vector < ARM64Reg > island_regs ;
2015-02-28 04:39:15 -06:00
for ( int i = 0 ; i < 32 ; ++ i )
{
if ( ! registers [ i ])
continue ;
int count = 0 ;
// 0 = true
// 1 < 4 && registers[i + 1] true!
// 2 < 4 && registers[i + 2] true!
// 3 < 4 && registers[i + 3] true!
// 4 < 4 && registers[i + 4] false!
while ( ++ count < 4 && ( i + count ) < 32 && registers [ i + count ]) {}
2015-03-02 23:50:33 -06:00
if ( count == 1 )
island_regs . push_back (( ARM64Reg )( Q0 + i ));
else
ST1 ( 64 , count , INDEX_POST , ( ARM64Reg )( Q0 + i ), tmp );
2015-02-28 04:39:15 -06:00
i += count - 1 ;
}
2015-03-02 23:50:33 -06:00
// Handle island registers
std :: vector < ARM64Reg > pair_regs ;
for ( auto & it : island_regs )
{
pair_regs . push_back ( it );
if ( pair_regs . size () == 2 )
{
STP ( 128 , INDEX_POST , pair_regs [ 0 ], pair_regs [ 1 ], tmp , 32 );
pair_regs . clear ();
}
}
if ( pair_regs . size ())
STR ( 128 , INDEX_POST , pair_regs [ 0 ], tmp , 16 );
2015-03-02 11:21:15 -06:00
}
else
{
2015-03-02 23:50:33 -06:00
std :: vector < ARM64Reg > pair_regs ;
2015-03-02 11:21:15 -06:00
for ( auto it : registers )
2015-03-02 23:50:33 -06:00
{
pair_regs . push_back (( ARM64Reg )( Q0 + it ));
if ( pair_regs . size () == 2 )
{
STP ( 128 , INDEX_PRE , pair_regs [ 0 ], pair_regs [ 1 ], SP , - 32 );
pair_regs . clear ();
}
}
if ( pair_regs . size ())
STR ( 128 , INDEX_PRE , pair_regs [ 0 ], SP , - 16 );
2015-02-28 04:39:15 -06:00
}
}
2015-03-02 11:21:15 -06:00
void ARM64FloatEmitter :: ABI_PopRegisters ( BitSet32 registers , ARM64Reg tmp )
2015-02-28 04:39:15 -06:00
{
bool bundled_loadstore = false ;
2015-03-02 03:41:45 -06:00
int num_regs = registers . Count ();
2015-02-28 04:39:15 -06:00
for ( int i = 0 ; i < 32 ; ++ i )
{
if ( ! registers [ i ])
continue ;
int count = 0 ;
while ( ++ count < 4 && ( i + count ) < 32 && registers [ i + count ]) {}
if ( count > 1 )
{
bundled_loadstore = true ;
break ;
}
}
2015-03-02 11:21:15 -06:00
if ( bundled_loadstore && tmp != INVALID_REG )
2015-02-28 04:39:15 -06:00
{
2015-03-02 11:21:15 -06:00
// The temporary register is only used to indicate that we can use this code path
2015-03-02 23:50:33 -06:00
std :: vector < ARM64Reg > island_regs ;
2015-02-28 04:39:15 -06:00
for ( int i = 0 ; i < 32 ; ++ i )
{
if ( ! registers [ i ])
continue ;
int count = 0 ;
while ( ++ count < 4 && ( i + count ) < 32 && registers [ i + count ]) {}
2015-03-02 23:50:33 -06:00
if ( count == 1 )
island_regs . push_back (( ARM64Reg )( Q0 + i ));
else
LD1 ( 64 , count , INDEX_POST , ( ARM64Reg )( Q0 + i ), SP );
2015-02-28 04:39:15 -06:00
i += count - 1 ;
}
2015-03-02 23:50:33 -06:00
// Handle island registers
std :: vector < ARM64Reg > pair_regs ;
for ( auto & it : island_regs )
{
pair_regs . push_back ( it );
if ( pair_regs . size () == 2 )
{
LDP ( 128 , INDEX_POST , pair_regs [ 0 ], pair_regs [ 1 ], SP , 32 );
pair_regs . clear ();
}
}
if ( pair_regs . size ())
LDR ( 128 , INDEX_POST , pair_regs [ 0 ], SP , 16 );
2015-01-07 13:42:36 -06:00
}
2015-03-02 11:21:15 -06:00
else
{
2015-03-02 23:50:33 -06:00
bool odd = num_regs % 2 ;
std :: vector < ARM64Reg > pair_regs ;
2015-03-02 11:21:15 -06:00
for ( int i = 31 ; i >= 0 ; -- i )
{
if ( ! registers [ i ])
continue ;
2015-03-02 23:50:33 -06:00
if ( odd )
{
// First load must be a regular LDR if odd
odd = false ;
LDR ( 128 , INDEX_POST , ( ARM64Reg )( Q0 + i ), SP , 16 );
}
else
{
pair_regs . push_back (( ARM64Reg )( Q0 + i ));
if ( pair_regs . size () == 2 )
{
LDP ( 128 , INDEX_POST , pair_regs [ 1 ], pair_regs [ 0 ], SP , 32 );
pair_regs . clear ();
}
}
2015-03-02 11:21:15 -06:00
}
}
2015-01-07 13:42:36 -06:00
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: ANDI2R ( ARM64Reg Rd , ARM64Reg Rn , u64 imm , ARM64Reg scratch )
{
unsigned int n , imm_s , imm_r ;
if ( ! Is64Bit ( Rn ))
imm &= 0xFFFFFFFF ;
if ( IsImmLogical ( imm , Is64Bit ( Rn ) ? 64 : 32 , & n , & imm_s , & imm_r ))
{
AND ( Rd , Rn , imm_r , imm_s , n != 0 );
}
else
{
_assert_msg_ ( DYNA_REC , scratch != INVALID_REG , "ANDSI2R - failed to construct logical immediate value from %08x, need scratch" , ( u32 ) imm );
MOVI2R ( scratch , imm );
AND ( Rd , Rn , scratch );
}
2014-02-05 01:56:23 +00:00
}
2015-06-07 16:57:57 -05:00
void ARM64XEmitter :: ORRI2R ( ARM64Reg Rd , ARM64Reg Rn , u64 imm , ARM64Reg scratch )
{
unsigned int n , imm_s , imm_r ;
if ( IsImmLogical ( imm , Is64Bit ( Rn ) ? 64 : 32 , & n , & imm_s , & imm_r ))
{
ORR ( Rd , Rn , imm_r , imm_s , n != 0 );
}
else
{
_assert_msg_ ( DYNA_REC , scratch != INVALID_REG , "ORRI2R - failed to construct logical immediate value from %08x, need scratch" , ( u32 ) imm );
MOVI2R ( scratch , imm );
ORR ( Rd , Rn , scratch );
}
}
void ARM64XEmitter :: EORI2R ( ARM64Reg Rd , ARM64Reg Rn , u64 imm , ARM64Reg scratch )
{
unsigned int n , imm_s , imm_r ;
if ( IsImmLogical ( imm , Is64Bit ( Rn ) ? 64 : 32 , & n , & imm_s , & imm_r ))
{
EOR ( Rd , Rn , imm_r , imm_s , n != 0 );
}
else
{
_assert_msg_ ( DYNA_REC , scratch != INVALID_REG , "EORI2R - failed to construct logical immediate value from %08x, need scratch" , ( u32 ) imm );
MOVI2R ( scratch , imm );
EOR ( Rd , Rn , scratch );
}
}
void ARM64XEmitter :: ANDSI2R ( ARM64Reg Rd , ARM64Reg Rn , u64 imm , ARM64Reg scratch )
{
unsigned int n , imm_s , imm_r ;
if ( IsImmLogical ( imm , Is64Bit ( Rn ) ? 64 : 32 , & n , & imm_s , & imm_r ))
{
ANDS ( Rd , Rn , imm_r , imm_s , n != 0 );
}
else
{
_assert_msg_ ( DYNA_REC , scratch != INVALID_REG , "ANDSI2R - failed to construct logical immediate value from %08x, need scratch" , ( u32 ) imm );
MOVI2R ( scratch , imm );
ANDS ( Rd , Rn , scratch );
}
}
void ARM64XEmitter :: ADDI2R ( ARM64Reg Rd , ARM64Reg Rn , u64 imm , ARM64Reg scratch )
{
u32 val ;
bool shift ;
if ( IsImmArithmetic ( imm , & val , & shift ))
{
ADD ( Rd , Rn , val , shift );
}
else
{
_assert_msg_ ( DYNA_REC , scratch != INVALID_REG , "ADDI2R - failed to construct arithmetic immediate value from %08x, need scratch" , ( u32 ) imm );
MOVI2R ( scratch , imm );
ADD ( Rd , Rn , scratch );
}
}
void ARM64XEmitter :: SUBI2R ( ARM64Reg Rd , ARM64Reg Rn , u64 imm , ARM64Reg scratch )
{
u32 val ;
bool shift ;
if ( IsImmArithmetic ( imm , & val , & shift ))
{
SUB ( Rd , Rn , val , shift );
}
else
{
_assert_msg_ ( DYNA_REC , scratch != INVALID_REG , "SUBI2R - failed to construct arithmetic immediate value from %08x, need scratch" , ( u32 ) imm );
MOVI2R ( scratch , imm );
SUB ( Rd , Rn , scratch );
}
}
void ARM64XEmitter :: CMPI2R ( ARM64Reg Rn , u64 imm , ARM64Reg scratch )
{
u32 val ;
bool shift ;
if ( IsImmArithmetic ( imm , & val , & shift ))
{
CMP ( Rn , val , shift );
}
else
{
_assert_msg_ ( DYNA_REC , scratch != INVALID_REG , "CMPI2R - failed to construct arithmetic immediate value from %08x, need scratch" , ( u32 ) imm );
MOVI2R ( scratch , imm );
CMP ( Rn , scratch );
}
}
bool ARM64XEmitter :: TryADDI2R ( ARM64Reg Rd , ARM64Reg Rn , u32 imm )
{
u32 val ;
bool shift ;
if ( IsImmArithmetic ( imm , & val , & shift ))
ADD ( Rd , Rn , val , shift );
else
return false ;
return true ;
}
bool ARM64XEmitter :: TrySUBI2R ( ARM64Reg Rd , ARM64Reg Rn , u32 imm )
{
u32 val ;
bool shift ;
if ( IsImmArithmetic ( imm , & val , & shift ))
SUB ( Rd , Rn , val , shift );
else
return false ;
return true ;
}
bool ARM64XEmitter :: TryCMPI2R ( ARM64Reg Rn , u32 imm )
{
u32 val ;
bool shift ;
if ( IsImmArithmetic ( imm , & val , & shift ))
CMP ( Rn , val , shift );
else
return false ;
return true ;
}
bool ARM64XEmitter :: TryANDI2R ( ARM64Reg Rd , ARM64Reg Rn , u32 imm )
{
u32 n , imm_r , imm_s ;
if ( IsImmLogical ( imm , 32 , & n , & imm_s , & imm_r ))
AND ( Rd , Rn , imm_r , imm_s , n != 0 );
else
return false ;
return true ;
}
bool ARM64XEmitter :: TryORRI2R ( ARM64Reg Rd , ARM64Reg Rn , u32 imm )
{
u32 n , imm_r , imm_s ;
if ( IsImmLogical ( imm , 32 , & n , & imm_s , & imm_r ))
ORR ( Rd , Rn , imm_r , imm_s , n != 0 );
else
return false ;
return true ;
}
bool ARM64XEmitter :: TryEORI2R ( ARM64Reg Rd , ARM64Reg Rn , u32 imm )
{
u32 n , imm_r , imm_s ;
if ( IsImmLogical ( imm , 32 , & n , & imm_s , & imm_r ))
EOR ( Rd , Rn , imm_r , imm_s , n != 0 );
else
return false ;
return true ;
}
float FPImm8ToFloat ( uint8_t bits )
{
int sign = bits >> 7 ;
uint32_t f = ( sign << 31 );
int bit6 = ( bits >> 6 ) & 1 ;
uint32_t exp = (( ! bit6 ) << 7 ) | ( 0x7C * bit6 ) | (( bits >> 4 ) & 3 );
uint32_t mantissa = ( bits & 0xF ) << 19 ;
f |= exp << 23 ;
f |= mantissa ;
float fl ;
memcpy ( & fl , & f , sizeof ( float ));
return fl ;
}
bool FPImm8FromFloat ( float value , uint8_t * immOut )
{
uint32_t f ;
memcpy ( & f , & value , sizeof ( float ));
uint32_t mantissa4 = ( f & 0x7FFFFF ) >> 19 ;
uint32_t exponent = ( f >> 23 ) & 0xFF ;
uint32_t sign = f >> 31 ;
if (( exponent >> 7 ) == (( exponent >> 6 ) & 1 ))
return false ;
uint8_t imm8 = ( sign << 7 ) | (( ! ( exponent >> 7 )) << 6 ) | (( exponent & 3 ) << 4 ) | mantissa4 ;
float newFloat = FPImm8ToFloat ( imm8 );
if ( newFloat == value )
* immOut = imm8 ;
else
return false ;
return true ;
}
void ARM64FloatEmitter :: MOVI2F ( ARM64Reg Rd , float value , ARM64Reg scratch , bool negate )
{
_assert_msg_ ( DYNA_REC , ! IsDouble ( Rd ), "MOVI2F does not yet support double precision" );
uint8_t imm8 ;
if ( value == 0.0 )
{
FMOV ( Rd , IsDouble ( Rd ) ? ZR : WZR );
if ( negate )
FNEG ( Rd , Rd );
// TODO: There are some other values we could generate with the float-imm instruction, like 1.0...
}
else if ( FPImm8FromFloat ( value , & imm8 ))
{
FMOV ( Rd , imm8 );
}
else
{
_assert_msg_ ( DYNA_REC , scratch != INVALID_REG , "Failed to find a way to generate FP immediate %f without scratch" , value );
u32 ival ;
if ( negate )
value = - value ;
memcpy ( & ival , & value , sizeof ( ival ));
m_emit -> MOVI2R ( scratch , ival );
FMOV ( Rd , scratch );
}
}
// TODO: Quite a few values could be generated easily using the MOVI instruction and friends.
void ARM64FloatEmitter :: MOVI2FDUP ( ARM64Reg Rd , float value , ARM64Reg scratch )
{
// TODO: Make it work with more element sizes
// TODO: Optimize - there are shorter solution for many values
ARM64Reg s = ( ARM64Reg )( S0 + DecodeReg ( Rd ));
MOVI2F ( s , value , scratch );
DUP ( 32 , Rd , Rd , 0 );
}
void ARM64XEmitter :: SUBSI2R ( ARM64Reg Rd , ARM64Reg Rn , u64 imm , ARM64Reg scratch )
{
u32 val ;
bool shift ;
if ( IsImmArithmetic ( imm , & val , & shift ))
{
SUBS ( Rd , Rn , val , shift );
}
else
{
_assert_msg_ ( DYNA_REC , scratch != INVALID_REG , "ANDSI2R - failed to construct immediate value from %08x, need scratch" , ( u32 ) imm );
MOVI2R ( scratch , imm );
SUBS ( Rd , Rn , scratch );
}
}
} // namespace