| 
									
										
										
										
											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>
 | 
					
						
							| 
									
										
										
										
											2016-09-13 21:45:23 +02:00
										 |  |  | #include <array>
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-27 11:56:22 +01:00
										 |  |  | #include "Common/Align.h"
 | 
					
						
							| 
									
										
										
										
											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-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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // 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; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t LargestPowerOf2Divisor(uint64_t value) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return value & -(int64_t)value; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool IsPowerOfTwo(uint64_t x) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return (x != 0) && ((x & (x - 1)) == 0); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define V8_UINT64_C(x) ((uint64_t)(x))
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:16:51 +01:00
										 |  |  | bool IsImmArithmetic(uint64_t input, u32* val, bool* shift) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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).
 | 
					
						
							| 
									
										
										
										
											2016-09-13 21:45:23 +02:00
										 |  |  |   static const std::array<uint64_t, 6> multipliers = {{ | 
					
						
							|  |  |  |       0x0000000000000001UL, 0x0000000100000001UL, 0x0001000100010001UL, 0x0101010101010101UL, | 
					
						
							|  |  |  |       0x1111111111111111UL, 0x5555555555555555UL, | 
					
						
							|  |  |  |   }}; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-15 10:26:59 +02:00
										 |  |  | void ARM64XEmitter::SetCodePtrUnsafe(u8* ptr) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_code = ptr; | 
					
						
							| 
									
										
										
										
											2015-08-15 10:26:59 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::SetCodePtr(u8* ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return m_code; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::ReserveCodeSpace(u32 bytes) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (u32 i = 0; i < bytes / 4; i++) | 
					
						
							|  |  |  |     BRK(0); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-08 22:52:52 -04:00
										 |  |  | const u8* ARM64XEmitter::AlignCode16() | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int c = int((u64)m_code & 15); | 
					
						
							|  |  |  |   if (c) | 
					
						
							|  |  |  |     ReserveCodeSpace(16 - c); | 
					
						
							|  |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int c = int((u64)m_code & 4095); | 
					
						
							|  |  |  |   if (c) | 
					
						
							|  |  |  |     ReserveCodeSpace(4096 - c); | 
					
						
							|  |  |  |   return m_code; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 15:32:11 -04:00
										 |  |  | void ARM64XEmitter::Write32(u32 value) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::memcpy(m_code, &value, sizeof(u32)); | 
					
						
							|  |  |  |   m_code += sizeof(u32); | 
					
						
							| 
									
										
										
										
											2015-10-22 15:32:11 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | void ARM64XEmitter::FlushIcache() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (start == end) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2015-07-11 12:22:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | #if defined(IOS)
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
 | 
					
						
							|  |  |  |   sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-09-10 02:31:07 +02:00
										 |  |  |   // Don't rely on GCC's __clear_cache implementation, as it caches
 | 
					
						
							|  |  |  |   // icache/dcache cache line sizes, that can vary between cores on
 | 
					
						
							|  |  |  |   // big.LITTLE architectures.
 | 
					
						
							|  |  |  |   u64 addr, ctr_el0; | 
					
						
							|  |  |  |   static size_t icache_line_size = 0xffff, dcache_line_size = 0xffff; | 
					
						
							|  |  |  |   size_t isize, dsize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   __asm__ volatile("mrs %0, ctr_el0" : "=r"(ctr_el0)); | 
					
						
							|  |  |  |   isize = 4 << ((ctr_el0 >> 0) & 0xf); | 
					
						
							|  |  |  |   dsize = 4 << ((ctr_el0 >> 16) & 0xf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // use the global minimum cache line size
 | 
					
						
							|  |  |  |   icache_line_size = isize = icache_line_size < isize ? icache_line_size : isize; | 
					
						
							|  |  |  |   dcache_line_size = dsize = dcache_line_size < dsize ? dcache_line_size : dsize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   addr = (u64)start & ~(u64)(dsize - 1); | 
					
						
							|  |  |  |   for (; addr < (u64)end; addr += dsize) | 
					
						
							| 
									
										
										
										
											2016-09-10 08:05:16 +02:00
										 |  |  |     // use "civac" instead of "cvau", as this is the suggested workaround for
 | 
					
						
							|  |  |  |     // Cortex-A53 errata 819472, 826319, 827319 and 824069.
 | 
					
						
							| 
									
										
										
										
											2016-09-10 02:31:07 +02:00
										 |  |  |     __asm__ volatile("dc civac, %0" : : "r"(addr) : "memory"); | 
					
						
							|  |  |  |   __asm__ volatile("dsb ish" : : : "memory"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   addr = (u64)start & ~(u64)(isize - 1); | 
					
						
							|  |  |  |   for (; addr < (u64)end; addr += isize) | 
					
						
							|  |  |  |     __asm__ volatile("ic ivau, %0" : : "r"(addr) : "memory"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   __asm__ volatile("dsb ish" : : : "memory"); | 
					
						
							|  |  |  |   __asm__ volatile("isb" : : : "memory"); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Exception generation
 | 
					
						
							| 
									
										
										
										
											2014-11-25 23:12:15 -05:00
										 |  |  | static const u32 ExcEnc[][3] = { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Arithmetic generation
 | 
					
						
							| 
									
										
										
										
											2014-11-25 23:12:15 -05:00
										 |  |  | static const u32 ArithEnc[] = { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     0x058,  // ADD
 | 
					
						
							|  |  |  |     0x258,  // SUB
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Conditional Select
 | 
					
						
							| 
									
										
										
										
											2014-11-25 23:12:15 -05:00
										 |  |  | static const u32 CondSelectEnc[][2] = { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     {0, 0},  // CSEL
 | 
					
						
							|  |  |  |     {0, 1},  // CSINC
 | 
					
						
							|  |  |  |     {1, 0},  // CSINV
 | 
					
						
							|  |  |  |     {1, 1},  // CSNEG
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Data-Processing (1 source)
 | 
					
						
							| 
									
										
										
										
											2014-11-25 23:12:15 -05:00
										 |  |  | static const u32 Data1SrcEnc[][2] = { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     {0, 0},  // RBIT
 | 
					
						
							|  |  |  |     {0, 1},  // REV16
 | 
					
						
							|  |  |  |     {0, 2},  // REV32
 | 
					
						
							|  |  |  |     {0, 3},  // REV64
 | 
					
						
							|  |  |  |     {0, 4},  // CLZ
 | 
					
						
							|  |  |  |     {0, 5},  // CLS
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Data-Processing (2 source)
 | 
					
						
							| 
									
										
										
										
											2014-11-25 23:12:15 -05:00
										 |  |  | static const u32 Data2SrcEnc[] = { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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)
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Data-Processing (3 source)
 | 
					
						
							| 
									
										
										
										
											2014-11-25 23:12:15 -05:00
										 |  |  | static const u32 Data3SrcEnc[][2] = { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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)
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Logical (shifted register)
 | 
					
						
							| 
									
										
										
										
											2014-11-25 23:12:15 -05:00
										 |  |  | static const u32 LogicalEnc[][2] = { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Load/Store Exclusive
 | 
					
						
							| 
									
										
										
										
											2015-07-02 11:09:01 -04:00
										 |  |  | static const u32 LoadStoreExcEnc[][5] = { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeCompareBranchInst(u32 op, ARM64Reg Rt, const void* ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   s64 distance = (s64)ptr - (s64)m_code; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %lx", | 
					
						
							|  |  |  |                __FUNCTION__, distance); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   distance >>= 2; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (0x34 << 24) | (op << 24) | (((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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   s64 distance = (s64)ptr - (s64)m_code; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %lx", | 
					
						
							|  |  |  |                __FUNCTION__, distance); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   distance >>= 2; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, distance >= -0x3FFF && distance < 0x3FFF, | 
					
						
							|  |  |  |                "%s: Received too large distance: %lx", __FUNCTION__, distance); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (0x36 << 24) | (op << 24) | (bits << 19) | | 
					
						
							|  |  |  |           (((u32)distance << 5) & 0x7FFE0) | Rt); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeUnconditionalBranchInst(u32 op, const void* ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s64 distance = (s64)ptr - s64(m_code); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %lx", | 
					
						
							|  |  |  |                __FUNCTION__, distance); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   distance >>= 2; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((op << 31) | (0x5 << 26) | (distance & 0x3FFFFFF)); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeUnconditionalBranchInst(u32 opc, u32 op2, u32 op3, u32 op4, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((0x6B << 25) | (opc << 21) | (op2 << 16) | (op3 << 10) | (Rn << 5) | op4); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeExceptionInst(u32 instenc, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(imm & ~0xFFFF), "%s: Exception instruction too large immediate: %d", | 
					
						
							|  |  |  |                __FUNCTION__, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((0xD4 << 24) | (ExcEnc[instenc][0] << 21) | (imm << 5) | (ExcEnc[instenc][1] << 2) | | 
					
						
							|  |  |  |           ExcEnc[instenc][2]); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeSystemInst(u32 op0, u32 op1, u32 CRn, u32 CRm, u32 op2, ARM64Reg Rt) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((0x354 << 22) | (op0 << 19) | (op1 << 16) | (CRn << 12) | (CRm << 8) | (op2 << 5) | Rt); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, | 
					
						
							|  |  |  |                                          ARM64Reg Rm, ArithOption Option) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (flags << 29) | (ArithEnc[instenc] << 21) | | 
					
						
							|  |  |  |           (Option.GetType() == ArithOption::TYPE_EXTENDEDREG ? (1 << 21) : 0) | (Rm << 16) | | 
					
						
							|  |  |  |           Option.GetData() | (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeArithmeticCarryInst(u32 op, bool flags, ARM64Reg Rd, ARM64Reg Rn, | 
					
						
							|  |  |  |                                               ARM64Reg Rm) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (op << 30) | (flags << 29) | (0xD0 << 21) | (Rm << 16) | (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeCondCompareImmInst(u32 op, ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |           Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (op << 30) | (1 << 29) | (0xD2 << 21) | (imm << 16) | (cond << 12) | | 
					
						
							|  |  |  |           (1 << 11) | (Rn << 5) | nzcv); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeCondCompareRegInst(u32 op, ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, | 
					
						
							|  |  |  |                                              CCFlags cond) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(nzcv & ~0xF), "%s: Flags out of range: %d", __FUNCTION__, nzcv) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       Rm = DecodeReg(Rm); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (op << 30) | (1 << 29) | (0xD2 << 21) | (Rm << 16) | (cond << 12) | | 
					
						
							|  |  |  |           (Rn << 5) | nzcv); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeCondSelectInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, | 
					
						
							|  |  |  |                                          CCFlags cond) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeData1SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (0x2D6 << 21) | (Data1SrcEnc[instenc][0] << 16) | | 
					
						
							|  |  |  |           (Data1SrcEnc[instenc][1] << 10) | (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeData2SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (0x0D6 << 21) | (Rm << 16) | (Data2SrcEnc[instenc] << 10) | (Rn << 5) | | 
					
						
							|  |  |  |           Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeData3SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, | 
					
						
							|  |  |  |                                        ARM64Reg Ra) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeLogicalInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, | 
					
						
							|  |  |  |                                       ArithOption Shift) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (LogicalEnc[instenc][0] << 29) | (0x5 << 25) | | 
					
						
							|  |  |  |           (LogicalEnc[instenc][1] << 21) | Shift.GetData() | (Rm << 16) | (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeLoadRegisterInst(u32 bitop, ARM64Reg Rt, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   bool bVec = IsVector(Rt); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(imm & 0xFFFFF), "%s: offset too large %d", __FUNCTION__, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeLoadStoreExcInst(u32 instenc, ARM64Reg Rs, ARM64Reg Rt2, ARM64Reg Rn, | 
					
						
							|  |  |  |                                            ARM64Reg Rt) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeLoadStorePairedInst(u32 op, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, | 
					
						
							|  |  |  |                                               u32 imm) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   bool b128Bit = IsQuad(Rt); | 
					
						
							|  |  |  |   bool bVec = IsVector(Rt); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (b128Bit) | 
					
						
							|  |  |  |     imm >>= 4; | 
					
						
							|  |  |  |   else if (b64Bit) | 
					
						
							|  |  |  |     imm >>= 3; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     imm >>= 2; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(imm & ~0xF), "%s: offset too large %d", __FUNCTION__, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 opc = 0; | 
					
						
							|  |  |  |   if (b128Bit) | 
					
						
							|  |  |  |     opc = 2; | 
					
						
							|  |  |  |   else if (b64Bit && bVec) | 
					
						
							|  |  |  |     opc = 1; | 
					
						
							|  |  |  |   else if (b64Bit && !bVec) | 
					
						
							|  |  |  |     opc = 2; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rt2 = DecodeReg(Rt2); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((opc << 30) | (bVec << 26) | (op << 22) | (imm << 15) | (Rt2 << 10) | (Rn << 5) | Rt); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   bool bVec = IsVector(Rt); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 offset = imm & 0x1FF; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s: offset too large %d", __FUNCTION__, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   bool bVec = IsVector(Rt); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (size == 64) | 
					
						
							|  |  |  |     imm >>= 3; | 
					
						
							|  |  |  |   else if (size == 32) | 
					
						
							|  |  |  |     imm >>= 2; | 
					
						
							|  |  |  |   else if (size == 16) | 
					
						
							|  |  |  |     imm >>= 1; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED): offset must be positive %d", __FUNCTION__, | 
					
						
							|  |  |  |                imm); | 
					
						
							|  |  |  |   _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s(INDEX_UNSIGNED): offset too large %d", __FUNCTION__, | 
					
						
							|  |  |  |                imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((b64Bit << 30) | (op << 22) | (bVec << 26) | (imm << 10) | (Rn << 5) | Rt); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeMOVWideInst(u32 op, ARM64Reg Rd, u32 imm, ShiftAmount pos) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(imm & ~0xFFFF), "%s: immediate out of range: %d", __FUNCTION__, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (op << 29) | (0x25 << 23) | (pos << 21) | (imm << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EncodeBitfieldMOVInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (op << 29) | (0x26 << 23) | (b64Bit << 22) | (immr << 16) | | 
					
						
							|  |  |  |           (imms << 10) | (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, | 
					
						
							|  |  |  |                                                   ArithOption Rm) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   ARM64Reg decoded_Rm = DecodeReg(Rm.GetReg()); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, | 
					
						
							|  |  |  |                                         ARM64Reg Rd) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s: immediate too large: %x", __FUNCTION__, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Write32((b64Bit << 31) | (op << 30) | (flags << 29) | (0x11 << 24) | (shift << 22) | (imm << 10) | | 
					
						
							|  |  |  |           (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, | 
					
						
							|  |  |  |                                          int n) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Sometimes Rd is fixed to SP, but can still be 32bit or 64bit.
 | 
					
						
							|  |  |  |   // Use Rn to determine bitness here.
 | 
					
						
							|  |  |  |   bool b64Bit = Is64Bit(Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((b64Bit << 31) | (op << 29) | (0x24 << 23) | (n << 22) | (immr << 16) | (imms << 10) | | 
					
						
							|  |  |  |           (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64XEmitter::EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, | 
					
						
							|  |  |  |                                         ARM64Reg Rn, s32 imm) | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   u32 type_encode = 0; | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (b64Bit) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     op |= 0b10; | 
					
						
							|  |  |  |     imm >>= 3; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     imm >>= 2; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rt2 = DecodeReg(Rt2); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((op << 30) | (0b101 << 27) | (type_encode << 23) | (load << 22) | ((imm & 0x7F) << 15) | | 
					
						
							|  |  |  |           (Rt2 << 10) | (Rn << 5) | Rt); | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-12-15 14:23:09 -06:00
										 |  |  | void ARM64XEmitter::EncodeAddressInst(u32 op, ARM64Reg Rd, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							| 
									
										
										
										
											2014-12-15 14:23:09 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((op << 31) | ((imm & 0x3) << 29) | (0x10 << 24) | ((imm & 0x1FFFFC) << 3) | Rd); | 
					
						
							| 
									
										
										
										
											2014-12-15 14:23:09 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | void ARM64XEmitter::EncodeLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s received too large offset: %d", | 
					
						
							|  |  |  |                __FUNCTION__, imm); | 
					
						
							|  |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((size << 30) | (0b111 << 27) | (op << 22) | ((imm & 0x1FF) << 12) | (Rn << 5) | Rt); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 15:20:35 -04:00
										 |  |  | static constexpr bool IsInRangeImm19(s64 distance) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return (distance >= -0x40000 && distance <= 0x3FFFF); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 15:20:35 -04:00
										 |  |  | static constexpr bool IsInRangeImm14(s64 distance) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return (distance >= -0x2000 && distance <= 0x1FFF); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 15:20:35 -04:00
										 |  |  | static constexpr bool IsInRangeImm26(s64 distance) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return (distance >= -0x2000000 && distance <= 0x1FFFFFF); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 15:20:35 -04:00
										 |  |  | static constexpr u32 MaskImm19(s64 distance) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return distance & 0x7FFFF; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 15:20:35 -04:00
										 |  |  | static constexpr u32 MaskImm14(s64 distance) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return distance & 0x3FFF; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 15:20:35 -04:00
										 |  |  | static constexpr u32 MaskImm26(s64 distance) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return distance & 0x3FFFFFF; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool Not = false; | 
					
						
							|  |  |  |   u32 inst = 0; | 
					
						
							|  |  |  |   s64 distance = (s64)(m_code - branch.ptr); | 
					
						
							|  |  |  |   distance >>= 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (branch.type) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case 1:  // CBNZ
 | 
					
						
							|  |  |  |     Not = true; | 
					
						
							|  |  |  |   case 0:  // CBZ
 | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     _assert_msg_(DYNA_REC, IsInRangeImm19(distance), "%s(%d): Received too large distance: %lx", | 
					
						
							|  |  |  |                  __FUNCTION__, branch.type, distance); | 
					
						
							|  |  |  |     bool b64Bit = Is64Bit(branch.reg); | 
					
						
							|  |  |  |     ARM64Reg reg = DecodeReg(branch.reg); | 
					
						
							|  |  |  |     inst = (b64Bit << 31) | (0x1A << 25) | (Not << 24) | (MaskImm19(distance) << 5) | reg; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   break; | 
					
						
							|  |  |  |   case 2:  // B (conditional)
 | 
					
						
							|  |  |  |     _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; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case 4:  // TBNZ
 | 
					
						
							|  |  |  |     Not = true; | 
					
						
							|  |  |  |   case 3:  // TBZ
 | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     _assert_msg_(DYNA_REC, IsInRangeImm14(distance), "%s(%d): Received too large distance: %lx", | 
					
						
							|  |  |  |                  __FUNCTION__, branch.type, distance); | 
					
						
							|  |  |  |     ARM64Reg reg = DecodeReg(branch.reg); | 
					
						
							|  |  |  |     inst = ((branch.bit & 0x20) << 26) | (0x1B << 25) | (Not << 24) | ((branch.bit & 0x1F) << 19) | | 
					
						
							|  |  |  |            (MaskImm14(distance) << 5) | reg; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   break; | 
					
						
							|  |  |  |   case 5:  // B (uncoditional)
 | 
					
						
							|  |  |  |     _assert_msg_(DYNA_REC, IsInRangeImm26(distance), "%s(%d): Received too large distance: %lx", | 
					
						
							|  |  |  |                  __FUNCTION__, branch.type, distance); | 
					
						
							|  |  |  |     inst = (0x5 << 26) | MaskImm26(distance); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case 6:  // BL (unconditional)
 | 
					
						
							|  |  |  |     _assert_msg_(DYNA_REC, IsInRangeImm26(distance), "%s(%d): Received too large distance: %lx", | 
					
						
							|  |  |  |                  __FUNCTION__, branch.type, distance); | 
					
						
							|  |  |  |     inst = (0x25 << 26) | MaskImm26(distance); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   *(u32*)branch.ptr = inst; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FixupBranch ARM64XEmitter::CBZ(ARM64Reg Rt) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   FixupBranch branch; | 
					
						
							|  |  |  |   branch.ptr = m_code; | 
					
						
							|  |  |  |   branch.type = 0; | 
					
						
							|  |  |  |   branch.reg = Rt; | 
					
						
							|  |  |  |   HINT(HINT_NOP); | 
					
						
							|  |  |  |   return branch; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | FixupBranch ARM64XEmitter::CBNZ(ARM64Reg Rt) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   FixupBranch branch; | 
					
						
							|  |  |  |   branch.ptr = m_code; | 
					
						
							|  |  |  |   branch.type = 1; | 
					
						
							|  |  |  |   branch.reg = Rt; | 
					
						
							|  |  |  |   HINT(HINT_NOP); | 
					
						
							|  |  |  |   return branch; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | FixupBranch ARM64XEmitter::B(CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   FixupBranch branch; | 
					
						
							|  |  |  |   branch.ptr = m_code; | 
					
						
							|  |  |  |   branch.type = 2; | 
					
						
							|  |  |  |   branch.cond = cond; | 
					
						
							|  |  |  |   HINT(HINT_NOP); | 
					
						
							|  |  |  |   return branch; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | FixupBranch ARM64XEmitter::TBZ(ARM64Reg Rt, u8 bit) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   FixupBranch branch; | 
					
						
							|  |  |  |   branch.ptr = m_code; | 
					
						
							|  |  |  |   branch.type = 3; | 
					
						
							|  |  |  |   branch.reg = Rt; | 
					
						
							|  |  |  |   branch.bit = bit; | 
					
						
							|  |  |  |   HINT(HINT_NOP); | 
					
						
							|  |  |  |   return branch; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | FixupBranch ARM64XEmitter::TBNZ(ARM64Reg Rt, u8 bit) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   FixupBranch branch; | 
					
						
							|  |  |  |   branch.ptr = m_code; | 
					
						
							|  |  |  |   branch.type = 4; | 
					
						
							|  |  |  |   branch.reg = Rt; | 
					
						
							|  |  |  |   branch.bit = bit; | 
					
						
							|  |  |  |   HINT(HINT_NOP); | 
					
						
							|  |  |  |   return branch; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | FixupBranch ARM64XEmitter::B() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   FixupBranch branch; | 
					
						
							|  |  |  |   branch.ptr = m_code; | 
					
						
							|  |  |  |   branch.type = 5; | 
					
						
							|  |  |  |   HINT(HINT_NOP); | 
					
						
							|  |  |  |   return branch; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | FixupBranch ARM64XEmitter::BL() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   FixupBranch branch; | 
					
						
							|  |  |  |   branch.ptr = m_code; | 
					
						
							|  |  |  |   branch.type = 6; | 
					
						
							|  |  |  |   HINT(HINT_NOP); | 
					
						
							|  |  |  |   return branch; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Compare and Branch
 | 
					
						
							|  |  |  | void ARM64XEmitter::CBZ(ARM64Reg Rt, const void* ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCompareBranchInst(0, Rt, ptr); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CBNZ(ARM64Reg Rt, const void* ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCompareBranchInst(1, Rt, ptr); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Conditional Branch
 | 
					
						
							|  |  |  | void ARM64XEmitter::B(CCFlags cond, const void* ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s64 distance = (s64)ptr - (s64)m_code; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   distance >>= 2; | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeTestBranchInst(0, Rt, bits, ptr); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::TBNZ(ARM64Reg Rt, u8 bits, const void* ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeTestBranchInst(1, Rt, bits, ptr); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Unconditional Branch
 | 
					
						
							| 
									
										
										
										
											2014-09-08 22:52:52 -04:00
										 |  |  | void ARM64XEmitter::B(const void* ptr) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeUnconditionalBranchInst(0, ptr); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-09-08 22:52:52 -04:00
										 |  |  | void ARM64XEmitter::BL(const void* ptr) | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeUnconditionalBranchInst(1, ptr); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:16:51 +01:00
										 |  |  | void ARM64XEmitter::QuickCallFunction(ARM64Reg scratchreg, const void* func) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | // Unconditional Branch (register)
 | 
					
						
							|  |  |  | void ARM64XEmitter::BR(ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeUnconditionalBranchInst(0, 0x1F, 0, 0, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::BLR(ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeUnconditionalBranchInst(1, 0x1F, 0, 0, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::RET(ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeUnconditionalBranchInst(2, 0x1F, 0, 0, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ERET() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeUnconditionalBranchInst(4, 0x1F, 0, 0, SP); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::DRPS() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeUnconditionalBranchInst(5, 0x1F, 0, 0, SP); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Exception generation
 | 
					
						
							|  |  |  | void ARM64XEmitter::SVC(u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeExceptionInst(0, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::HVC(u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeExceptionInst(1, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::SMC(u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeExceptionInst(2, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::BRK(u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeExceptionInst(3, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::HLT(u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeExceptionInst(4, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::DCPS1(u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeExceptionInst(5, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::DCPS2(u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeExceptionInst(6, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::DCPS3(u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeExceptionInst(7, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // System
 | 
					
						
							|  |  |  | void ARM64XEmitter::_MSR(PStateField field, u8 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 op1 = 0, op2 = 0; | 
					
						
							|  |  |  |   switch (field) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   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); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:27:56 +01:00
										 |  |  | static void GetSystemReg(PStateField field, int& o0, int& op1, int& CRn, int& CRm, int& op2) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   switch (field) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case FIELD_NZCV: | 
					
						
							|  |  |  |     o0 = 3; | 
					
						
							|  |  |  |     op1 = 3; | 
					
						
							|  |  |  |     CRn = 4; | 
					
						
							|  |  |  |     CRm = 2; | 
					
						
							|  |  |  |     op2 = 0; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case FIELD_FPCR: | 
					
						
							|  |  |  |     o0 = 3; | 
					
						
							|  |  |  |     op1 = 3; | 
					
						
							|  |  |  |     CRn = 4; | 
					
						
							|  |  |  |     CRm = 4; | 
					
						
							|  |  |  |     op2 = 0; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case FIELD_FPSR: | 
					
						
							|  |  |  |     o0 = 3; | 
					
						
							|  |  |  |     op1 = 3; | 
					
						
							|  |  |  |     CRn = 4; | 
					
						
							|  |  |  |     CRm = 4; | 
					
						
							|  |  |  |     op2 = 1; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     _assert_msg_(DYNA_REC, false, "Invalid PStateField to do a register move from/to"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::_MSR(PStateField field, ARM64Reg Rt) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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)); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::MRS(ARM64Reg Rt, PStateField field) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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)); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | void ARM64XEmitter::HINT(SystemHint op) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeSystemInst(0, 3, 2, 0, op, WSP); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CLREX() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeSystemInst(0, 3, 3, 0, 2, WSP); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::DSB(BarrierType type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeSystemInst(0, 3, 3, type, 4, WSP); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::DMB(BarrierType type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeSystemInst(0, 3, 3, type, 5, WSP); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ISB(BarrierType type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeSystemInst(0, 3, 3, type, 6, WSP); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Add/Subtract (extended register)
 | 
					
						
							|  |  |  | void ARM64XEmitter::ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeArithmeticInst(0, false, Rd, Rn, Rm, Option); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeArithmeticInst(0, true, Rd, Rn, Rm, Option); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeArithmeticInst(1, false, Rd, Rn, Rm, Option); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeArithmeticInst(1, true, Rd, Rn, Rm, Option); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::CMN(ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeArithmeticCarryInst(0, false, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ADCS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeArithmeticCarryInst(0, true, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::SBC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeArithmeticCarryInst(1, false, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::SBCS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeArithmeticCarryInst(1, true, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Conditional Compare (immediate)
 | 
					
						
							|  |  |  | void ARM64XEmitter::CCMN(ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCondCompareImmInst(0, Rn, imm, nzcv, cond); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CCMP(ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCondCompareImmInst(1, Rn, imm, nzcv, cond); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Conditiona Compare (register)
 | 
					
						
							|  |  |  | void ARM64XEmitter::CCMN(ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCondCompareRegInst(0, Rn, Rm, nzcv, cond); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CCMP(ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCondCompareRegInst(1, Rn, Rm, nzcv, cond); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Conditional Select
 | 
					
						
							|  |  |  | void ARM64XEmitter::CSEL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCondSelectInst(0, Rd, Rn, Rm, cond); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CSINC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCondSelectInst(1, Rd, Rn, Rm, cond); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CSINV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCondSelectInst(2, Rd, Rn, Rm, cond); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CSNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeCondSelectInst(3, Rd, Rn, Rm, cond); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Data-Processing 1 source
 | 
					
						
							|  |  |  | void ARM64XEmitter::RBIT(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData1SrcInst(0, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::REV16(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData1SrcInst(1, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::REV32(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData1SrcInst(2, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::REV64(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData1SrcInst(3, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CLZ(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData1SrcInst(4, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CLS(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData1SrcInst(5, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Data-Processing 2 source
 | 
					
						
							|  |  |  | void ARM64XEmitter::UDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(0, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::SDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(1, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LSLV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(2, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LSRV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(3, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ASRV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(4, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::RORV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(5, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CRC32B(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(6, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CRC32H(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(7, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CRC32W(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(8, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CRC32CB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(9, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CRC32CH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(10, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CRC32CW(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(11, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CRC32X(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(12, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CRC32CX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData2SrcInst(13, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Data-Processing 3 source
 | 
					
						
							|  |  |  | void ARM64XEmitter::MADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData3SrcInst(0, Rd, Rn, Rm, Ra); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::MSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData3SrcInst(1, Rd, Rn, Rm, Ra); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::SMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData3SrcInst(2, Rd, Rn, Rm, Ra); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | void ARM64XEmitter::SMULL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SMADDL(Rd, Rn, Rm, SP); | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | void ARM64XEmitter::SMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData3SrcInst(3, Rd, Rn, Rm, Ra); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData3SrcInst(5, Rd, Rn, Rm, Ra); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-03-04 21:58:17 +01:00
										 |  |  | void ARM64XEmitter::UMULL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   UMADDL(Rd, Rn, Rm, SP); | 
					
						
							| 
									
										
										
										
											2016-03-04 21:58:17 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | void ARM64XEmitter::UMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData3SrcInst(6, Rd, Rn, Rm, Ra); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData3SrcInst(0, Rd, Rn, Rm, SP); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:03:01 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::MNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeData3SrcInst(1, Rd, Rn, Rm, SP); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:03:01 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Logical (shifted register)
 | 
					
						
							|  |  |  | void ARM64XEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLogicalInst(0, Rd, Rn, Rm, Shift); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::BIC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLogicalInst(1, Rd, Rn, Rm, Shift); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLogicalInst(2, Rd, Rn, Rm, Shift); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ORN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLogicalInst(3, Rd, Rn, Rm, Shift); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLogicalInst(4, Rd, Rn, Rm, Shift); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::EON(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLogicalInst(5, Rd, Rn, Rm, Shift); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ANDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLogicalInst(6, Rd, Rn, Rm, Shift); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLogicalInst(7, Rd, Rn, Rm, Shift); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::MOV(ARM64Reg Rd, ARM64Reg Rm, ArithOption Shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, Shift); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-18 16:30:40 -05:00
										 |  |  | void ARM64XEmitter::MOV(ARM64Reg Rd, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ORN(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSL, 0)); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LSL(ARM64Reg Rd, ARM64Reg Rm, int shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSL, shift)); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LSR(ARM64Reg Rd, ARM64Reg Rm, int shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSR, shift)); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ASR(ARM64Reg Rd, ARM64Reg Rm, int shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_ASR, shift)); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ROR(ARM64Reg Rd, ARM64Reg Rm, int shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeAddSubImmInst(0, false, shift, imm, Rn, Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeAddSubImmInst(0, true, shift, imm, Rn, Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::SUB(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeAddSubImmInst(1, false, shift, imm, Rn, Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeAddSubImmInst(1, true, shift, imm, Rn, Rd); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::CMP(ARM64Reg Rn, u32 imm, bool shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeMOVWideInst(2, Rd, imm, pos); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::MOVN(ARM64Reg Rd, u32 imm, ShiftAmount pos) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeMOVWideInst(0, Rd, imm, pos); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::MOVK(ARM64Reg Rd, u32 imm, ShiftAmount pos) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeMOVWideInst(3, Rd, imm, pos); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Bitfield move
 | 
					
						
							|  |  |  | void ARM64XEmitter::BFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeBitfieldMOVInst(1, Rd, Rn, immr, imms); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::SBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeBitfieldMOVInst(0, Rd, Rn, immr, imms); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeBitfieldMOVInst(2, Rd, Rn, immr, imms); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-29 19:00:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::BFI(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2015-06-29 19:00:22 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::UBFIZ(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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-29 19:00:22 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | void ARM64XEmitter::EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-09-10 17:52:54 -05:00
										 |  |  | void ARM64XEmitter::SXTB(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SBFM(Rd, Rn, 0, 7); | 
					
						
							| 
									
										
										
										
											2014-09-10 17:52:54 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::SXTH(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SBFM(Rd, Rn, 0, 15); | 
					
						
							| 
									
										
										
										
											2014-09-10 17:52:54 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::SXTW(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, Is64Bit(Rd), "%s requires 64bit register as destination", __FUNCTION__); | 
					
						
							|  |  |  |   SBFM(Rd, Rn, 0, 31); | 
					
						
							| 
									
										
										
										
											2014-09-10 17:52:54 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | void ARM64XEmitter::UXTB(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   UBFM(Rd, Rn, 0, 7); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::UXTH(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   UBFM(Rd, Rn, 0, 15); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Load Register (Literal)
 | 
					
						
							|  |  |  | void ARM64XEmitter::LDR(ARM64Reg Rt, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadRegisterInst(0, Rt, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDRSW(ARM64Reg Rt, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadRegisterInst(2, Rt, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::PRFM(ARM64Reg Rt, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadRegisterInst(3, Rt, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | // Load/Store pair
 | 
					
						
							|  |  |  | void ARM64XEmitter::LDP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStorePair(0, 1, type, Rt, Rt2, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDPSW(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStorePair(1, 1, type, Rt, Rt2, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStorePair(0, 0, type, Rt, Rt2, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-12-02 18:08:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | // Load/Store Exclusive
 | 
					
						
							|  |  |  | void ARM64XEmitter::STXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(0, Rs, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STLXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(1, Rs, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDXRB(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(2, SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDAXRB(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(3, SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STLRB(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(4, SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDARB(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(5, SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STXRH(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(6, Rs, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STLXRH(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(7, Rs, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDXRH(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(8, SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDAXRH(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(9, SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STLRH(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(10, SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDARH(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(11, SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(18 + Is64Bit(Rt), Rs, Rt2, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDXR(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(20 + Is64Bit(Rt), SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDAXR(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(26 + Is64Bit(Rt), SP, Rt2, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STLR(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreExcInst(28 + Is64Bit(Rt), SP, SP, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDAR(ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStorePairedInst(0xA0, Rt, Rt2, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDNP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStorePairedInst(0xA1, Rt, Rt2, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (type == INDEX_UNSIGNED) | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x0E4, Rt, Rn, imm, 8); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x0E0, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (type == INDEX_UNSIGNED) | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x0E5, Rt, Rn, imm, 8); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x0E1, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (type == INDEX_UNSIGNED) | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x0E6 : 0x0E7, Rt, Rn, imm, 8); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x0E2 : 0x0E3, type == INDEX_POST ? 1 : 3, Rt, Rn, | 
					
						
							|  |  |  |                                imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (type == INDEX_UNSIGNED) | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x1E4, Rt, Rn, imm, 16); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x1E0, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (type == INDEX_UNSIGNED) | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x1E5, Rt, Rn, imm, 16); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x1E1, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (type == INDEX_UNSIGNED) | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x1E6 : 0x1E7, Rt, Rn, imm, 16); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x1E2 : 0x1E3, type == INDEX_POST ? 1 : 3, Rt, Rn, | 
					
						
							|  |  |  |                                imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (type == INDEX_UNSIGNED) | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E4 : 0x2E4, Rt, Rn, imm, Is64Bit(Rt) ? 64 : 32); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E0 : 0x2E0, type == INDEX_POST ? 1 : 3, Rt, Rn, | 
					
						
							|  |  |  |                                imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (type == INDEX_UNSIGNED) | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E5 : 0x2E5, Rt, Rn, imm, Is64Bit(Rt) ? 64 : 32); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E1 : 0x2E1, type == INDEX_POST ? 1 : 3, Rt, Rn, | 
					
						
							|  |  |  |                                imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (type == INDEX_UNSIGNED) | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x2E6, Rt, Rn, imm, 32); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     EncodeLoadStoreIndexedInst(0x2E2, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rt); | 
					
						
							|  |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreUnscaled(0, 0, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDURB(ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreUnscaled(0, 1, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDURSB(ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreUnscaled(0, Is64Bit(Rt) ? 2 : 3, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STURH(ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreUnscaled(1, 0, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDURH(ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreUnscaled(1, 1, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDURSH(ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreUnscaled(1, Is64Bit(Rt) ? 2 : 3, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::STUR(ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreUnscaled(Is64Bit(Rt) ? 3 : 2, 0, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDUR(ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreUnscaled(Is64Bit(Rt) ? 3 : 2, 1, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::LDURSW(ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !Is64Bit(Rt), "%s must have a 64bit destination register!", __FUNCTION__); | 
					
						
							|  |  |  |   EncodeLoadStoreUnscaled(2, 2, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-15 14:23:09 -06:00
										 |  |  | // Address of label/page PC-relative
 | 
					
						
							|  |  |  | void ARM64XEmitter::ADR(ARM64Reg Rd, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeAddressInst(0, Rd, imm); | 
					
						
							| 
									
										
										
										
											2014-12-15 14:23:09 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64XEmitter::ADRP(ARM64Reg Rd, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeAddressInst(1, Rd, imm >> 12); | 
					
						
							| 
									
										
										
										
											2014-12-15 14:23:09 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   unsigned int parts = Is64Bit(Rd) ? 4 : 2; | 
					
						
							|  |  |  |   BitSet32 upload_part(0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Always start with a movz! Kills the dependency on the register.
 | 
					
						
							|  |  |  |   bool use_movz = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!imm) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Zero immediate, just clear the register. EOR is pointless when we have MOVZ, which looks
 | 
					
						
							|  |  |  |     // clearer in disasm too.
 | 
					
						
							|  |  |  |     MOVZ(Rd, 0, SHIFT_0); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ((Is64Bit(Rd) && imm == std::numeric_limits<u64>::max()) || | 
					
						
							|  |  |  |       (!Is64Bit(Rd) && imm == std::numeric_limits<u32>::max())) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Max unsigned value (or if signed, -1)
 | 
					
						
							|  |  |  |     // Set to ~ZR
 | 
					
						
							|  |  |  |     ARM64Reg ZR = Is64Bit(Rd) ? SP : WSP; | 
					
						
							|  |  |  |     ORN(Rd, ZR, ZR, ArithOption(ZR, ST_LSL, 0)); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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.
 | 
					
						
							|  |  |  |   // XXX: Optimize more
 | 
					
						
							|  |  |  |   // XXX: Support rotating immediates to save instructions
 | 
					
						
							|  |  |  |   if (optimize) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     for (unsigned int i = 0; i < parts; ++i) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if ((imm >> (i * 16)) & 0xFFFF) | 
					
						
							|  |  |  |         upload_part[i] = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   u64 aligned_pc = (u64)GetCodePtr() & ~0xFFF; | 
					
						
							|  |  |  |   s64 aligned_offset = (s64)imm - (s64)aligned_pc; | 
					
						
							|  |  |  |   if (upload_part.Count() > 1 && std::abs(aligned_offset) < 0xFFFFFFFFLL) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // 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; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (unsigned i = 0; i < parts; ++i) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (use_movz && upload_part[i]) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       MOVZ(Rd, (imm >> (i * 16)) & 0xFFFF, (ShiftAmount)i); | 
					
						
							|  |  |  |       use_movz = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (upload_part[i] || !optimize) | 
					
						
							|  |  |  |         MOVK(Rd, (imm >> (i * 16)) & 0xFFFF, (ShiftAmount)i); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-12-15 14:23:09 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 09:14:01 +02:00
										 |  |  | bool ARM64XEmitter::MOVI2R2(ARM64Reg Rd, u64 imm1, u64 imm2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // TODO: Also optimize for performance, not just for code size.
 | 
					
						
							|  |  |  |   u8* start_pointer = GetWritableCodePtr(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MOVI2R(Rd, imm1); | 
					
						
							|  |  |  |   int size1 = GetCodePtr() - start_pointer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SetCodePtrUnsafe(start_pointer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MOVI2R(Rd, imm2); | 
					
						
							|  |  |  |   int size2 = GetCodePtr() - start_pointer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SetCodePtrUnsafe(start_pointer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool element = size1 > size2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MOVI2R(Rd, element ? imm2 : imm1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return element; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-15 14:23:09 -06:00
										 |  |  | void ARM64XEmitter::ABI_PushRegisters(BitSet32 registers) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   int num_regs = registers.Count(); | 
					
						
							|  |  |  |   int stack_size = (num_regs + (num_regs & 1)) * 8; | 
					
						
							|  |  |  |   auto it = registers.begin(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   if (!num_regs) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   // 8 byte per register, but 16 byte alignment, so we may have to padd one register.
 | 
					
						
							|  |  |  |   // Only update the SP on the last write to avoid the dependency between those stores.
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   // The first push must adjust the SP, else a context switch may invalidate everything below SP.
 | 
					
						
							|  |  |  |   if (num_regs & 1) | 
					
						
							|  |  |  |     STR(INDEX_PRE, (ARM64Reg)(X0 + *it++), SP, -stack_size); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |     STP(INDEX_PRE, (ARM64Reg)(X0 + *it++), (ARM64Reg)(X0 + *it++), SP, -stack_size); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   // Fast store for all other registers, this is always an even number.
 | 
					
						
							|  |  |  |   for (int i = 0; i < (num_regs - 1) / 2; i++) | 
					
						
							|  |  |  |     STP(INDEX_SIGNED, (ARM64Reg)(X0 + *it++), (ARM64Reg)(X0 + *it++), SP, 16 * (i + 1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _assert_msg_(DYNA_REC, it == registers.end(), "%s registers don't match.", __FUNCTION__); | 
					
						
							| 
									
										
										
										
											2014-12-15 14:23:09 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int num_regs = registers.Count(); | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   int stack_size = (num_regs + (num_regs & 1)) * 8; | 
					
						
							|  |  |  |   auto it = registers.begin(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   if (!num_regs) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   // We must adjust the SP in the end, so load the first (two) registers at least.
 | 
					
						
							|  |  |  |   ARM64Reg first = (ARM64Reg)(X0 + *it++); | 
					
						
							|  |  |  |   ARM64Reg second; | 
					
						
							|  |  |  |   if (!(num_regs & 1)) | 
					
						
							|  |  |  |     second = (ARM64Reg)(X0 + *it++); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   // 8 byte per register, but 16 byte alignment, so we may have to padd one register.
 | 
					
						
							|  |  |  |   // Only update the SP on the last load to avoid the dependency between those loads.
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   // Fast load for all but the first (two) registers, this is always an even number.
 | 
					
						
							|  |  |  |   for (int i = 0; i < (num_regs - 1) / 2; i++) | 
					
						
							|  |  |  |     LDP(INDEX_SIGNED, (ARM64Reg)(X0 + *it++), (ARM64Reg)(X0 + *it++), SP, 16 * (i + 1)); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   // Post loading the first (two) registers.
 | 
					
						
							|  |  |  |   if (num_regs & 1) | 
					
						
							|  |  |  |     LDR(INDEX_POST, first, SP, stack_size); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     LDP(INDEX_POST, first, second, SP, stack_size); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-09 09:25:31 +01:00
										 |  |  |   _assert_msg_(DYNA_REC, it == registers.end(), "%s registers don't match.", __FUNCTION__); | 
					
						
							| 
									
										
										
										
											2014-02-05 01:56:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | // Float Emitter
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 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) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     _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()); | 
					
						
							|  |  |  |     _assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED) immediate offset must be positive!", | 
					
						
							|  |  |  |                  __FUNCTION__); | 
					
						
							|  |  |  |     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 | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), | 
					
						
							|  |  |  |                  "%s immediate offset must be within range of -256 to 256!", __FUNCTION__); | 
					
						
							|  |  |  |     encoded_imm = (imm & 0x1FF) << 2; | 
					
						
							|  |  |  |     if (type == INDEX_POST) | 
					
						
							|  |  |  |       encoded_imm |= 1; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       encoded_imm |= 3; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Write32((encoded_size << 30) | (0xF << 26) | (type == INDEX_UNSIGNED ? (1 << 24) : 0) | | 
					
						
							|  |  |  |           (size == 128 ? (1 << 23) : 0) | (opc << 22) | (encoded_imm << 10) | (Rn << 5) | Rt); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, | 
					
						
							|  |  |  |                                           ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s only supports double and single registers!", | 
					
						
							|  |  |  |                __FUNCTION__); | 
					
						
							|  |  |  |   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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); | 
					
						
							|  |  |  |   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); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((Q << 30) | (op << 29) | (0b111 << 25) | (imm5 << 16) | (imm4 << 11) | (1 << 10) | | 
					
						
							|  |  |  |           (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); | 
					
						
							|  |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((Q << 30) | (U << 29) | (0b1110001 << 21) | (size << 22) | (opcode << 12) | (1 << 11) | | 
					
						
							|  |  |  |           (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, | 
					
						
							|  |  |  |                                                      ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); | 
					
						
							|  |  |  |   bool quad = IsQuad(Rt); | 
					
						
							|  |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((quad << 30) | (0b1101 << 24) | (L << 22) | (R << 21) | (opcode << 13) | (S << 12) | | 
					
						
							|  |  |  |           (size << 10) | (Rn << 5) | Rt); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, | 
					
						
							|  |  |  |                                                      ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); | 
					
						
							|  |  |  |   bool quad = IsQuad(Rt); | 
					
						
							|  |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((quad << 30) | (0x1B << 23) | (L << 22) | (R << 21) | (Rm << 16) | (opcode << 13) | | 
					
						
							|  |  |  |           (S << 12) | (size << 10) | (Rn << 5) | Rt); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | void ARM64FloatEmitter::Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); | 
					
						
							|  |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Write32((M << 31) | (S << 29) | (0xF1 << 21) | (type << 22) | (opcode << 15) | (1 << 14) | | 
					
						
							|  |  |  |           (Rn << 5) | Rd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, | 
					
						
							|  |  |  |                                        ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   _assert_msg_(DYNA_REC, Rn <= SP, "%s only supports GPR as source!", __FUNCTION__); | 
					
						
							|  |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Write32((sf << 31) | (S << 29) | (0xF1 << 21) | (type << 22) | (rmode << 19) | (opcode << 16) | | 
					
						
							|  |  |  |           (Rn << 5) | Rd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::FCVTS(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitConvertScalarToInt(Rd, Rn, round, false); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::FCVTU(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitConvertScalarToInt(Rd, Rn, round, true); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, | 
					
						
							|  |  |  |                                         u32 opcode, int scale, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((sf << 31) | (S << 29) | (0xF0 << 21) | (direction << 21) | (type << 22) | (rmode << 19) | | 
					
						
							|  |  |  |           (opcode << 16) | (scale << 10) | (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | void ARM64FloatEmitter::EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !IsQuad(Rn), "%s doesn't support vector!", __FUNCTION__); | 
					
						
							|  |  |  |   bool is_double = IsDouble(Rn); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((M << 31) | (S << 29) | (0xF1 << 21) | (is_double << 22) | (Rm << 16) | (op << 14) | | 
					
						
							|  |  |  |           (1 << 13) | (Rn << 5) | opcode2); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, | 
					
						
							|  |  |  |                                        ARM64Reg Rm) | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); | 
					
						
							|  |  |  |   bool is_double = IsDouble(Rd); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool quad = IsQuad(Rd); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 encoded_size = 0; | 
					
						
							|  |  |  |   if (size == 16) | 
					
						
							|  |  |  |     encoded_size = 1; | 
					
						
							|  |  |  |   else if (size == 32) | 
					
						
							|  |  |  |     encoded_size = 2; | 
					
						
							|  |  |  |   else if (size == 64) | 
					
						
							|  |  |  |     encoded_size = 3; | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((quad << 30) | (7 << 25) | (encoded_size << 22) | (Rm << 16) | (op << 12) | (1 << 11) | | 
					
						
							|  |  |  |           (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool is_double = !IsSingle(Rd); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, immh, "%s bad encoding! Can't have zero immh", __FUNCTION__); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((Q << 30) | (U << 29) | (0xF << 24) | (immh << 19) | (immb << 16) | (opcode << 11) | | 
					
						
							|  |  |  |           (1 << 10) | (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitScalarShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, | 
					
						
							|  |  |  |                                            ARM64Reg Rn) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((2 << 30) | (U << 29) | (0x3E << 23) | (immh << 19) | (immb << 16) | (opcode << 11) | | 
					
						
							|  |  |  |           (1 << 10) | (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, | 
					
						
							|  |  |  |                                                        ARM64Reg Rn) | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool quad = IsQuad(Rt); | 
					
						
							|  |  |  |   u32 encoded_size = 0; | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (size == 16) | 
					
						
							|  |  |  |     encoded_size = 1; | 
					
						
							|  |  |  |   else if (size == 32) | 
					
						
							|  |  |  |     encoded_size = 2; | 
					
						
							|  |  |  |   else if (size == 64) | 
					
						
							|  |  |  |     encoded_size = 3; | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((quad << 30) | (3 << 26) | (L << 22) | (opcode << 12) | (encoded_size << 10) | (Rn << 5) | | 
					
						
							|  |  |  |           Rt); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, | 
					
						
							|  |  |  |                                                            ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							| 
									
										
										
										
											2015-02-28 04:39:15 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool quad = IsQuad(Rt); | 
					
						
							|  |  |  |   u32 encoded_size = 0; | 
					
						
							| 
									
										
										
										
											2015-02-28 04:39:15 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (size == 16) | 
					
						
							|  |  |  |     encoded_size = 1; | 
					
						
							|  |  |  |   else if (size == 32) | 
					
						
							|  |  |  |     encoded_size = 2; | 
					
						
							|  |  |  |   else if (size == 64) | 
					
						
							|  |  |  |     encoded_size = 3; | 
					
						
							| 
									
										
										
										
											2015-02-28 04:39:15 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rt = DecodeReg(Rt); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							| 
									
										
										
										
											2015-02-28 04:39:15 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((quad << 30) | (0b11001 << 23) | (L << 22) | (Rm << 16) | (opcode << 12) | | 
					
						
							|  |  |  |           (encoded_size << 10) | (Rn << 5) | Rt); | 
					
						
							| 
									
										
										
										
											2015-02-28 04:39:15 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, | 
					
						
							|  |  |  |                                           ARM64Reg Rn) | 
					
						
							| 
									
										
										
										
											2015-01-20 16:34:32 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); | 
					
						
							| 
									
										
										
										
											2015-01-20 16:34:32 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							| 
									
										
										
										
											2015-01-20 16:34:32 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((M << 31) | (S << 29) | (0xF1 << 21) | (type << 22) | (opcode << 15) | (1 << 14) | | 
					
						
							|  |  |  |           (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2015-01-20 16:34:32 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, | 
					
						
							|  |  |  |                                            ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool quad = IsQuad(Rd); | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Rd = DecodeReg(Rd); | 
					
						
							|  |  |  |   Rn = DecodeReg(Rn); | 
					
						
							|  |  |  |   Rm = DecodeReg(Rm); | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Write32((quad << 30) | (U << 29) | (0xF << 24) | (size << 22) | (L << 21) | (Rm << 16) | | 
					
						
							|  |  |  |           (opcode << 12) | (H << 11) | (Rn << 5) | Rd); | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | void ARM64FloatEmitter::EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _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) | (0xF << 26) | (op << 22) | ((imm & 0x1FF) << 12) | (Rn << 5) | Rt); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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-06-07 19:53:05 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-23 15:34:53 -05:00
										 |  |  | void ARM64FloatEmitter::EncodeModImm(bool Q, u8 op, u8 cmode, u8 o2, ARM64Reg Rd, u8 abcdefgh) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-01-04 12:45:40 +01:00
										 |  |  |   union | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     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-08-23 15:34:53 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | void ARM64FloatEmitter::LDR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitLoadStoreImmediate(size, 1, type, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::STR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitLoadStoreImmediate(size, 0, type, Rt, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | // Loadstore unscaled
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::LDUR(u8 size, ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2015-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::STUR(u8 size, ARM64Reg Rt, ARM64Reg Rn, s32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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-02-16 22:00:43 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool S = 0; | 
					
						
							|  |  |  |   u32 opcode = 0; | 
					
						
							|  |  |  |   u32 encoded_size = 0; | 
					
						
							|  |  |  |   ARM64Reg encoded_reg = INVALID_REG; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (size == 8) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 4) != 0; | 
					
						
							|  |  |  |     opcode = 0; | 
					
						
							|  |  |  |     encoded_size = index & 3; | 
					
						
							|  |  |  |     if (index & 8) | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToQuad(Rt); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToDouble(Rt); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (size == 16) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 2) != 0; | 
					
						
							|  |  |  |     opcode = 2; | 
					
						
							|  |  |  |     encoded_size = (index & 1) << 1; | 
					
						
							|  |  |  |     if (index & 4) | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToQuad(Rt); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToDouble(Rt); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (size == 32) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 1) != 0; | 
					
						
							|  |  |  |     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); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::LD1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool S = 0; | 
					
						
							|  |  |  |   u32 opcode = 0; | 
					
						
							|  |  |  |   u32 encoded_size = 0; | 
					
						
							|  |  |  |   ARM64Reg encoded_reg = INVALID_REG; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (size == 8) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 4) != 0; | 
					
						
							|  |  |  |     opcode = 0; | 
					
						
							|  |  |  |     encoded_size = index & 3; | 
					
						
							|  |  |  |     if (index & 8) | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToQuad(Rt); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToDouble(Rt); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (size == 16) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 2) != 0; | 
					
						
							|  |  |  |     opcode = 2; | 
					
						
							|  |  |  |     encoded_size = (index & 1) << 1; | 
					
						
							|  |  |  |     if (index & 4) | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToQuad(Rt); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToDouble(Rt); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (size == 32) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 1) != 0; | 
					
						
							|  |  |  |     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-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | void ARM64FloatEmitter::LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitLoadStoreSingleStructure(1, 1, 6, 0, size >> 4, Rt, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-09 17:42:15 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitLoadStoreSingleStructure(1, 0, 6, 0, size >> 4, Rt, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-09 17:42:15 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::LD2R(u8 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitLoadStoreSingleStructure(1, 1, 6, 0, size >> 4, Rt, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-09 17:42:15 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool S = 0; | 
					
						
							|  |  |  |   u32 opcode = 0; | 
					
						
							|  |  |  |   u32 encoded_size = 0; | 
					
						
							|  |  |  |   ARM64Reg encoded_reg = INVALID_REG; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (size == 8) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 4) != 0; | 
					
						
							|  |  |  |     opcode = 0; | 
					
						
							|  |  |  |     encoded_size = index & 3; | 
					
						
							|  |  |  |     if (index & 8) | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToQuad(Rt); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToDouble(Rt); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (size == 16) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 2) != 0; | 
					
						
							|  |  |  |     opcode = 2; | 
					
						
							|  |  |  |     encoded_size = (index & 1) << 1; | 
					
						
							|  |  |  |     if (index & 4) | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToQuad(Rt); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToDouble(Rt); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (size == 32) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 1) != 0; | 
					
						
							|  |  |  |     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); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool S = 0; | 
					
						
							|  |  |  |   u32 opcode = 0; | 
					
						
							|  |  |  |   u32 encoded_size = 0; | 
					
						
							|  |  |  |   ARM64Reg encoded_reg = INVALID_REG; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (size == 8) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 4) != 0; | 
					
						
							|  |  |  |     opcode = 0; | 
					
						
							|  |  |  |     encoded_size = index & 3; | 
					
						
							|  |  |  |     if (index & 8) | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToQuad(Rt); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToDouble(Rt); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (size == 16) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 2) != 0; | 
					
						
							|  |  |  |     opcode = 2; | 
					
						
							|  |  |  |     encoded_size = (index & 1) << 1; | 
					
						
							|  |  |  |     if (index & 4) | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToQuad(Rt); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       encoded_reg = EncodeRegToDouble(Rt); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (size == 32) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     S = (index & 1) != 0; | 
					
						
							|  |  |  |     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); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Loadstore multiple structure
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::LD1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _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, 1, opcode, Rt, Rn); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 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-28 04:39:15 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | void ARM64FloatEmitter::ST1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 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-28 04:39:15 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-02 03:41:19 -06:00
										 |  |  | // Loadstore paired
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::LDP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, | 
					
						
							|  |  |  |                             s32 imm) | 
					
						
							| 
									
										
										
										
											2015-03-02 03:41:19 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStorePair(size, true, type, Rt, Rt2, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-03-02 03:41:19 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::STP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, | 
					
						
							|  |  |  |                             s32 imm) | 
					
						
							| 
									
										
										
										
											2015-03-02 03:41:19 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStorePair(size, false, type, Rt, Rt2, Rn, imm); | 
					
						
							| 
									
										
										
										
											2015-03-02 03:41:19 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-07 19:53:05 -05:00
										 |  |  | // Loadstore register offset
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::STR(u8 size, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreRegisterOffset(size, false, Rt, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 19:53:05 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::LDR(u8 size, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EncodeLoadStoreRegisterOffset(size, true, Rt, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 19:53:05 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-20 16:34:32 -06:00
										 |  |  | void ARM64FloatEmitter::FABS(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar1Source(0, 0, IsDouble(Rd), 1, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-01-20 16:34:32 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FNEG(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar1Source(0, 0, IsDouble(Rd), 2, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FSQRT(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar1Source(0, 0, IsDouble(Rd), 3, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-01-20 16:34:32 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar2Source(0, 0, IsDouble(Rd), 3, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar2Source(0, 0, IsDouble(Rd), 1, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FMAX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar2Source(0, 0, IsDouble(Rd), 4, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FMIN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar2Source(0, 0, IsDouble(Rd), 5, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FMAXNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar2Source(0, 0, IsDouble(Rd), 6, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FMINNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar2Source(0, 0, IsDouble(Rd), 7, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FNMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar2Source(0, 0, IsDouble(Rd), 8, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::FMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 0); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 1); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FNMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 2); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FNMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 3); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void ARM64FloatEmitter::EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, | 
					
						
							|  |  |  |                                           ARM64Reg Ra, int opcode) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   EmitCopy(IsQuad(Rd), 0, imm5, 0, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FABS(u8 size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitThreeSame(0, size >> 6, 0x1A, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-09 17:42:15 -05:00
										 |  |  | void ARM64FloatEmitter::FMAX(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitThreeSame(0, size >> 6, 0b11110, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-09 17:42:15 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | void ARM64FloatEmitter::FMLA(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Emit2RegMisc(false, 0, size >> 6, 0x17, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FCVTL2(u8 size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitThreeSame(0, 2 | (size >> 6), 0x1A, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FMLS(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitThreeSame(0, 2 | (size >> 6), 0x19, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::NOT(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int imm = size * 2 - scale; | 
					
						
							|  |  |  |   EmitShiftImm(IsQuad(Rd), 0, imm >> 3, imm & 7, 0x1C, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int imm = size * 2 - scale; | 
					
						
							|  |  |  |   EmitShiftImm(IsQuad(Rd), 1, imm >> 3, imm & 7, 0x1C, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-13 23:16:17 -05:00
										 |  |  | void ARM64FloatEmitter::SQXTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Emit2RegMisc(false, 0, dest_size >> 4, 0b10100, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-13 23:16:17 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::SQXTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Emit2RegMisc(true, 0, dest_size >> 4, 0b10100, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-13 23:16:17 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::UQXTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Emit2RegMisc(false, 1, dest_size >> 4, 0b10100, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-13 23:16:17 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::UQXTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Emit2RegMisc(true, 1, dest_size >> 4, 0b10100, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-13 23:16:17 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | void ARM64FloatEmitter::XTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Emit2RegMisc(false, 0, dest_size >> 4, 0b10010, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-06-13 23:16:17 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::XTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 imm5 = 0; | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (size == 8) | 
					
						
							|  |  |  |     imm5 = 1; | 
					
						
							|  |  |  |   else if (size == 16) | 
					
						
							|  |  |  |     imm5 = 2; | 
					
						
							|  |  |  |   else if (size == 32) | 
					
						
							|  |  |  |     imm5 = 4; | 
					
						
							|  |  |  |   else if (size == 64) | 
					
						
							|  |  |  |     imm5 = 8; | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | void ARM64FloatEmitter::UMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							|  |  |  |   _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__); | 
					
						
							|  |  |  |   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(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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool b64Bit = Is64Bit(Rd); | 
					
						
							|  |  |  |   _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__); | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 dst_encoding = 0; | 
					
						
							|  |  |  |   u32 src_encoding = 0; | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (size_to == 16) | 
					
						
							|  |  |  |     dst_encoding = 3; | 
					
						
							|  |  |  |   else if (size_to == 32) | 
					
						
							|  |  |  |     dst_encoding = 0; | 
					
						
							|  |  |  |   else if (size_to == 64) | 
					
						
							|  |  |  |     dst_encoding = 1; | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (size_from == 16) | 
					
						
							|  |  |  |     src_encoding = 3; | 
					
						
							|  |  |  |   else if (size_from == 32) | 
					
						
							|  |  |  |     src_encoding = 0; | 
					
						
							|  |  |  |   else if (size_from == 64) | 
					
						
							|  |  |  |     src_encoding = 1; | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Emit1Source(0, 0, src_encoding, 4 | dst_encoding, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | void ARM64FloatEmitter::SCVTF(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::UCVTF(ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | void ARM64FloatEmitter::SCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale) | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool sf = Is64Bit(Rn); | 
					
						
							|  |  |  |   u32 type = 0; | 
					
						
							|  |  |  |   if (IsDouble(Rd)) | 
					
						
							|  |  |  |     type = 1; | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitConversion2(sf, 0, false, type, 0, 2, 64 - scale, Rd, Rn); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | void ARM64FloatEmitter::UCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale) | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool sf = Is64Bit(Rn); | 
					
						
							|  |  |  |   u32 type = 0; | 
					
						
							|  |  |  |   if (IsDouble(Rd)) | 
					
						
							|  |  |  |     type = 1; | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitCompare(0, 0, 0, 0, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FCMP(ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitCompare(0, 0, 0, 8, Rn, (ARM64Reg)0); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FCMPE(ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitCompare(0, 0, 0, 0x10, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::FCMPE(ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitCondSelect(0, 0, cond, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Permute
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::UZP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitPermute(size, 0b001, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::TRN1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitPermute(size, 0b010, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::ZIP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitPermute(size, 0b011, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::UZP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitPermute(size, 0b101, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::TRN2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitPermute(size, 0b110, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::ZIP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitPermute(size, 0b111, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SSHLL(src_size, Rd, Rn, shift, false); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::SSHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SSHLL(src_size, Rd, Rn, shift, true); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SHRN(dest_size, Rd, Rn, shift, false); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::SHRN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SHRN(dest_size, Rd, Rn, shift, true); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   USHLL(src_size, Rd, Rn, shift, false); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::USHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   USHLL(src_size, Rd, Rn, shift, true); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::SXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SXTL(src_size, Rd, Rn, false); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::SXTL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SXTL(src_size, Rd, Rn, true); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   UXTL(src_size, Rd, Rn, false); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | void ARM64FloatEmitter::UXTL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   UXTL(src_size, Rd, Rn, true); | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _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, 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) | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _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); | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | void ARM64FloatEmitter::SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper) | 
					
						
							| 
									
										
										
										
											2015-01-18 16:25:40 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, shift < dest_size, "%s shift amount must less than the element size!", | 
					
						
							|  |  |  |                __FUNCTION__); | 
					
						
							|  |  |  |   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); | 
					
						
							|  |  |  |     ; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", | 
					
						
							|  |  |  |                __FUNCTION__); | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EmitVectorxElement(0, 2 | (size >> 6), L, 0x9, H, Rd, Rn, Rm); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::FMLA(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _assert_msg_(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", | 
					
						
							|  |  |  |                __FUNCTION__); | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool L = false; | 
					
						
							|  |  |  |   bool H = false; | 
					
						
							|  |  |  |   if (size == 32) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     L = index & 1; | 
					
						
							|  |  |  |     H = (index >> 1) & 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (size == 64) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     H = index == 1; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-02-12 18:47:06 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2015-08-23 15:34:53 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::BIC(u8 size, ARM64Reg Rd, u8 imm, u8 shift) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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-08-23 15:34:53 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-02 11:21:15 -06:00
										 |  |  | void ARM64FloatEmitter::ABI_PushRegisters(BitSet32 registers, ARM64Reg tmp) | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool bundled_loadstore = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (bundled_loadstore && tmp != INVALID_REG) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int num_regs = registers.Count(); | 
					
						
							|  |  |  |     m_emit->SUB(SP, SP, num_regs * 16); | 
					
						
							|  |  |  |     m_emit->ADD(tmp, SP, 0); | 
					
						
							|  |  |  |     std::vector<ARM64Reg> island_regs; | 
					
						
							|  |  |  |     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]) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (count == 1) | 
					
						
							|  |  |  |         island_regs.push_back((ARM64Reg)(Q0 + i)); | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         ST1(64, count, INDEX_POST, (ARM64Reg)(Q0 + i), tmp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       i += count - 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 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); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     std::vector<ARM64Reg> pair_regs; | 
					
						
							|  |  |  |     for (auto it : registers) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       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-01-07 13:42:36 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-02 11:21:15 -06:00
										 |  |  | void ARM64FloatEmitter::ABI_PopRegisters(BitSet32 registers, ARM64Reg tmp) | 
					
						
							| 
									
										
										
										
											2015-01-07 13:42:36 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool bundled_loadstore = false; | 
					
						
							|  |  |  |   int num_regs = registers.Count(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (bundled_loadstore && tmp != INVALID_REG) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // The temporary register is only used to indicate that we can use this code path
 | 
					
						
							|  |  |  |     std::vector<ARM64Reg> island_regs; | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  |         island_regs.push_back((ARM64Reg)(Q0 + i)); | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         LD1(64, count, INDEX_POST, (ARM64Reg)(Q0 + i), SP); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       i += count - 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 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); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     bool odd = num_regs % 2; | 
					
						
							|  |  |  |     std::vector<ARM64Reg> pair_regs; | 
					
						
							|  |  |  |     for (int i = 31; i >= 0; --i) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (!registers[i]) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       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-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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::ORRI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::EORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::ANDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  | void ARM64XEmitter::ADDI2R_internal(ARM64Reg Rd, ARM64Reg Rn, u64 imm, bool negative, bool flags, | 
					
						
							|  |  |  |                                     ARM64Reg scratch) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   auto addi = [this](ARM64Reg Rd, ARM64Reg Rn, u64 imm, bool shift, bool negative, bool flags) { | 
					
						
							|  |  |  |     switch ((negative << 1) | flags) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |       ADD(Rd, Rn, imm, shift); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 1: | 
					
						
							|  |  |  |       ADDS(Rd, Rn, imm, shift); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 2: | 
					
						
							|  |  |  |       SUB(Rd, Rn, imm, shift); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 3: | 
					
						
							|  |  |  |       SUBS(Rd, Rn, imm, shift); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool has_scratch = scratch != INVALID_REG; | 
					
						
							| 
									
										
										
										
											2016-10-26 21:17:29 +02:00
										 |  |  |   u64 imm_neg = Is64Bit(Rd) ? -imm : -imm & 0xFFFFFFFFuLL; | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   bool neg_neg = negative ? false : true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Fast paths, aarch64 immediate instructions
 | 
					
						
							|  |  |  |   // Try them all first
 | 
					
						
							|  |  |  |   if (imm <= 0xFFF) | 
					
						
							| 
									
										
										
										
											2016-10-26 21:17:29 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |     addi(Rd, Rn, imm, false, negative, flags); | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2016-10-26 21:17:29 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   if (imm <= 0xFFFFFF && (imm & 0xFFF) == 0) | 
					
						
							| 
									
										
										
										
											2016-10-27 09:14:01 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |     addi(Rd, Rn, imm >> 12, true, negative, flags); | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2016-10-27 09:14:01 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   if (imm_neg <= 0xFFF) | 
					
						
							| 
									
										
										
										
											2016-10-27 09:14:01 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |     addi(Rd, Rn, imm_neg, false, neg_neg, flags); | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2016-10-27 09:14:01 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   if (imm_neg <= 0xFFFFFF && (imm_neg & 0xFFF) == 0) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |     addi(Rd, Rn, imm_neg >> 12, true, neg_neg, flags); | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   // ADD+ADD is slower than MOVK+ADD, but inplace.
 | 
					
						
							|  |  |  |   // But it supports a few more bits, so use it to avoid MOVK+MOVK+ADD.
 | 
					
						
							|  |  |  |   // As this splits the addition in two parts, this must not be done on setting flags.
 | 
					
						
							|  |  |  |   if (!flags && (imm >= 0x10000u || !has_scratch) && imm < 0x1000000u) | 
					
						
							| 
									
										
										
										
											2016-10-26 20:47:03 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |     addi(Rd, Rn, imm & 0xFFF, false, negative, false); | 
					
						
							|  |  |  |     addi(Rd, Rd, imm >> 12, true, negative, false); | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:47:03 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   if (!flags && (imm_neg >= 0x10000u || !has_scratch) && imm_neg < 0x1000000u) | 
					
						
							| 
									
										
										
										
											2016-10-26 21:17:29 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |     addi(Rd, Rn, imm_neg & 0xFFF, false, neg_neg, false); | 
					
						
							|  |  |  |     addi(Rd, Rd, imm_neg >> 12, true, neg_neg, false); | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2016-10-26 21:17:29 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   _assert_msg_(DYNA_REC, has_scratch, | 
					
						
							|  |  |  |                "ADDI2R - failed to construct arithmetic immediate value from %08x, need scratch", | 
					
						
							|  |  |  |                (u32)imm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   negative ^= MOVI2R2(scratch, imm, imm_neg); | 
					
						
							|  |  |  |   switch ((negative << 1) | flags) | 
					
						
							| 
									
										
										
										
											2016-10-26 20:47:03 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   case 0: | 
					
						
							|  |  |  |     ADD(Rd, Rn, scratch); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case 1: | 
					
						
							|  |  |  |     ADDS(Rd, Rn, scratch); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case 2: | 
					
						
							|  |  |  |     SUB(Rd, Rn, scratch); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case 3: | 
					
						
							|  |  |  |     SUBS(Rd, Rn, scratch); | 
					
						
							|  |  |  |     break; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:47:03 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  | void ARM64XEmitter::ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   ADDI2R_internal(Rd, Rn, imm, false, false, scratch); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64XEmitter::ADDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   ADDI2R_internal(Rd, Rn, imm, false, true, scratch); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | void ARM64XEmitter::SUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   ADDI2R_internal(Rd, Rn, imm, true, false, scratch); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:47:03 +02:00
										 |  |  | void ARM64XEmitter::SUBSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   ADDI2R_internal(Rd, Rn, imm, true, true, scratch); | 
					
						
							| 
									
										
										
										
											2016-10-26 20:47:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | void ARM64XEmitter::CMPI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-27 18:11:51 +02:00
										 |  |  |   ADDI2R_internal(Is64Bit(Rn) ? ZR : WZR, Rn, imm, true, true, scratch); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ARM64XEmitter::TryADDI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 val; | 
					
						
							|  |  |  |   bool shift; | 
					
						
							|  |  |  |   if (IsImmArithmetic(imm, &val, &shift)) | 
					
						
							|  |  |  |     ADD(Rd, Rn, val, shift); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ARM64XEmitter::TrySUBI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 val; | 
					
						
							|  |  |  |   bool shift; | 
					
						
							|  |  |  |   if (IsImmArithmetic(imm, &val, &shift)) | 
					
						
							|  |  |  |     SUB(Rd, Rn, val, shift); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ARM64XEmitter::TryCMPI2R(ARM64Reg Rn, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   u32 val; | 
					
						
							|  |  |  |   bool shift; | 
					
						
							|  |  |  |   if (IsImmArithmetic(imm, &val, &shift)) | 
					
						
							|  |  |  |     CMP(Rn, val, shift); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ARM64XEmitter::TryANDI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | bool ARM64XEmitter::TryORRI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | bool ARM64XEmitter::TryEORI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float FPImm8ToFloat(uint8_t bits) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:16:51 +01:00
										 |  |  | bool FPImm8FromFloat(float value, uint8_t* immOut) | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   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; | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::MOVI2F(ARM64Reg Rd, float value, ARM64Reg scratch, bool negate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   _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); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TODO: Quite a few values could be generated easily using the MOVI instruction and friends.
 | 
					
						
							|  |  |  | void ARM64FloatEmitter::MOVI2FDUP(ARM64Reg Rd, float value, ARM64Reg scratch) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // 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); | 
					
						
							| 
									
										
										
										
											2015-06-07 16:57:57 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace
 |