Adding test case for text-decoration property state change on applying different...
[WebKit-https.git] / Source / JavaScriptCore / assembler / ARM64Assembler.h
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef ARM64Assembler_h
27 #define ARM64Assembler_h
28
29 #if ENABLE(ASSEMBLER) && CPU(ARM64)
30
31 #include "AssemblerBuffer.h"
32 #include <wtf/Assertions.h>
33 #include <wtf/Vector.h>
34 #include <stdint.h>
35
36 #define CHECK_DATASIZE_OF(datasize) ASSERT(datasize == 32 || datasize == 64)
37 #define DATASIZE_OF(datasize) ((datasize == 64) ? Datasize_64 : Datasize_32)
38 #define MEMOPSIZE_OF(datasize) ((datasize == 8 || datasize == 128) ? MemOpSize_8_or_128 : (datasize == 16) ? MemOpSize_16 : (datasize == 32) ? MemOpSize_32 : MemOpSize_64)
39 #define CHECK_DATASIZE() CHECK_DATASIZE_OF(datasize)
40 #define DATASIZE DATASIZE_OF(datasize)
41 #define MEMOPSIZE MEMOPSIZE_OF(datasize)
42 #define CHECK_FP_MEMOP_DATASIZE() ASSERT(datasize == 8 || datasize == 16 || datasize == 32 || datasize == 64 || datasize == 128)
43
44 namespace JSC {
45
46 ALWAYS_INLINE bool isInt9(int32_t value)
47 {
48     return value == ((value << 23) >> 23);
49 }
50
51 ALWAYS_INLINE bool isUInt5(int32_t value)
52 {
53     return !(value & ~0x1f);
54 }
55
56 ALWAYS_INLINE bool isUInt12(int32_t value)
57 {
58     return !(value & ~0xfff);
59 }
60
61 ALWAYS_INLINE bool isUInt12(intptr_t value)
62 {
63     return !(value & ~0xfffL);
64 }
65
66 class UInt5 {
67 public:
68     explicit UInt5(int value)
69         : m_value(value)
70     {
71         ASSERT(isUInt5(value));
72     }
73
74     operator int() { return m_value; }
75
76 private:
77     int m_value;
78 };
79
80 class UInt12 {
81 public:
82     explicit UInt12(int value)
83         : m_value(value)
84     {
85         ASSERT(isUInt12(value));
86     }
87
88     operator int() { return m_value; }
89
90 private:
91     int m_value;
92 };
93
94 class PostIndex {
95 public:
96     explicit PostIndex(int value)
97         : m_value(value)
98     {
99         ASSERT(isInt9(value));
100     }
101
102     operator int() { return m_value; }
103
104 private:
105     int m_value;
106 };
107
108 class PreIndex {
109 public:
110     explicit PreIndex(int value)
111         : m_value(value)
112     {
113         ASSERT(isInt9(value));
114     }
115
116     operator int() { return m_value; }
117
118 private:
119     int m_value;
120 };
121
122 class LogicalImmediate {
123 public:
124     static LogicalImmediate create32(uint32_t value)
125     {
126         // Check for 0, -1 - these cannot be encoded.
127         if (!value || !~value)
128             return InvalidLogicalImmediate;
129
130         // First look for a 32-bit pattern, then for repeating 16-bit
131         // patterns, 8-bit, 4-bit, and finally 2-bit.
132
133         unsigned hsb, lsb;
134         bool inverted;
135         if (findBitRange<32>(value, hsb, lsb, inverted))
136             return encodeLogicalImmediate<32>(hsb, lsb, inverted);
137
138         if ((value & 0xffff) != (value >> 16))
139             return InvalidLogicalImmediate;
140         value &= 0xffff;
141
142         if (findBitRange<16>(value, hsb, lsb, inverted))
143             return encodeLogicalImmediate<16>(hsb, lsb, inverted);
144
145         if ((value & 0xff) != (value >> 8))
146             return InvalidLogicalImmediate;
147         value &= 0xff;
148
149         if (findBitRange<8>(value, hsb, lsb, inverted))
150             return encodeLogicalImmediate<8>(hsb, lsb, inverted);
151
152         if ((value & 0xf) != (value >> 4))
153             return InvalidLogicalImmediate;
154         value &= 0xf;
155
156         if (findBitRange<4>(value, hsb, lsb, inverted))
157             return encodeLogicalImmediate<4>(hsb, lsb, inverted);
158
159         if ((value & 0x3) != (value >> 2))
160             return InvalidLogicalImmediate;
161         value &= 0x3;
162
163         if (findBitRange<2>(value, hsb, lsb, inverted))
164             return encodeLogicalImmediate<2>(hsb, lsb, inverted);
165
166         return InvalidLogicalImmediate;
167     }
168
169     static LogicalImmediate create64(uint64_t value)
170     {
171         // Check for 0, -1 - these cannot be encoded.
172         if (!value || !~value)
173             return InvalidLogicalImmediate;
174
175         // Look for a contiguous bit range.
176         unsigned hsb, lsb;
177         bool inverted;
178         if (findBitRange<64>(value, hsb, lsb, inverted))
179             return encodeLogicalImmediate<64>(hsb, lsb, inverted);
180
181         // If the high & low 32 bits are equal, we can try for a 32-bit (or narrower) pattern.
182         if (static_cast<uint32_t>(value) == static_cast<uint32_t>(value >> 32))
183             return create32(static_cast<uint32_t>(value));
184         return InvalidLogicalImmediate;
185     }
186
187     int value() const
188     {
189         ASSERT(isValid());
190         return m_value;
191     }
192
193     bool isValid() const
194     {
195         return m_value != InvalidLogicalImmediate;
196     }
197
198     bool is64bit() const
199     {
200         return m_value & (1 << 12);
201     }
202
203 private:
204     LogicalImmediate(int value)
205         : m_value(value)
206     {
207     }
208
209     // Generate a mask with bits in the range hsb..0 set, for example:
210     //   hsb:63 = 0xffffffffffffffff
211     //   hsb:42 = 0x000007ffffffffff
212     //   hsb: 0 = 0x0000000000000001
213     static uint64_t mask(unsigned hsb)
214     {
215         ASSERT(hsb < 64);
216         return 0xffffffffffffffffull >> (63 - hsb);
217     }
218
219     template<unsigned N>
220     static void partialHSB(uint64_t& value, unsigned&result)
221     {
222         if (value & (0xffffffffffffffffull << N)) {
223             result += N;
224             value >>= N;
225         }
226     }
227
228     // Find the bit number of the highest bit set in a non-zero value, for example:
229     //   0x8080808080808080 = hsb:63
230     //   0x0000000000000001 = hsb: 0
231     //   0x000007ffffe00000 = hsb:42
232     static unsigned highestSetBit(uint64_t value)
233     {
234         ASSERT(value);
235         unsigned hsb = 0;
236         partialHSB<32>(value, hsb);
237         partialHSB<16>(value, hsb);
238         partialHSB<8>(value, hsb);
239         partialHSB<4>(value, hsb);
240         partialHSB<2>(value, hsb);
241         partialHSB<1>(value, hsb);
242         return hsb;
243     }
244
245     // This function takes a value and a bit width, where value obeys the following constraints:
246     //   * bits outside of the width of the value must be zero.
247     //   * bits within the width of value must neither be all clear or all set.
248     // The input is inspected to detect values that consist of either two or three contiguous
249     // ranges of bits. The output range hsb..lsb will describe the second range of the value.
250     // if the range is set, inverted will be false, and if the range is clear, inverted will
251     // be true. For example (with width 8):
252     //   00001111 = hsb:3, lsb:0, inverted:false
253     //   11110000 = hsb:3, lsb:0, inverted:true
254     //   00111100 = hsb:5, lsb:2, inverted:false
255     //   11000011 = hsb:5, lsb:2, inverted:true
256     template<unsigned width>
257     static bool findBitRange(uint64_t value, unsigned& hsb, unsigned& lsb, bool& inverted)
258     {
259         ASSERT(value & mask(width - 1));
260         ASSERT(value != mask(width - 1));
261         ASSERT(!(value & ~mask(width - 1)));
262
263         // Detect cases where the top bit is set; if so, flip all the bits & set invert.
264         // This halves the number of patterns we need to look for.
265         const uint64_t msb = 1ull << (width - 1);
266         if ((inverted = (value & msb)))
267             value ^= mask(width - 1);
268
269         // Find the highest set bit in value, generate a corresponding mask & flip all
270         // bits under it.
271         hsb = highestSetBit(value);
272         value ^= mask(hsb);
273         if (!value) {
274             // If this cleared the value, then the range hsb..0 was all set.
275             lsb = 0;
276             return true;
277         }
278
279         // Try making one more mask, and flipping the bits!
280         lsb = highestSetBit(value);
281         value ^= mask(lsb);
282         if (!value) {
283             // Success - but lsb actually points to the hsb of a third range - add one
284             // to get to the lsb of the mid range.
285             ++lsb;
286             return true;
287         }
288
289         return false;
290     }
291
292     // Encodes the set of immN:immr:imms fields found in a logical immediate.
293     template<unsigned width>
294     static int encodeLogicalImmediate(unsigned hsb, unsigned lsb, bool inverted)
295     {
296         // Check width is a power of 2!
297         ASSERT(!(width & (width -1)));
298         ASSERT(width <= 64 && width >= 2);
299         ASSERT(hsb >= lsb);
300         ASSERT(hsb < width);
301
302         int immN = 0;
303         int imms = 0;
304         int immr = 0;
305
306         // For 64-bit values this is easy - just set immN to true, and imms just
307         // contains the bit number of the highest set bit of the set range. For
308         // values with narrower widths, these are encoded by a leading set of
309         // one bits, followed by a zero bit, followed by the remaining set of bits
310         // being the high bit of the range. For a 32-bit immediate there are no
311         // leading one bits, just a zero followed by a five bit number. For a
312         // 16-bit immediate there is one one bit, a zero bit, and then a four bit
313         // bit-position, etc.
314         if (width == 64)
315             immN = 1;
316         else
317             imms = 63 & ~(width + width - 1);
318
319         if (inverted) {
320             // if width is 64 & hsb is 62, then we have a value something like:
321             //   0x80000000ffffffff (in this case with lsb 32).
322             // The ror should be by 1, imms (effectively set width minus 1) is
323             // 32. Set width is full width minus cleared width.
324             immr = (width - 1) - hsb;
325             imms |= (width - ((hsb - lsb) + 1)) - 1;
326         } else {
327             // if width is 64 & hsb is 62, then we have a value something like:
328             //   0x7fffffff00000000 (in this case with lsb 32).
329             // The value is effectively rol'ed by lsb, which is equivalent to
330             // a ror by width - lsb (or 0, in the case where lsb is 0). imms
331             // is hsb - lsb.
332             immr = (width - lsb) & (width - 1);
333             imms |= hsb - lsb;
334         }
335
336         return immN << 12 | immr << 6 | imms;
337     }
338
339     static const int InvalidLogicalImmediate = -1;
340
341     int m_value;
342 };
343
344 inline uint16_t getHalfword(uint64_t value, int which)
345 {
346     return value >> (which << 4);
347 }
348
349 namespace ARM64Registers {
350     typedef enum {
351         // ´┐╝Parameter/result registers
352         x0,
353         x1,
354         x2,
355         x3,
356         x4,
357         x5,
358         x6,
359         x7,
360         // Indirect result location register
361         x8,
362         // Temporary registers
363         x9,
364         x10,
365         x11,
366         x12,
367         x13,
368         x14,
369         x15,
370         // Intra-procedure-call scratch registers (temporary)
371         x16, ip0 = x16,
372         x17, ip1 = x17,
373         // Platform Register (temporary)
374         x18,
375         // Callee-saved
376         x19,
377         x20,
378         x21,
379         x22,
380         x23,
381         x24,
382         x25,
383         x26,
384         x27,
385         x28,
386         // Special
387         x29, fp = x29,
388         x30, lr = x30,
389         sp,
390         zr = 0x3f,
391     } RegisterID;
392
393     typedef enum {
394         // Parameter/result registers
395         q0,
396         q1,
397         q2,
398         q3,
399         q4,
400         q5,
401         q6,
402         q7,
403         // Callee-saved (up to 64-bits only!)
404         q8,
405         q9,
406         q10,
407         q11,
408         q12,
409         q13,
410         q14,
411         q15,
412         // Temporary registers
413         q16,
414         q17,
415         q18,
416         q19,
417         q20,
418         q21,
419         q22,
420         q23,
421         q24,
422         q25,
423         q26,
424         q27,
425         q28,
426         q29,
427         q30,
428         q31,
429     } FPRegisterID;
430
431     static bool isSp(RegisterID reg) { return reg == sp; }
432     static bool isZr(RegisterID reg) { return reg == zr; }
433 }
434
435 class ARM64Assembler {
436 public:
437     typedef ARM64Registers::RegisterID RegisterID;
438     typedef ARM64Registers::FPRegisterID FPRegisterID;
439     
440     static RegisterID firstRegister() { return ARM64Registers::x0; }
441     static RegisterID lastRegister() { return ARM64Registers::x28; }
442     
443     static FPRegisterID firstFPRegister() { return ARM64Registers::q0; }
444     static FPRegisterID lastFPRegister() { return ARM64Registers::q31; }
445
446 private:
447     static bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); }
448     static bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); }
449
450 public:
451     ARM64Assembler()
452         : m_indexOfLastWatchpoint(INT_MIN)
453         , m_indexOfTailOfLastWatchpoint(INT_MIN)
454     {
455     }
456
457     // (HS, LO, HI, LS) -> (AE, B, A, BE)
458     // (VS, VC) -> (O, NO)
459     typedef enum {
460         ConditionEQ,
461         ConditionNE,
462         ConditionHS, ConditionCS = ConditionHS,
463         ConditionLO, ConditionCC = ConditionLO,
464         ConditionMI,
465         ConditionPL,
466         ConditionVS,
467         ConditionVC,
468         ConditionHI,
469         ConditionLS,
470         ConditionGE,
471         ConditionLT,
472         ConditionGT,
473         ConditionLE,
474         ConditionAL,
475         ConditionInvalid
476     } Condition;
477
478     static Condition invert(Condition cond)
479     {
480         return static_cast<Condition>(cond ^ 1);
481     }
482
483     typedef enum {
484         LSL,
485         LSR,
486         ASR,
487         ROR
488     } ShiftType;
489
490     typedef enum {
491         UXTB,
492         UXTH,
493         UXTW,
494         UXTX,
495         SXTB,
496         SXTH,
497         SXTW,
498         SXTX
499     } ExtendType;
500
501     enum SetFlags {
502         DontSetFlags,
503         S
504     };
505
506 #define JUMP_ENUM_WITH_SIZE(index, value) (((value) << 4) | (index))
507 #define JUMP_ENUM_SIZE(jump) ((jump) >> 4)
508     enum JumpType { JumpFixed = JUMP_ENUM_WITH_SIZE(0, 0),
509         JumpNoCondition = JUMP_ENUM_WITH_SIZE(1, 1 * sizeof(uint32_t)),
510         JumpCondition = JUMP_ENUM_WITH_SIZE(2, 2 * sizeof(uint32_t)),
511         JumpCompareAndBranch = JUMP_ENUM_WITH_SIZE(3, 2 * sizeof(uint32_t)),
512         JumpTestBit = JUMP_ENUM_WITH_SIZE(4, 2 * sizeof(uint32_t)),
513         JumpNoConditionFixedSize = JUMP_ENUM_WITH_SIZE(5, 1 * sizeof(uint32_t)),
514         JumpConditionFixedSize = JUMP_ENUM_WITH_SIZE(6, 2 * sizeof(uint32_t)),
515         JumpCompareAndBranchFixedSize = JUMP_ENUM_WITH_SIZE(7, 2 * sizeof(uint32_t)),
516         JumpTestBitFixedSize = JUMP_ENUM_WITH_SIZE(8, 2 * sizeof(uint32_t)),
517     };
518     enum JumpLinkType {
519         LinkInvalid = JUMP_ENUM_WITH_SIZE(0, 0),
520         LinkJumpNoCondition = JUMP_ENUM_WITH_SIZE(1, 1 * sizeof(uint32_t)),
521         LinkJumpConditionDirect = JUMP_ENUM_WITH_SIZE(2, 1 * sizeof(uint32_t)),
522         LinkJumpCondition = JUMP_ENUM_WITH_SIZE(3, 2 * sizeof(uint32_t)),
523         LinkJumpCompareAndBranch = JUMP_ENUM_WITH_SIZE(4, 2 * sizeof(uint32_t)),
524         LinkJumpCompareAndBranchDirect = JUMP_ENUM_WITH_SIZE(5, 1 * sizeof(uint32_t)),
525         LinkJumpTestBit = JUMP_ENUM_WITH_SIZE(6, 2 * sizeof(uint32_t)),
526         LinkJumpTestBitDirect = JUMP_ENUM_WITH_SIZE(7, 1 * sizeof(uint32_t)),
527     };
528
529     class LinkRecord {
530     public:
531         LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition)
532         {
533             data.realTypes.m_from = from;
534             data.realTypes.m_to = to;
535             data.realTypes.m_type = type;
536             data.realTypes.m_linkType = LinkInvalid;
537             data.realTypes.m_condition = condition;
538         }
539         LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition, bool is64Bit, RegisterID compareRegister)
540         {
541             data.realTypes.m_from = from;
542             data.realTypes.m_to = to;
543             data.realTypes.m_type = type;
544             data.realTypes.m_linkType = LinkInvalid;
545             data.realTypes.m_condition = condition;
546             data.realTypes.m_is64Bit = is64Bit;
547             data.realTypes.m_compareRegister = compareRegister;
548         }
549         LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition, unsigned bitNumber, RegisterID compareRegister)
550         {
551             data.realTypes.m_from = from;
552             data.realTypes.m_to = to;
553             data.realTypes.m_type = type;
554             data.realTypes.m_linkType = LinkInvalid;
555             data.realTypes.m_condition = condition;
556             data.realTypes.m_bitNumber = bitNumber;
557             data.realTypes.m_compareRegister = compareRegister;
558         }
559         void operator=(const LinkRecord& other)
560         {
561             data.copyTypes.content[0] = other.data.copyTypes.content[0];
562             data.copyTypes.content[1] = other.data.copyTypes.content[1];
563             data.copyTypes.content[2] = other.data.copyTypes.content[2];
564         }
565         intptr_t from() const { return data.realTypes.m_from; }
566         void setFrom(intptr_t from) { data.realTypes.m_from = from; }
567         intptr_t to() const { return data.realTypes.m_to; }
568         JumpType type() const { return data.realTypes.m_type; }
569         JumpLinkType linkType() const { return data.realTypes.m_linkType; }
570         void setLinkType(JumpLinkType linkType) { ASSERT(data.realTypes.m_linkType == LinkInvalid); data.realTypes.m_linkType = linkType; }
571         Condition condition() const { return data.realTypes.m_condition; }
572         bool is64Bit() const { return data.realTypes.m_is64Bit; }
573         unsigned bitNumber() const { return data.realTypes.m_bitNumber; }
574         RegisterID compareRegister() const { return data.realTypes.m_compareRegister; }
575
576     private:
577         union {
578             struct RealTypes {
579                 intptr_t m_from : 48;
580                 intptr_t m_to : 48;
581                 JumpType m_type : 8;
582                 JumpLinkType m_linkType : 8;
583                 Condition m_condition : 4;
584                 bool m_is64Bit : 1;
585                 unsigned m_bitNumber : 6;
586                 RegisterID m_compareRegister : 5;
587             } realTypes;
588             struct CopyTypes {
589                 uint64_t content[3];
590             } copyTypes;
591             COMPILE_ASSERT(sizeof(RealTypes) == sizeof(CopyTypes), LinkRecordCopyStructSizeEqualsRealStruct);
592         } data;
593     };
594
595     // bits(N) VFPExpandImm(bits(8) imm8);
596     //
597     // Encoding of floating point immediates is a litte complicated. Here's a
598     // high level description:
599     //     +/-m*2-n where m and n are integers, 16 <= m <= 31, 0 <= n <= 7
600     // and the algirithm for expanding to a single precision float:
601     //     return imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,5):imm8<5:0>:Zeros(19);
602     //
603     // The trickiest bit is how the exponent is handled. The following table
604     // may help clarify things a little:
605     //     654
606     //     100 01111100 124 -3 1020 01111111100
607     //     101 01111101 125 -2 1021 01111111101
608     //     110 01111110 126 -1 1022 01111111110
609     //     111 01111111 127  0 1023 01111111111
610     //     000 10000000 128  1 1024 10000000000
611     //     001 10000001 129  2 1025 10000000001
612     //     010 10000010 130  3 1026 10000000010
613     //     011 10000011 131  4 1027 10000000011
614     // The first column shows the bit pattern stored in bits 6-4 of the arm
615     // encoded immediate. The second column shows the 8-bit IEEE 754 single
616     // -precision exponent in binary, the third column shows the raw decimal
617     // value. IEEE 754 single-precision numbers are stored with a bias of 127
618     // to the exponent, so the fourth column shows the resulting exponent.
619     // From this was can see that the exponent can be in the range -3..4,
620     // which agrees with the high level description given above. The fifth
621     // and sixth columns shows the value stored in a IEEE 754 double-precision
622     // number to represent these exponents in decimal and binary, given the
623     // bias of 1023.
624     //
625     // Ultimately, detecting doubles that can be encoded as immediates on arm
626     // and encoding doubles is actually not too bad. A floating point value can
627     // be encoded by retaining the sign bit, the low three bits of the exponent
628     // and the high 4 bits of the mantissa. To validly be able to encode an
629     // immediate the remainder of the mantissa must be zero, and the high part
630     // of the exponent must match the top bit retained, bar the highest bit
631     // which must be its inverse.
632     static bool canEncodeFPImm(double d)
633     {
634         // Discard the sign bit, the low two bits of the exponent & the highest
635         // four bits of the mantissa.
636         uint64_t masked = bitwise_cast<uint64_t>(d) & 0x7fc0ffffffffffffull;
637         return (masked == 0x3fc0000000000000ull) || (masked == 0x4000000000000000ull);
638     }
639
640     template<int datasize>
641     static bool canEncodePImmOffset(int32_t offset)
642     {
643         int32_t maxPImm = 4095 * (datasize / 8);
644         if (offset < 0)
645             return false;
646         if (offset > maxPImm)
647             return false;
648         if (offset & ((datasize / 8 ) - 1))
649             return false;
650         return true;
651     }
652
653     static bool canEncodeSImmOffset(int32_t offset)
654     {
655         return isInt9(offset);
656     }
657
658 private:
659     int encodeFPImm(double d)
660     {
661         ASSERT(canEncodeFPImm(d));
662         uint64_t u64 = bitwise_cast<uint64_t>(d);
663         return (static_cast<int>(u64 >> 56) & 0x80) | (static_cast<int>(u64 >> 48) & 0x7f);
664     }
665
666     template<int datasize>
667     int encodeShiftAmount(int amount)
668     {
669         ASSERT(!amount || datasize == (8 << amount));
670         return amount;
671     }
672
673     template<int datasize>
674     static int encodePositiveImmediate(unsigned pimm)
675     {
676         ASSERT(!(pimm & ((datasize / 8) - 1)));
677         return pimm / (datasize / 8);
678     }
679
680     enum Datasize {
681         Datasize_32,
682         Datasize_64,
683         Datasize_64_top,
684         Datasize_16
685     };
686
687     enum MemOpSize {
688         MemOpSize_8_or_128,
689         MemOpSize_16,
690         MemOpSize_32,
691         MemOpSize_64,
692     };
693
694     enum BranchType {
695         BranchType_JMP,
696         BranchType_CALL,
697         BranchType_RET
698     };
699
700     enum AddOp {
701         AddOp_ADD,
702         AddOp_SUB
703     };
704
705     enum BitfieldOp {
706         BitfieldOp_SBFM,
707         BitfieldOp_BFM,
708         BitfieldOp_UBFM
709     };
710
711     enum DataOp1Source {
712         DataOp_RBIT,
713         DataOp_REV16,
714         DataOp_REV32,
715         DataOp_REV64,
716         DataOp_CLZ,
717         DataOp_CLS
718     };
719
720     enum DataOp2Source {
721         DataOp_UDIV = 2,
722         DataOp_SDIV = 3,
723         DataOp_LSLV = 8,
724         DataOp_LSRV = 9,
725         DataOp_ASRV = 10,
726         DataOp_RORV = 11
727     };
728
729     enum DataOp3Source {
730         DataOp_MADD = 0,
731         DataOp_MSUB = 1,
732         DataOp_SMADDL = 2,
733         DataOp_SMSUBL = 3,
734         DataOp_SMULH = 4,
735         DataOp_UMADDL = 10,
736         DataOp_UMSUBL = 11,
737         DataOp_UMULH = 12
738     };
739
740     enum ExcepnOp {
741         ExcepnOp_EXCEPTION = 0,
742         ExcepnOp_BREAKPOINT = 1,
743         ExcepnOp_HALT = 2,
744         ExcepnOp_DCPS = 5
745     };
746
747     enum FPCmpOp {
748         FPCmpOp_FCMP = 0x00,
749         FPCmpOp_FCMP0 = 0x08,
750         FPCmpOp_FCMPE = 0x10,
751         FPCmpOp_FCMPE0 = 0x18
752     };
753
754     enum FPCondCmpOp {
755         FPCondCmpOp_FCMP,
756         FPCondCmpOp_FCMPE
757     };
758
759     enum FPDataOp1Source {
760         FPDataOp_FMOV = 0,
761         FPDataOp_FABS = 1,
762         FPDataOp_FNEG = 2,
763         FPDataOp_FSQRT = 3,
764         FPDataOp_FCVT_toSingle = 4,
765         FPDataOp_FCVT_toDouble = 5,
766         FPDataOp_FCVT_toHalf = 7,
767         FPDataOp_FRINTN = 8,
768         FPDataOp_FRINTP = 9,
769         FPDataOp_FRINTM = 10,
770         FPDataOp_FRINTZ = 11,
771         FPDataOp_FRINTA = 12,
772         FPDataOp_FRINTX = 14,
773         FPDataOp_FRINTI = 15
774     };
775
776     enum FPDataOp2Source {
777         FPDataOp_FMUL,
778         FPDataOp_FDIV,
779         FPDataOp_FADD,
780         FPDataOp_FSUB,
781         FPDataOp_FMAX,
782         FPDataOp_FMIN,
783         FPDataOp_FMAXNM,
784         FPDataOp_FMINNM,
785         FPDataOp_FNMUL
786     };
787
788     enum FPIntConvOp {
789         FPIntConvOp_FCVTNS = 0x00,
790         FPIntConvOp_FCVTNU = 0x01,
791         FPIntConvOp_SCVTF = 0x02,
792         FPIntConvOp_UCVTF = 0x03,
793         FPIntConvOp_FCVTAS = 0x04,
794         FPIntConvOp_FCVTAU = 0x05,
795         FPIntConvOp_FMOV_QtoX = 0x06,
796         FPIntConvOp_FMOV_XtoQ = 0x07,
797         FPIntConvOp_FCVTPS = 0x08,
798         FPIntConvOp_FCVTPU = 0x09,
799         FPIntConvOp_FMOV_QtoX_top = 0x0e,
800         FPIntConvOp_FMOV_XtoQ_top = 0x0f,
801         FPIntConvOp_FCVTMS = 0x10,
802         FPIntConvOp_FCVTMU = 0x11,
803         FPIntConvOp_FCVTZS = 0x18,
804         FPIntConvOp_FCVTZU = 0x19,
805     };
806
807     enum LogicalOp {
808         LogicalOp_AND,
809         LogicalOp_ORR,
810         LogicalOp_EOR,
811         LogicalOp_ANDS
812     };
813
814     enum MemOp {
815         MemOp_STORE,
816         MemOp_LOAD,
817         MemOp_STORE_V128, 
818         MemOp_LOAD_V128,
819         MemOp_PREFETCH = 2, // size must be 3
820         MemOp_LOAD_signed64 = 2, // size may be 0, 1 or 2
821         MemOp_LOAD_signed32 = 3 // size may be 0 or 1
822     };
823
824     enum MoveWideOp {
825         MoveWideOp_N = 0,
826         MoveWideOp_Z = 2,
827         MoveWideOp_K = 3 
828     };
829
830     enum LdrLiteralOp {
831         LdrLiteralOp_32BIT = 0,
832         LdrLiteralOp_64BIT = 1,
833         LdrLiteralOp_LDRSW = 2,
834         LdrLiteralOp_128BIT = 2
835     };
836
837 public:
838     // Integer Instructions:
839
840     template<int datasize, SetFlags setFlags = DontSetFlags>
841     ALWAYS_INLINE void adc(RegisterID rd, RegisterID rn, RegisterID rm)
842     {
843         CHECK_DATASIZE();
844         insn(addSubtractWithCarry(DATASIZE, AddOp_ADD, setFlags, rm, rn, rd));
845     }
846
847     template<int datasize, SetFlags setFlags = DontSetFlags>
848     ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, UInt12 imm12, int shift = 0)
849     {
850         CHECK_DATASIZE();
851         ASSERT(!shift || shift == 12);
852         insn(addSubtractImmediate(DATASIZE, AddOp_ADD, setFlags, shift == 12, imm12, rn, rd));
853     }
854
855     template<int datasize, SetFlags setFlags = DontSetFlags>
856     ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm)
857     {
858         add<datasize, setFlags>(rd, rn, rm, LSL, 0);
859     }
860
861     template<int datasize, SetFlags setFlags = DontSetFlags>
862     ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
863     {
864         CHECK_DATASIZE();
865         insn(addSubtractExtendedRegister(DATASIZE, AddOp_ADD, setFlags, rm, extend, amount, rn, rd));
866     }
867
868     template<int datasize, SetFlags setFlags = DontSetFlags>
869     ALWAYS_INLINE void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
870     {
871         CHECK_DATASIZE();
872         if (isSp(rn)) {
873             ASSERT(shift == LSL);
874             add<datasize, setFlags>(rd, rn, rm, UXTX, amount);
875         } else
876             insn(addSubtractShiftedRegister(DATASIZE, AddOp_ADD, setFlags, shift, rm, amount, rn, rd));
877     }
878
879     ALWAYS_INLINE void adr(RegisterID rd, int offset)
880     {
881         insn(pcRelative(false, offset, rd));
882     }
883
884     ALWAYS_INLINE void adrp(RegisterID rd, int offset)
885     {
886         ASSERT(!(offset & 0xfff));
887         insn(pcRelative(true, offset >> 12, rd));
888     }
889
890     template<int datasize, SetFlags setFlags = DontSetFlags>
891     ALWAYS_INLINE void and_(RegisterID rd, RegisterID rn, RegisterID rm)
892     {
893         and_<datasize, setFlags>(rd, rn, rm, LSL, 0);
894     }
895
896     template<int datasize, SetFlags setFlags = DontSetFlags>
897     ALWAYS_INLINE void and_(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
898     {
899         CHECK_DATASIZE();
900         insn(logicalShiftedRegister(DATASIZE, setFlags ? LogicalOp_ANDS : LogicalOp_AND, shift, false, rm, amount, rn, rd));
901     }
902
903     template<int datasize, SetFlags setFlags = DontSetFlags>
904     ALWAYS_INLINE void and_(RegisterID rd, RegisterID rn, LogicalImmediate imm)
905     {
906         CHECK_DATASIZE();
907         insn(logicalImmediate(DATASIZE, setFlags ? LogicalOp_ANDS : LogicalOp_AND, imm.value(), rn, rd));
908     }
909
910     template<int datasize>
911     ALWAYS_INLINE void asr(RegisterID rd, RegisterID rn, int shift)
912     {
913         ASSERT(shift < datasize);
914         sbfm<datasize>(rd, rn, shift, datasize - 1);
915     }
916
917     template<int datasize>
918     ALWAYS_INLINE void asr(RegisterID rd, RegisterID rn, RegisterID rm)
919     {
920         asrv<datasize>(rd, rn, rm);
921     }
922
923     template<int datasize>
924     ALWAYS_INLINE void asrv(RegisterID rd, RegisterID rn, RegisterID rm)
925     {
926         CHECK_DATASIZE();
927         insn(dataProcessing2Source(DATASIZE, rm, DataOp_ASRV, rn, rd));
928     }
929
930     ALWAYS_INLINE void b(int32_t offset = 0)
931     {
932         ASSERT(!(offset & 3));
933         offset >>= 2;
934         ASSERT(offset == (offset << 6) >> 6);
935         insn(unconditionalBranchImmediate(false, offset));
936     }
937
938     ALWAYS_INLINE void b_cond(Condition cond, int32_t offset = 0)
939     {
940         ASSERT(!(offset & 3));
941         offset >>= 2;
942         ASSERT(offset == (offset << 13) >> 13);
943         insn(conditionalBranchImmediate(offset, cond));
944     }
945
946     template<int datasize>
947     ALWAYS_INLINE void bfi(RegisterID rd, RegisterID rn, int lsb, int width)
948     {
949         bfm<datasize>(rd, rn, (datasize - lsb) & (datasize - 1), width - 1);
950     }
951
952     template<int datasize>
953     ALWAYS_INLINE void bfm(RegisterID rd, RegisterID rn, int immr, int imms)
954     {
955         CHECK_DATASIZE();
956         insn(bitfield(DATASIZE, BitfieldOp_BFM, immr, imms, rn, rd));
957     }
958
959     template<int datasize>
960     ALWAYS_INLINE void bfxil(RegisterID rd, RegisterID rn, int lsb, int width)
961     {
962         bfm<datasize>(rd, rn, lsb, lsb + width - 1);
963     }
964
965     template<int datasize, SetFlags setFlags = DontSetFlags>
966     ALWAYS_INLINE void bic(RegisterID rd, RegisterID rn, RegisterID rm)
967     {
968         bic<datasize, setFlags>(rd, rn, rm, LSL, 0);
969     }
970
971     template<int datasize, SetFlags setFlags = DontSetFlags>
972     ALWAYS_INLINE void bic(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
973     {
974         CHECK_DATASIZE();
975         insn(logicalShiftedRegister(DATASIZE, setFlags ? LogicalOp_ANDS : LogicalOp_AND, shift, true, rm, amount, rn, rd));
976     }
977
978     ALWAYS_INLINE void bl(int32_t offset = 0)
979     {
980         ASSERT(!(offset & 3));
981         offset >>= 2;
982         insn(unconditionalBranchImmediate(true, offset));
983     }
984
985     ALWAYS_INLINE void blr(RegisterID rn)
986     {
987         insn(unconditionalBranchRegister(BranchType_CALL, rn));
988     }
989
990     ALWAYS_INLINE void br(RegisterID rn)
991     {
992         insn(unconditionalBranchRegister(BranchType_JMP, rn));
993     }
994
995     ALWAYS_INLINE void brk(uint16_t imm)
996     {
997         insn(excepnGeneration(ExcepnOp_BREAKPOINT, imm, 0));
998     }
999     
1000     template<int datasize>
1001     ALWAYS_INLINE void cbnz(RegisterID rt, int32_t offset = 0)
1002     {
1003         CHECK_DATASIZE();
1004         ASSERT(!(offset & 3));
1005         offset >>= 2;
1006         insn(compareAndBranchImmediate(DATASIZE, true, offset, rt));
1007     }
1008
1009     template<int datasize>
1010     ALWAYS_INLINE void cbz(RegisterID rt, int32_t offset = 0)
1011     {
1012         CHECK_DATASIZE();
1013         ASSERT(!(offset & 3));
1014         offset >>= 2;
1015         insn(compareAndBranchImmediate(DATASIZE, false, offset, rt));
1016     }
1017
1018     template<int datasize>
1019     ALWAYS_INLINE void ccmn(RegisterID rn, RegisterID rm, int nzcv, Condition cond)
1020     {
1021         CHECK_DATASIZE();
1022         insn(conditionalCompareRegister(DATASIZE, AddOp_ADD, rm, cond, rn, nzcv));
1023     }
1024
1025     template<int datasize>
1026     ALWAYS_INLINE void ccmn(RegisterID rn, UInt5 imm, int nzcv, Condition cond)
1027     {
1028         CHECK_DATASIZE();
1029         insn(conditionalCompareImmediate(DATASIZE, AddOp_ADD, imm, cond, rn, nzcv));
1030     }
1031
1032     template<int datasize>
1033     ALWAYS_INLINE void ccmp(RegisterID rn, RegisterID rm, int nzcv, Condition cond)
1034     {
1035         CHECK_DATASIZE();
1036         insn(conditionalCompareRegister(DATASIZE, AddOp_SUB, rm, cond, rn, nzcv));
1037     }
1038
1039     template<int datasize>
1040     ALWAYS_INLINE void ccmp(RegisterID rn, UInt5 imm, int nzcv, Condition cond)
1041     {
1042         CHECK_DATASIZE();
1043         insn(conditionalCompareImmediate(DATASIZE, AddOp_SUB, imm, cond, rn, nzcv));
1044     }
1045
1046     template<int datasize>
1047     ALWAYS_INLINE void cinc(RegisterID rd, RegisterID rn, Condition cond)
1048     {
1049         csinc<datasize>(rd, rn, rn, invert(cond));
1050     }
1051
1052     template<int datasize>
1053     ALWAYS_INLINE void cinv(RegisterID rd, RegisterID rn, Condition cond)
1054     {
1055         csinv<datasize>(rd, rn, rn, invert(cond));
1056     }
1057
1058     template<int datasize>
1059     ALWAYS_INLINE void cls(RegisterID rd, RegisterID rn)
1060     {
1061         CHECK_DATASIZE();
1062         insn(dataProcessing1Source(DATASIZE, DataOp_CLS, rn, rd));
1063     }
1064
1065     template<int datasize>
1066     ALWAYS_INLINE void clz(RegisterID rd, RegisterID rn)
1067     {
1068         CHECK_DATASIZE();
1069         insn(dataProcessing1Source(DATASIZE, DataOp_CLZ, rn, rd));
1070     }
1071
1072     template<int datasize>
1073     ALWAYS_INLINE void cmn(RegisterID rn, UInt12 imm12, int shift = 0)
1074     {
1075         add<datasize, S>(ARM64Registers::zr, rn, imm12, shift);
1076     }
1077
1078     template<int datasize>
1079     ALWAYS_INLINE void cmn(RegisterID rn, RegisterID rm)
1080     {
1081         add<datasize, S>(ARM64Registers::zr, rn, rm);
1082     }
1083
1084     template<int datasize>
1085     ALWAYS_INLINE void cmn(RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1086     {
1087         add<datasize, S>(ARM64Registers::zr, rn, rm, extend, amount);
1088     }
1089
1090     template<int datasize>
1091     ALWAYS_INLINE void cmn(RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1092     {
1093         add<datasize, S>(ARM64Registers::zr, rn, rm, shift, amount);
1094     }
1095
1096     template<int datasize>
1097     ALWAYS_INLINE void cmp(RegisterID rn, UInt12 imm12, int shift = 0)
1098     {
1099         sub<datasize, S>(ARM64Registers::zr, rn, imm12, shift);
1100     }
1101
1102     template<int datasize>
1103     ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm)
1104     {
1105         sub<datasize, S>(ARM64Registers::zr, rn, rm);
1106     }
1107
1108     template<int datasize>
1109     ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1110     {
1111         sub<datasize, S>(ARM64Registers::zr, rn, rm, extend, amount);
1112     }
1113
1114     template<int datasize>
1115     ALWAYS_INLINE void cmp(RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1116     {
1117         sub<datasize, S>(ARM64Registers::zr, rn, rm, shift, amount);
1118     }
1119
1120     template<int datasize>
1121     ALWAYS_INLINE void cneg(RegisterID rd, RegisterID rn, Condition cond)
1122     {
1123         csneg<datasize>(rd, rn, rn, invert(cond));
1124     }
1125
1126     template<int datasize>
1127     ALWAYS_INLINE void csel(RegisterID rd, RegisterID rn, RegisterID rm, Condition cond)
1128     {
1129         CHECK_DATASIZE();
1130         insn(conditionalSelect(DATASIZE, false, rm, cond, false, rn, rd));
1131     }
1132
1133     template<int datasize>
1134     ALWAYS_INLINE void cset(RegisterID rd, Condition cond)
1135     {
1136         csinc<datasize>(rd, ARM64Registers::zr, ARM64Registers::zr, invert(cond));
1137     }
1138
1139     template<int datasize>
1140     ALWAYS_INLINE void csetm(RegisterID rd, Condition cond)
1141     {
1142         csinv<datasize>(rd, ARM64Registers::zr, ARM64Registers::zr, invert(cond));
1143     }
1144
1145     template<int datasize>
1146     ALWAYS_INLINE void csinc(RegisterID rd, RegisterID rn, RegisterID rm, Condition cond)
1147     {
1148         CHECK_DATASIZE();
1149         insn(conditionalSelect(DATASIZE, false, rm, cond, true, rn, rd));
1150     }
1151
1152     template<int datasize>
1153     ALWAYS_INLINE void csinv(RegisterID rd, RegisterID rn, RegisterID rm, Condition cond)
1154     {
1155         CHECK_DATASIZE();
1156         insn(conditionalSelect(DATASIZE, true, rm, cond, false, rn, rd));
1157     }
1158
1159     template<int datasize>
1160     ALWAYS_INLINE void csneg(RegisterID rd, RegisterID rn, RegisterID rm, Condition cond)
1161     {
1162         CHECK_DATASIZE();
1163         insn(conditionalSelect(DATASIZE, true, rm, cond, true, rn, rd));
1164     }
1165
1166     template<int datasize>
1167     ALWAYS_INLINE void eon(RegisterID rd, RegisterID rn, RegisterID rm)
1168     {
1169         eon<datasize>(rd, rn, rm, LSL, 0);
1170     }
1171
1172     template<int datasize>
1173     ALWAYS_INLINE void eon(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1174     {
1175         CHECK_DATASIZE();
1176         insn(logicalShiftedRegister(DATASIZE, LogicalOp_EOR, shift, true, rm, amount, rn, rd));
1177     }
1178
1179     template<int datasize>
1180     ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, RegisterID rm)
1181     {
1182         eor<datasize>(rd, rn, rm, LSL, 0);
1183     }
1184
1185     template<int datasize>
1186     ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1187     {
1188         CHECK_DATASIZE();
1189         insn(logicalShiftedRegister(DATASIZE, LogicalOp_EOR, shift, false, rm, amount, rn, rd));
1190     }
1191     
1192     template<int datasize>
1193     ALWAYS_INLINE void eor(RegisterID rd, RegisterID rn, LogicalImmediate imm)
1194     {
1195         CHECK_DATASIZE();
1196         insn(logicalImmediate(DATASIZE, LogicalOp_EOR, imm.value(), rn, rd));
1197     }
1198
1199     template<int datasize>
1200     ALWAYS_INLINE void extr(RegisterID rd, RegisterID rn, RegisterID rm, int lsb)
1201     {
1202         CHECK_DATASIZE();
1203         insn(extract(DATASIZE, rm, lsb, rn, rd));
1204     }
1205
1206     ALWAYS_INLINE void hint(int imm)
1207     {
1208         insn(hintPseudo(imm));
1209     }
1210
1211     ALWAYS_INLINE void hlt(uint16_t imm)
1212     {
1213         insn(excepnGeneration(ExcepnOp_HALT, imm, 0));
1214     }
1215
1216     template<int datasize>
1217     ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, RegisterID rm)
1218     {
1219         ldr<datasize>(rt, rn, rm, UXTX, 0);
1220     }
1221
1222     template<int datasize>
1223     ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1224     {
1225         CHECK_DATASIZE();
1226         insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, false, MemOp_LOAD, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
1227     }
1228
1229     template<int datasize>
1230     ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, unsigned pimm)
1231     {
1232         CHECK_DATASIZE();
1233         insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, false, MemOp_LOAD, encodePositiveImmediate<datasize>(pimm), rn, rt));
1234     }
1235
1236     template<int datasize>
1237     ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, PostIndex simm)
1238     {
1239         CHECK_DATASIZE();
1240         insn(loadStoreRegisterPostIndex(MEMOPSIZE, false, MemOp_LOAD, simm, rn, rt));
1241     }
1242
1243     template<int datasize>
1244     ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, PreIndex simm)
1245     {
1246         CHECK_DATASIZE();
1247         insn(loadStoreRegisterPreIndex(MEMOPSIZE, false, MemOp_LOAD, simm, rn, rt));
1248     }
1249
1250     template<int datasize>
1251     ALWAYS_INLINE void ldr_literal(RegisterID rt, int offset = 0)
1252     {
1253         CHECK_DATASIZE();
1254         ASSERT(!(offset & 3));
1255         insn(loadRegisterLiteral(datasize == 64 ? LdrLiteralOp_64BIT : LdrLiteralOp_32BIT, false, offset >> 2, rt));
1256     }
1257
1258     ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, RegisterID rm)
1259     {
1260         // Not calling the 5 argument form of ldrb, since is amount is ommitted S is false.
1261         insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_LOAD, rm, UXTX, false, rn, rt));
1262     }
1263
1264     ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1265     {
1266         ASSERT_UNUSED(amount, !amount);
1267         insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_LOAD, rm, extend, true, rn, rt));
1268     }
1269
1270     ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, unsigned pimm)
1271     {
1272         insn(loadStoreRegisterUnsignedImmediate(MemOpSize_8_or_128, false, MemOp_LOAD, encodePositiveImmediate<8>(pimm), rn, rt));
1273     }
1274
1275     ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, PostIndex simm)
1276     {
1277         insn(loadStoreRegisterPostIndex(MemOpSize_8_or_128, false, MemOp_LOAD, simm, rn, rt));
1278     }
1279
1280     ALWAYS_INLINE void ldrb(RegisterID rt, RegisterID rn, PreIndex simm)
1281     {
1282         insn(loadStoreRegisterPreIndex(MemOpSize_8_or_128, false, MemOp_LOAD, simm, rn, rt));
1283     }
1284
1285     ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, RegisterID rm)
1286     {
1287         ldrh(rt, rn, rm, UXTX, 0);
1288     }
1289
1290     ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1291     {
1292         ASSERT(!amount || amount == 1);
1293         insn(loadStoreRegisterRegisterOffset(MemOpSize_16, false, MemOp_LOAD, rm, extend, amount == 1, rn, rt));
1294     }
1295
1296     ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, unsigned pimm)
1297     {
1298         insn(loadStoreRegisterUnsignedImmediate(MemOpSize_16, false, MemOp_LOAD, encodePositiveImmediate<16>(pimm), rn, rt));
1299     }
1300
1301     ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, PostIndex simm)
1302     {
1303         insn(loadStoreRegisterPostIndex(MemOpSize_16, false, MemOp_LOAD, simm, rn, rt));
1304     }
1305
1306     ALWAYS_INLINE void ldrh(RegisterID rt, RegisterID rn, PreIndex simm)
1307     {
1308         insn(loadStoreRegisterPreIndex(MemOpSize_16, false, MemOp_LOAD, simm, rn, rt));
1309     }
1310
1311     template<int datasize>
1312     ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, RegisterID rm)
1313     {
1314         CHECK_DATASIZE();
1315         // Not calling the 5 argument form of ldrsb, since is amount is ommitted S is false.
1316         insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, rm, UXTX, false, rn, rt));
1317     }
1318
1319     template<int datasize>
1320     ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1321     {
1322         CHECK_DATASIZE();
1323         ASSERT_UNUSED(amount, !amount);
1324         insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, rm, extend, true, rn, rt));
1325     }
1326
1327     template<int datasize>
1328     ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, unsigned pimm)
1329     {
1330         CHECK_DATASIZE();
1331         insn(loadStoreRegisterUnsignedImmediate(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, encodePositiveImmediate<8>(pimm), rn, rt));
1332     }
1333
1334     template<int datasize>
1335     ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, PostIndex simm)
1336     {
1337         CHECK_DATASIZE();
1338         insn(loadStoreRegisterPostIndex(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
1339     }
1340
1341     template<int datasize>
1342     ALWAYS_INLINE void ldrsb(RegisterID rt, RegisterID rn, PreIndex simm)
1343     {
1344         CHECK_DATASIZE();
1345         insn(loadStoreRegisterPreIndex(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
1346     }
1347
1348     template<int datasize>
1349     ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, RegisterID rm)
1350     {
1351         ldrsh<datasize>(rt, rn, rm, UXTX, 0);
1352     }
1353
1354     template<int datasize>
1355     ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1356     {
1357         CHECK_DATASIZE();
1358         ASSERT(!amount || amount == 1);
1359         insn(loadStoreRegisterRegisterOffset(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, rm, extend, amount == 1, rn, rt));
1360     }
1361
1362     template<int datasize>
1363     ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, unsigned pimm)
1364     {
1365         CHECK_DATASIZE();
1366         insn(loadStoreRegisterUnsignedImmediate(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, encodePositiveImmediate<16>(pimm), rn, rt));
1367     }
1368
1369     template<int datasize>
1370     ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, PostIndex simm)
1371     {
1372         CHECK_DATASIZE();
1373         insn(loadStoreRegisterPostIndex(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
1374     }
1375
1376     template<int datasize>
1377     ALWAYS_INLINE void ldrsh(RegisterID rt, RegisterID rn, PreIndex simm)
1378     {
1379         CHECK_DATASIZE();
1380         insn(loadStoreRegisterPreIndex(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
1381     }
1382
1383     ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, RegisterID rm)
1384     {
1385         ldrsw(rt, rn, rm, UXTX, 0);
1386     }
1387
1388     ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1389     {
1390         ASSERT(!amount || amount == 2);
1391         insn(loadStoreRegisterRegisterOffset(MemOpSize_32, false, MemOp_LOAD_signed64, rm, extend, amount == 2, rn, rt));
1392     }
1393
1394     ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, unsigned pimm)
1395     {
1396         insn(loadStoreRegisterUnsignedImmediate(MemOpSize_32, false, MemOp_LOAD_signed64, encodePositiveImmediate<32>(pimm), rn, rt));
1397     }
1398
1399     ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, PostIndex simm)
1400     {
1401         insn(loadStoreRegisterPostIndex(MemOpSize_32, false, MemOp_LOAD_signed64, simm, rn, rt));
1402     }
1403
1404     ALWAYS_INLINE void ldrsw(RegisterID rt, RegisterID rn, PreIndex simm)
1405     {
1406         insn(loadStoreRegisterPreIndex(MemOpSize_32, false, MemOp_LOAD_signed64, simm, rn, rt));
1407     }
1408
1409     ALWAYS_INLINE void ldrsw_literal(RegisterID rt, int offset = 0)
1410     {
1411         ASSERT(!(offset & 3));
1412         insn(loadRegisterLiteral(LdrLiteralOp_LDRSW, false, offset >> 2, rt));
1413     }
1414
1415     template<int datasize>
1416     ALWAYS_INLINE void ldur(RegisterID rt, RegisterID rn, int simm)
1417     {
1418         CHECK_DATASIZE();
1419         insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, false, MemOp_LOAD, simm, rn, rt));
1420     }
1421
1422     ALWAYS_INLINE void ldurb(RegisterID rt, RegisterID rn, int simm)
1423     {
1424         insn(loadStoreRegisterUnscaledImmediate(MemOpSize_8_or_128, false, MemOp_LOAD, simm, rn, rt));
1425     }
1426
1427     ALWAYS_INLINE void ldurh(RegisterID rt, RegisterID rn, int simm)
1428     {
1429         insn(loadStoreRegisterUnscaledImmediate(MemOpSize_16, false, MemOp_LOAD, simm, rn, rt));
1430     }
1431
1432     template<int datasize>
1433     ALWAYS_INLINE void ldursb(RegisterID rt, RegisterID rn, int simm)
1434     {
1435         CHECK_DATASIZE();
1436         insn(loadStoreRegisterUnscaledImmediate(MemOpSize_8_or_128, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
1437     }
1438
1439     template<int datasize>
1440     ALWAYS_INLINE void ldursh(RegisterID rt, RegisterID rn, int simm)
1441     {
1442         CHECK_DATASIZE();
1443         insn(loadStoreRegisterUnscaledImmediate(MemOpSize_16, false, (datasize == 64) ? MemOp_LOAD_signed64 : MemOp_LOAD_signed32, simm, rn, rt));
1444     }
1445
1446     ALWAYS_INLINE void ldursw(RegisterID rt, RegisterID rn, int simm)
1447     {
1448         insn(loadStoreRegisterUnscaledImmediate(MemOpSize_32, false, MemOp_LOAD_signed64, simm, rn, rt));
1449     }
1450
1451     template<int datasize>
1452     ALWAYS_INLINE void lsl(RegisterID rd, RegisterID rn, int shift)
1453     {
1454         ASSERT(shift < datasize);
1455         ubfm<datasize>(rd, rn, (datasize - shift) & (datasize - 1), datasize - 1 - shift);
1456     }
1457
1458     template<int datasize>
1459     ALWAYS_INLINE void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
1460     {
1461         lslv<datasize>(rd, rn, rm);
1462     }
1463
1464     template<int datasize>
1465     ALWAYS_INLINE void lslv(RegisterID rd, RegisterID rn, RegisterID rm)
1466     {
1467         CHECK_DATASIZE();
1468         insn(dataProcessing2Source(DATASIZE, rm, DataOp_LSLV, rn, rd));
1469     }
1470
1471     template<int datasize>
1472     ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rn, int shift)
1473     {
1474         ASSERT(shift < datasize);
1475         ubfm<datasize>(rd, rn, shift, datasize - 1);
1476     }
1477
1478     template<int datasize>
1479     ALWAYS_INLINE void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
1480     {
1481         lsrv<datasize>(rd, rn, rm);
1482     }
1483
1484     template<int datasize>
1485     ALWAYS_INLINE void lsrv(RegisterID rd, RegisterID rn, RegisterID rm)
1486     {
1487         CHECK_DATASIZE();
1488         insn(dataProcessing2Source(DATASIZE, rm, DataOp_LSRV, rn, rd));
1489     }
1490
1491     template<int datasize>
1492     ALWAYS_INLINE void madd(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1493     {
1494         CHECK_DATASIZE();
1495         insn(dataProcessing3Source(DATASIZE, DataOp_MADD, rm, ra, rn, rd));
1496     }
1497
1498     template<int datasize>
1499     ALWAYS_INLINE void mneg(RegisterID rd, RegisterID rn, RegisterID rm)
1500     {
1501         msub<datasize>(rd, rn, rm, ARM64Registers::zr);
1502     }
1503
1504     template<int datasize>
1505     ALWAYS_INLINE void mov(RegisterID rd, RegisterID rm)
1506     {
1507         if (isSp(rd) || isSp(rm))
1508             add<datasize>(rd, rm, UInt12(0));
1509         else
1510             orr<datasize>(rd, ARM64Registers::zr, rm);
1511     }
1512
1513     template<int datasize>
1514     ALWAYS_INLINE void movi(RegisterID rd, LogicalImmediate imm)
1515     {
1516         orr<datasize>(rd, ARM64Registers::zr, imm);
1517     }
1518
1519     template<int datasize>
1520     ALWAYS_INLINE void movk(RegisterID rd, uint16_t value, int shift = 0)
1521     {
1522         CHECK_DATASIZE();
1523         ASSERT(!(shift & 0xf));
1524         insn(moveWideImediate(DATASIZE, MoveWideOp_K, shift >> 4, value, rd));
1525     }
1526
1527     template<int datasize>
1528     ALWAYS_INLINE void movn(RegisterID rd, uint16_t value, int shift = 0)
1529     {
1530         CHECK_DATASIZE();
1531         ASSERT(!(shift & 0xf));
1532         insn(moveWideImediate(DATASIZE, MoveWideOp_N, shift >> 4, value, rd));
1533     }
1534
1535     template<int datasize>
1536     ALWAYS_INLINE void movz(RegisterID rd, uint16_t value, int shift = 0)
1537     {
1538         CHECK_DATASIZE();
1539         ASSERT(!(shift & 0xf));
1540         insn(moveWideImediate(DATASIZE, MoveWideOp_Z, shift >> 4, value, rd));
1541     }
1542
1543     template<int datasize>
1544     ALWAYS_INLINE void msub(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1545     {
1546         CHECK_DATASIZE();
1547         insn(dataProcessing3Source(DATASIZE, DataOp_MSUB, rm, ra, rn, rd));
1548     }
1549
1550     template<int datasize>
1551     ALWAYS_INLINE void mul(RegisterID rd, RegisterID rn, RegisterID rm)
1552     {
1553         madd<datasize>(rd, rn, rm, ARM64Registers::zr);
1554     }
1555
1556     template<int datasize>
1557     ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm)
1558     {
1559         orn<datasize>(rd, ARM64Registers::zr, rm);
1560     }
1561
1562     template<int datasize>
1563     ALWAYS_INLINE void mvn(RegisterID rd, RegisterID rm, ShiftType shift, int amount)
1564     {
1565         orn<datasize>(rd, ARM64Registers::zr, rm, shift, amount);
1566     }
1567
1568     template<int datasize, SetFlags setFlags = DontSetFlags>
1569     ALWAYS_INLINE void neg(RegisterID rd, RegisterID rm)
1570     {
1571         sub<datasize, setFlags>(rd, ARM64Registers::zr, rm);
1572     }
1573
1574     template<int datasize, SetFlags setFlags = DontSetFlags>
1575     ALWAYS_INLINE void neg(RegisterID rd, RegisterID rm, ShiftType shift, int amount)
1576     {
1577         sub<datasize, setFlags>(rd, ARM64Registers::zr, rm, shift, amount);
1578     }
1579
1580     template<int datasize, SetFlags setFlags = DontSetFlags>
1581     ALWAYS_INLINE void ngc(RegisterID rd, RegisterID rm)
1582     {
1583         sbc<datasize, setFlags>(rd, ARM64Registers::zr, rm);
1584     }
1585
1586     template<int datasize, SetFlags setFlags = DontSetFlags>
1587     ALWAYS_INLINE void ngc(RegisterID rd, RegisterID rm, ShiftType shift, int amount)
1588     {
1589         sbc<datasize, setFlags>(rd, ARM64Registers::zr, rm, shift, amount);
1590     }
1591
1592     ALWAYS_INLINE void nop()
1593     {
1594         insn(nopPseudo());
1595     }
1596
1597     template<int datasize>
1598     ALWAYS_INLINE void orn(RegisterID rd, RegisterID rn, RegisterID rm)
1599     {
1600         orn<datasize>(rd, rn, rm, LSL, 0);
1601     }
1602
1603     template<int datasize>
1604     ALWAYS_INLINE void orn(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1605     {
1606         CHECK_DATASIZE();
1607         insn(logicalShiftedRegister(DATASIZE, LogicalOp_ORR, shift, true, rm, amount, rn, rd));
1608     }
1609
1610     template<int datasize>
1611     ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm)
1612     {
1613         orr<datasize>(rd, rn, rm, LSL, 0);
1614     }
1615
1616     template<int datasize>
1617     ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1618     {
1619         CHECK_DATASIZE();
1620         insn(logicalShiftedRegister(DATASIZE, LogicalOp_ORR, shift, false, rm, amount, rn, rd));
1621     }
1622
1623     template<int datasize>
1624     ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, LogicalImmediate imm)
1625     {
1626         CHECK_DATASIZE();
1627         insn(logicalImmediate(DATASIZE, LogicalOp_ORR, imm.value(), rn, rd));
1628     }
1629
1630     template<int datasize>
1631     ALWAYS_INLINE void rbit(RegisterID rd, RegisterID rn)
1632     {
1633         CHECK_DATASIZE();
1634         insn(dataProcessing1Source(DATASIZE, DataOp_RBIT, rn, rd));
1635     }
1636
1637     ALWAYS_INLINE void ret(RegisterID rn = ARM64Registers::lr)
1638     {
1639         insn(unconditionalBranchRegister(BranchType_RET, rn));
1640     }
1641
1642     template<int datasize>
1643     ALWAYS_INLINE void rev(RegisterID rd, RegisterID rn)
1644     {
1645         CHECK_DATASIZE();
1646         if (datasize == 32) // 'rev' mnemonic means REV32 or REV64 depending on the operand width.
1647             insn(dataProcessing1Source(Datasize_32, DataOp_REV32, rn, rd));
1648         else
1649             insn(dataProcessing1Source(Datasize_64, DataOp_REV64, rn, rd));
1650     }
1651
1652     template<int datasize>
1653     ALWAYS_INLINE void rev16(RegisterID rd, RegisterID rn)
1654     {
1655         CHECK_DATASIZE();
1656         insn(dataProcessing1Source(DATASIZE, DataOp_REV16, rn, rd));
1657     }
1658
1659     template<int datasize>
1660     ALWAYS_INLINE void rev32(RegisterID rd, RegisterID rn)
1661     {
1662         ASSERT(datasize == 64); // 'rev32' only valid with 64-bit operands.
1663         insn(dataProcessing1Source(Datasize_64, DataOp_REV32, rn, rd));
1664     }
1665
1666     template<int datasize>
1667     ALWAYS_INLINE void ror(RegisterID rd, RegisterID rn, RegisterID rm)
1668     {
1669         rorv<datasize>(rd, rn, rm);
1670     }
1671
1672     template<int datasize>
1673     ALWAYS_INLINE void ror(RegisterID rd, RegisterID rs, int shift)
1674     {
1675         extr<datasize>(rd, rs, rs, shift);
1676     }
1677
1678     template<int datasize>
1679     ALWAYS_INLINE void rorv(RegisterID rd, RegisterID rn, RegisterID rm)
1680     {
1681         CHECK_DATASIZE();
1682         insn(dataProcessing2Source(DATASIZE, rm, DataOp_RORV, rn, rd));
1683     }
1684
1685     template<int datasize, SetFlags setFlags = DontSetFlags>
1686     ALWAYS_INLINE void sbc(RegisterID rd, RegisterID rn, RegisterID rm)
1687     {
1688         CHECK_DATASIZE();
1689         insn(addSubtractWithCarry(DATASIZE, AddOp_SUB, setFlags, rm, rn, rd));
1690     }
1691
1692     template<int datasize>
1693     ALWAYS_INLINE void sbfiz(RegisterID rd, RegisterID rn, int lsb, int width)
1694     {
1695         sbfm<datasize>(rd, rn, (datasize - lsb) & (datasize - 1), width - 1);
1696     }
1697
1698     template<int datasize>
1699     ALWAYS_INLINE void sbfm(RegisterID rd, RegisterID rn, int immr, int imms)
1700     {
1701         CHECK_DATASIZE();
1702         insn(bitfield(DATASIZE, BitfieldOp_SBFM, immr, imms, rn, rd));
1703     }
1704
1705     template<int datasize>
1706     ALWAYS_INLINE void sbfx(RegisterID rd, RegisterID rn, int lsb, int width)
1707     {
1708         sbfm<datasize>(rd, rn, lsb, lsb + width - 1);
1709     }
1710
1711     template<int datasize>
1712     ALWAYS_INLINE void sdiv(RegisterID rd, RegisterID rn, RegisterID rm)
1713     {
1714         CHECK_DATASIZE();
1715         insn(dataProcessing2Source(DATASIZE, rm, DataOp_SDIV, rn, rd));
1716     }
1717
1718     ALWAYS_INLINE void smaddl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1719     {
1720         insn(dataProcessing3Source(Datasize_64, DataOp_SMADDL, rm, ra, rn, rd));
1721     }
1722
1723     ALWAYS_INLINE void smnegl(RegisterID rd, RegisterID rn, RegisterID rm)
1724     {
1725         smsubl(rd, rn, rm, ARM64Registers::zr);
1726     }
1727
1728     ALWAYS_INLINE void smsubl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1729     {
1730         insn(dataProcessing3Source(Datasize_64, DataOp_SMSUBL, rm, ra, rn, rd));
1731     }
1732
1733     ALWAYS_INLINE void smulh(RegisterID rd, RegisterID rn, RegisterID rm)
1734     {
1735         insn(dataProcessing3Source(Datasize_64, DataOp_SMULH, rm, ARM64Registers::zr, rn, rd));
1736     }
1737
1738     ALWAYS_INLINE void smull(RegisterID rd, RegisterID rn, RegisterID rm)
1739     {
1740         smaddl(rd, rn, rm, ARM64Registers::zr);
1741     }
1742
1743     template<int datasize>
1744     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm)
1745     {
1746         str<datasize>(rt, rn, rm, UXTX, 0);
1747     }
1748
1749     template<int datasize>
1750     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1751     {
1752         CHECK_DATASIZE();
1753         insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, false, MemOp_STORE, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
1754     }
1755
1756     template<int datasize>
1757     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, unsigned pimm)
1758     {
1759         CHECK_DATASIZE();
1760         insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, false, MemOp_STORE, encodePositiveImmediate<datasize>(pimm), rn, rt));
1761     }
1762
1763     template<int datasize>
1764     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, PostIndex simm)
1765     {
1766         CHECK_DATASIZE();
1767         insn(loadStoreRegisterPostIndex(MEMOPSIZE, false, MemOp_STORE, simm, rn, rt));
1768     }
1769
1770     template<int datasize>
1771     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, PreIndex simm)
1772     {
1773         CHECK_DATASIZE();
1774         insn(loadStoreRegisterPreIndex(MEMOPSIZE, false, MemOp_STORE, simm, rn, rt));
1775     }
1776
1777     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, RegisterID rm)
1778     {
1779         // Not calling the 5 argument form of strb, since is amount is ommitted S is false.
1780         insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_STORE, rm, UXTX, false, rn, rt));
1781     }
1782
1783     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1784     {
1785         ASSERT_UNUSED(amount, !amount);
1786         insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_STORE, rm, extend, true, rn, rt));
1787     }
1788
1789     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, unsigned pimm)
1790     {
1791         insn(loadStoreRegisterUnsignedImmediate(MemOpSize_8_or_128, false, MemOp_STORE, encodePositiveImmediate<8>(pimm), rn, rt));
1792     }
1793
1794     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, PostIndex simm)
1795     {
1796         insn(loadStoreRegisterPostIndex(MemOpSize_8_or_128, false, MemOp_STORE, simm, rn, rt));
1797     }
1798
1799     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, PreIndex simm)
1800     {
1801         insn(loadStoreRegisterPreIndex(MemOpSize_8_or_128, false, MemOp_STORE, simm, rn, rt));
1802     }
1803
1804     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, RegisterID rm)
1805     {
1806         strh(rt, rn, rm, UXTX, 0);
1807     }
1808
1809     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1810     {
1811         ASSERT(!amount || amount == 1);
1812         insn(loadStoreRegisterRegisterOffset(MemOpSize_16, false, MemOp_STORE, rm, extend, amount == 1, rn, rt));
1813     }
1814
1815     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, unsigned pimm)
1816     {
1817         insn(loadStoreRegisterUnsignedImmediate(MemOpSize_16, false, MemOp_STORE, encodePositiveImmediate<16>(pimm), rn, rt));
1818     }
1819
1820     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, PostIndex simm)
1821     {
1822         insn(loadStoreRegisterPostIndex(MemOpSize_16, false, MemOp_STORE, simm, rn, rt));
1823     }
1824
1825     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, PreIndex simm)
1826     {
1827         insn(loadStoreRegisterPreIndex(MemOpSize_16, false, MemOp_STORE, simm, rn, rt));
1828     }
1829
1830     template<int datasize>
1831     ALWAYS_INLINE void stur(RegisterID rt, RegisterID rn, int simm)
1832     {
1833         CHECK_DATASIZE();
1834         insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, false, MemOp_STORE, simm, rn, rt));
1835     }
1836
1837     ALWAYS_INLINE void sturb(RegisterID rt, RegisterID rn, int simm)
1838     {
1839         insn(loadStoreRegisterUnscaledImmediate(MemOpSize_8_or_128, false, MemOp_STORE, simm, rn, rt));
1840     }
1841
1842     ALWAYS_INLINE void sturh(RegisterID rt, RegisterID rn, int simm)
1843     {
1844         insn(loadStoreRegisterUnscaledImmediate(MemOpSize_16, false, MemOp_STORE, simm, rn, rt));
1845     }
1846
1847     template<int datasize, SetFlags setFlags = DontSetFlags>
1848     ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, UInt12 imm12, int shift = 0)
1849     {
1850         CHECK_DATASIZE();
1851         ASSERT(!shift || shift == 12);
1852         insn(addSubtractImmediate(DATASIZE, AddOp_SUB, setFlags, shift == 12, imm12, rn, rd));
1853     }
1854
1855     template<int datasize, SetFlags setFlags = DontSetFlags>
1856     ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm)
1857     {
1858         sub<datasize, setFlags>(rd, rn, rm, LSL, 0);
1859     }
1860
1861     template<int datasize, SetFlags setFlags = DontSetFlags>
1862     ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1863     {
1864         CHECK_DATASIZE();
1865         insn(addSubtractExtendedRegister(DATASIZE, AddOp_SUB, setFlags, rm, extend, amount, rn, rd));
1866     }
1867
1868     template<int datasize, SetFlags setFlags = DontSetFlags>
1869     ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1870     {
1871         CHECK_DATASIZE();
1872         if (isSp(rn)) {
1873             ASSERT(shift == LSL);
1874             sub<datasize, setFlags>(rd, rn, rm, UXTX, amount);
1875         } else
1876             insn(addSubtractShiftedRegister(DATASIZE, AddOp_SUB, setFlags, shift, rm, amount, rn, rd));
1877     }
1878
1879     template<int datasize>
1880     ALWAYS_INLINE void sxtb(RegisterID rd, RegisterID rn)
1881     {
1882         sbfm<datasize>(rd, rn, 0, 7);
1883     }
1884
1885     template<int datasize>
1886     ALWAYS_INLINE void sxth(RegisterID rd, RegisterID rn)
1887     {
1888         sbfm<datasize>(rd, rn, 0, 15);
1889     }
1890
1891     ALWAYS_INLINE void sxtw(RegisterID rd, RegisterID rn)
1892     {
1893         sbfm<64>(rd, rn, 0, 31);
1894     }
1895
1896     ALWAYS_INLINE void tbz(RegisterID rt, int imm, int offset = 0)
1897     {
1898         ASSERT(!(offset & 3));
1899         offset >>= 2;
1900         insn(testAndBranchImmediate(false, imm, offset, rt));
1901     }
1902
1903     ALWAYS_INLINE void tbnz(RegisterID rt, int imm, int offset = 0)
1904     {
1905         ASSERT(!(offset & 3));
1906         offset >>= 2;
1907         insn(testAndBranchImmediate(true, imm, offset, rt));
1908     }
1909
1910     template<int datasize>
1911     ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm)
1912     {
1913         and_<datasize, S>(ARM64Registers::zr, rn, rm);
1914     }
1915
1916     template<int datasize>
1917     ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1918     {
1919         and_<datasize, S>(ARM64Registers::zr, rn, rm, shift, amount);
1920     }
1921
1922     template<int datasize>
1923     ALWAYS_INLINE void tst(RegisterID rn, LogicalImmediate imm)
1924     {
1925         and_<datasize, S>(ARM64Registers::zr, rn, imm);
1926     }
1927
1928     template<int datasize>
1929     ALWAYS_INLINE void ubfiz(RegisterID rd, RegisterID rn, int lsb, int width)
1930     {
1931         ubfm<datasize>(rd, rn, (datasize - lsb) & (datasize - 1), width - 1);
1932     }
1933
1934     template<int datasize>
1935     ALWAYS_INLINE void ubfm(RegisterID rd, RegisterID rn, int immr, int imms)
1936     {
1937         CHECK_DATASIZE();
1938         insn(bitfield(DATASIZE, BitfieldOp_UBFM, immr, imms, rn, rd));
1939     }
1940
1941     template<int datasize>
1942     ALWAYS_INLINE void ubfx(RegisterID rd, RegisterID rn, int lsb, int width)
1943     {
1944         ubfm<datasize>(rd, rn, lsb, lsb + width - 1);
1945     }
1946
1947     template<int datasize>
1948     ALWAYS_INLINE void udiv(RegisterID rd, RegisterID rn, RegisterID rm)
1949     {
1950         CHECK_DATASIZE();
1951         insn(dataProcessing2Source(DATASIZE, rm, DataOp_UDIV, rn, rd));
1952     }
1953
1954     ALWAYS_INLINE void umaddl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1955     {
1956         insn(dataProcessing3Source(Datasize_64, DataOp_UMADDL, rm, ra, rn, rd));
1957     }
1958
1959     ALWAYS_INLINE void umnegl(RegisterID rd, RegisterID rn, RegisterID rm)
1960     {
1961         umsubl(rd, rn, rm, ARM64Registers::zr);
1962     }
1963
1964     ALWAYS_INLINE void umsubl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1965     {
1966         insn(dataProcessing3Source(Datasize_64, DataOp_UMSUBL, rm, ra, rn, rd));
1967     }
1968
1969     ALWAYS_INLINE void umulh(RegisterID rd, RegisterID rn, RegisterID rm)
1970     {
1971         insn(dataProcessing3Source(Datasize_64, DataOp_UMULH, rm, ARM64Registers::zr, rn, rd));
1972     }
1973
1974     ALWAYS_INLINE void umull(RegisterID rd, RegisterID rn, RegisterID rm)
1975     {
1976         umaddl(rd, rn, rm, ARM64Registers::zr);
1977     }
1978
1979     template<int datasize>
1980     ALWAYS_INLINE void uxtb(RegisterID rd, RegisterID rn)
1981     {
1982         ubfm<datasize>(rd, rn, 0, 7);
1983     }
1984
1985     template<int datasize>
1986     ALWAYS_INLINE void uxth(RegisterID rd, RegisterID rn)
1987     {
1988         ubfm<datasize>(rd, rn, 0, 15);
1989     }
1990
1991     ALWAYS_INLINE void uxtw(RegisterID rd, RegisterID rn)
1992     {
1993         ubfm<64>(rd, rn, 0, 31);
1994     }
1995
1996     // Floating Point Instructions:
1997
1998     template<int datasize>
1999     ALWAYS_INLINE void fabs(FPRegisterID vd, FPRegisterID vn)
2000     {
2001         CHECK_DATASIZE();
2002         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FABS, vn, vd));
2003     }
2004
2005     template<int datasize>
2006     ALWAYS_INLINE void fadd(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2007     {
2008         CHECK_DATASIZE();
2009         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FADD, vn, vd));
2010     }
2011
2012     template<int datasize>
2013     ALWAYS_INLINE void fccmp(FPRegisterID vn, FPRegisterID vm, int nzcv, Condition cond)
2014     {
2015         CHECK_DATASIZE();
2016         insn(floatingPointConditionalCompare(DATASIZE, vm, cond, vn, FPCondCmpOp_FCMP, nzcv));
2017     }
2018
2019     template<int datasize>
2020     ALWAYS_INLINE void fccmpe(FPRegisterID vn, FPRegisterID vm, int nzcv, Condition cond)
2021     {
2022         CHECK_DATASIZE();
2023         insn(floatingPointConditionalCompare(DATASIZE, vm, cond, vn, FPCondCmpOp_FCMPE, nzcv));
2024     }
2025
2026     template<int datasize>
2027     ALWAYS_INLINE void fcmp(FPRegisterID vn, FPRegisterID vm)
2028     {
2029         CHECK_DATASIZE();
2030         insn(floatingPointCompare(DATASIZE, vm, vn, FPCmpOp_FCMP));
2031     }
2032
2033     template<int datasize>
2034     ALWAYS_INLINE void fcmp_0(FPRegisterID vn)
2035     {
2036         CHECK_DATASIZE();
2037         insn(floatingPointCompare(DATASIZE, static_cast<FPRegisterID>(0), vn, FPCmpOp_FCMP0));
2038     }
2039
2040     template<int datasize>
2041     ALWAYS_INLINE void fcmpe(FPRegisterID vn, FPRegisterID vm)
2042     {
2043         CHECK_DATASIZE();
2044         insn(floatingPointCompare(DATASIZE, vm, vn, FPCmpOp_FCMPE));
2045     }
2046
2047     template<int datasize>
2048     ALWAYS_INLINE void fcmpe_0(FPRegisterID vn)
2049     {
2050         CHECK_DATASIZE();
2051         insn(floatingPointCompare(DATASIZE, static_cast<FPRegisterID>(0), vn, FPCmpOp_FCMPE0));
2052     }
2053
2054     template<int datasize>
2055     ALWAYS_INLINE void fcsel(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, Condition cond)
2056     {
2057         CHECK_DATASIZE();
2058         insn(floatingPointConditionalSelect(DATASIZE, vm, cond, vn, vd));
2059     }
2060
2061     template<int dstsize, int srcsize>
2062     ALWAYS_INLINE void fcvt(FPRegisterID vd, FPRegisterID vn)
2063     {
2064         ASSERT(dstsize == 16 || dstsize == 32 || dstsize == 64);
2065         ASSERT(srcsize == 16 || srcsize == 32 || srcsize == 64);
2066         ASSERT(dstsize != srcsize);
2067         Datasize type = (srcsize == 64) ? Datasize_64 : (srcsize == 32) ? Datasize_32 : Datasize_16;
2068         FPDataOp1Source opcode = (dstsize == 64) ? FPDataOp_FCVT_toDouble : (dstsize == 32) ? FPDataOp_FCVT_toSingle : FPDataOp_FCVT_toHalf;
2069         insn(floatingPointDataProcessing1Source(type, opcode, vn, vd));
2070     }
2071
2072     template<int dstsize, int srcsize>
2073     ALWAYS_INLINE void fcvtas(RegisterID rd, FPRegisterID vn)
2074     {
2075         CHECK_DATASIZE_OF(dstsize);
2076         CHECK_DATASIZE_OF(srcsize);
2077         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTAS, vn, rd));
2078     }
2079
2080     template<int dstsize, int srcsize>
2081     ALWAYS_INLINE void fcvtau(RegisterID rd, FPRegisterID vn)
2082     {
2083         CHECK_DATASIZE_OF(dstsize);
2084         CHECK_DATASIZE_OF(srcsize);
2085         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTAU, vn, rd));
2086     }
2087
2088     template<int dstsize, int srcsize>
2089     ALWAYS_INLINE void fcvtms(RegisterID rd, FPRegisterID vn)
2090     {
2091         CHECK_DATASIZE_OF(dstsize);
2092         CHECK_DATASIZE_OF(srcsize);
2093         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTMS, vn, rd));
2094     }
2095
2096     template<int dstsize, int srcsize>
2097     ALWAYS_INLINE void fcvtmu(RegisterID rd, FPRegisterID vn)
2098     {
2099         CHECK_DATASIZE_OF(dstsize);
2100         CHECK_DATASIZE_OF(srcsize);
2101         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTMU, vn, rd));
2102     }
2103
2104     template<int dstsize, int srcsize>
2105     ALWAYS_INLINE void fcvtns(RegisterID rd, FPRegisterID vn)
2106     {
2107         CHECK_DATASIZE_OF(dstsize);
2108         CHECK_DATASIZE_OF(srcsize);
2109         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTNS, vn, rd));
2110     }
2111
2112     template<int dstsize, int srcsize>
2113     ALWAYS_INLINE void fcvtnu(RegisterID rd, FPRegisterID vn)
2114     {
2115         CHECK_DATASIZE_OF(dstsize);
2116         CHECK_DATASIZE_OF(srcsize);
2117         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTNU, vn, rd));
2118     }
2119
2120     template<int dstsize, int srcsize>
2121     ALWAYS_INLINE void fcvtps(RegisterID rd, FPRegisterID vn)
2122     {
2123         CHECK_DATASIZE_OF(dstsize);
2124         CHECK_DATASIZE_OF(srcsize);
2125         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTPS, vn, rd));
2126     }
2127
2128     template<int dstsize, int srcsize>
2129     ALWAYS_INLINE void fcvtpu(RegisterID rd, FPRegisterID vn)
2130     {
2131         CHECK_DATASIZE_OF(dstsize);
2132         CHECK_DATASIZE_OF(srcsize);
2133         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTPU, vn, rd));
2134     }
2135
2136     template<int dstsize, int srcsize>
2137     ALWAYS_INLINE void fcvtzs(RegisterID rd, FPRegisterID vn)
2138     {
2139         CHECK_DATASIZE_OF(dstsize);
2140         CHECK_DATASIZE_OF(srcsize);
2141         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTZS, vn, rd));
2142     }
2143
2144     template<int dstsize, int srcsize>
2145     ALWAYS_INLINE void fcvtzu(RegisterID rd, FPRegisterID vn)
2146     {
2147         CHECK_DATASIZE_OF(dstsize);
2148         CHECK_DATASIZE_OF(srcsize);
2149         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTZU, vn, rd));
2150     }
2151
2152     template<int datasize>
2153     ALWAYS_INLINE void fdiv(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2154     {
2155         CHECK_DATASIZE();
2156         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FDIV, vn, vd));
2157     }
2158
2159     template<int datasize>
2160     ALWAYS_INLINE void fmadd(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
2161     {
2162         CHECK_DATASIZE();
2163         insn(floatingPointDataProcessing3Source(DATASIZE, false, vm, AddOp_ADD, va, vn, vd));
2164     }
2165
2166     template<int datasize>
2167     ALWAYS_INLINE void fmax(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2168     {
2169         CHECK_DATASIZE();
2170         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMAX, vn, vd));
2171     }
2172
2173     template<int datasize>
2174     ALWAYS_INLINE void fmaxnm(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2175     {
2176         CHECK_DATASIZE();
2177         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMAXNM, vn, vd));
2178     }
2179
2180     template<int datasize>
2181     ALWAYS_INLINE void fmin(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2182     {
2183         CHECK_DATASIZE();
2184         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMIN, vn, vd));
2185     }
2186
2187     template<int datasize>
2188     ALWAYS_INLINE void fminnm(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2189     {
2190         CHECK_DATASIZE();
2191         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMINNM, vn, vd));
2192     }
2193
2194     template<int datasize>
2195     ALWAYS_INLINE void fmov(FPRegisterID vd, FPRegisterID vn)
2196     {
2197         CHECK_DATASIZE();
2198         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FMOV, vn, vd));
2199     }
2200
2201     template<int datasize>
2202     ALWAYS_INLINE void fmov(FPRegisterID vd, RegisterID rn)
2203     {
2204         CHECK_DATASIZE();
2205         insn(floatingPointIntegerConversions(DATASIZE, DATASIZE, FPIntConvOp_FMOV_XtoQ, rn, vd));
2206     }
2207
2208     template<int datasize>
2209     ALWAYS_INLINE void fmov(RegisterID rd, FPRegisterID vn)
2210     {
2211         CHECK_DATASIZE();
2212         insn(floatingPointIntegerConversions(DATASIZE, DATASIZE, FPIntConvOp_FMOV_QtoX, vn, rd));
2213     }
2214
2215     template<int datasize>
2216     ALWAYS_INLINE void fmov(FPRegisterID vd, double imm)
2217     {
2218         CHECK_DATASIZE();
2219         insn(floatingPointImmediate(DATASIZE, encodeFPImm(imm), vd));
2220     }
2221
2222     ALWAYS_INLINE void fmov_top(FPRegisterID vd, RegisterID rn)
2223     {
2224         insn(floatingPointIntegerConversions(Datasize_64, Datasize_64, FPIntConvOp_FMOV_XtoQ_top, rn, vd));
2225     }
2226
2227     ALWAYS_INLINE void fmov_top(RegisterID rd, FPRegisterID vn)
2228     {
2229         insn(floatingPointIntegerConversions(Datasize_64, Datasize_64, FPIntConvOp_FMOV_QtoX_top, vn, rd));
2230     }
2231
2232     template<int datasize>
2233     ALWAYS_INLINE void fmsub(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
2234     {
2235         CHECK_DATASIZE();
2236         insn(floatingPointDataProcessing3Source(DATASIZE, false, vm, AddOp_SUB, va, vn, vd));
2237     }
2238
2239     template<int datasize>
2240     ALWAYS_INLINE void fmul(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2241     {
2242         CHECK_DATASIZE();
2243         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMUL, vn, vd));
2244     }
2245
2246     template<int datasize>
2247     ALWAYS_INLINE void fneg(FPRegisterID vd, FPRegisterID vn)
2248     {
2249         CHECK_DATASIZE();
2250         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FNEG, vn, vd));
2251     }
2252
2253     template<int datasize>
2254     ALWAYS_INLINE void fnmadd(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
2255     {
2256         CHECK_DATASIZE();
2257         insn(floatingPointDataProcessing3Source(DATASIZE, true, vm, AddOp_ADD, va, vn, vd));
2258     }
2259
2260     template<int datasize>
2261     ALWAYS_INLINE void fnmsub(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
2262     {
2263         CHECK_DATASIZE();
2264         insn(floatingPointDataProcessing3Source(DATASIZE, true, vm, AddOp_SUB, va, vn, vd));
2265     }
2266
2267     template<int datasize>
2268     ALWAYS_INLINE void fnmul(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2269     {
2270         CHECK_DATASIZE();
2271         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FNMUL, vn, vd));
2272     }
2273
2274     template<int datasize>
2275     ALWAYS_INLINE void frinta(FPRegisterID vd, FPRegisterID vn)
2276     {
2277         CHECK_DATASIZE();
2278         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTA, vn, vd));
2279     }
2280
2281     template<int datasize>
2282     ALWAYS_INLINE void frinti(FPRegisterID vd, FPRegisterID vn)
2283     {
2284         CHECK_DATASIZE();
2285         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTI, vn, vd));
2286     }
2287
2288     template<int datasize>
2289     ALWAYS_INLINE void frintm(FPRegisterID vd, FPRegisterID vn)
2290     {
2291         CHECK_DATASIZE();
2292         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTM, vn, vd));
2293     }
2294
2295     template<int datasize>
2296     ALWAYS_INLINE void frintn(FPRegisterID vd, FPRegisterID vn)
2297     {
2298         CHECK_DATASIZE();
2299         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTN, vn, vd));
2300     }
2301
2302     template<int datasize>
2303     ALWAYS_INLINE void frintp(FPRegisterID vd, FPRegisterID vn)
2304     {
2305         CHECK_DATASIZE();
2306         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTP, vn, vd));
2307     }
2308
2309     template<int datasize>
2310     ALWAYS_INLINE void frintx(FPRegisterID vd, FPRegisterID vn)
2311     {
2312         CHECK_DATASIZE();
2313         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTX, vn, vd));
2314     }
2315
2316     template<int datasize>
2317     ALWAYS_INLINE void frintz(FPRegisterID vd, FPRegisterID vn)
2318     {
2319         CHECK_DATASIZE();
2320         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTZ, vn, vd));
2321     }
2322
2323     template<int datasize>
2324     ALWAYS_INLINE void fsqrt(FPRegisterID vd, FPRegisterID vn)
2325     {
2326         CHECK_DATASIZE();
2327         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FSQRT, vn, vd));
2328     }
2329
2330     template<int datasize>
2331     ALWAYS_INLINE void fsub(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2332     {
2333         CHECK_DATASIZE();
2334         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FSUB, vn, vd));
2335     }
2336
2337     template<int datasize>
2338     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, RegisterID rm)
2339     {
2340         ldr<datasize>(rt, rn, rm, UXTX, 0);
2341     }
2342
2343     template<int datasize>
2344     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
2345     {
2346         CHECK_FP_MEMOP_DATASIZE();
2347         insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
2348     }
2349
2350     template<int datasize>
2351     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, unsigned pimm)
2352     {
2353         CHECK_FP_MEMOP_DATASIZE();
2354         insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, encodePositiveImmediate<datasize>(pimm), rn, rt));
2355     }
2356
2357     template<int datasize>
2358     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, PostIndex simm)
2359     {
2360         CHECK_FP_MEMOP_DATASIZE();
2361         insn(loadStoreRegisterPostIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, simm, rn, rt));
2362     }
2363
2364     template<int datasize>
2365     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, PreIndex simm)
2366     {
2367         CHECK_FP_MEMOP_DATASIZE();
2368         insn(loadStoreRegisterPreIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, simm, rn, rt));
2369     }
2370
2371     template<int datasize>
2372     ALWAYS_INLINE void ldr_literal(FPRegisterID rt, int offset = 0)
2373     {
2374         CHECK_FP_MEMOP_DATASIZE();
2375         ASSERT(datasize >= 32);
2376         ASSERT(!(offset & 3));
2377         insn(loadRegisterLiteral(datasize == 128 ? LdrLiteralOp_128BIT : datasize == 64 ? LdrLiteralOp_64BIT : LdrLiteralOp_32BIT, true, offset >> 2, rt));
2378     }
2379
2380     template<int datasize>
2381     ALWAYS_INLINE void ldur(FPRegisterID rt, RegisterID rn, int simm)
2382     {
2383         CHECK_FP_MEMOP_DATASIZE();
2384         insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, simm, rn, rt));
2385     }
2386
2387     template<int dstsize, int srcsize>
2388     ALWAYS_INLINE void scvtf(FPRegisterID vd, RegisterID rn)
2389     {
2390         CHECK_DATASIZE_OF(dstsize);
2391         CHECK_DATASIZE_OF(srcsize);
2392         insn(floatingPointIntegerConversions(DATASIZE_OF(srcsize), DATASIZE_OF(dstsize), FPIntConvOp_SCVTF, rn, vd));
2393     }
2394
2395     template<int datasize>
2396     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, RegisterID rm)
2397     {
2398         str<datasize>(rt, rn, rm, UXTX, 0);
2399     }
2400
2401     template<int datasize>
2402     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
2403     {
2404         CHECK_FP_MEMOP_DATASIZE();
2405         insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
2406     }
2407
2408     template<int datasize>
2409     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, unsigned pimm)
2410     {
2411         CHECK_FP_MEMOP_DATASIZE();
2412         insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, encodePositiveImmediate<datasize>(pimm), rn, rt));
2413     }
2414
2415     template<int datasize>
2416     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, PostIndex simm)
2417     {
2418         CHECK_FP_MEMOP_DATASIZE();
2419         insn(loadStoreRegisterPostIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, simm, rn, rt));
2420     }
2421
2422     template<int datasize>
2423     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, PreIndex simm)
2424     {
2425         CHECK_FP_MEMOP_DATASIZE();
2426         insn(loadStoreRegisterPreIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, simm, rn, rt));
2427     }
2428
2429     template<int datasize>
2430     ALWAYS_INLINE void stur(FPRegisterID rt, RegisterID rn, int simm)
2431     {
2432         CHECK_DATASIZE();
2433         insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, simm, rn, rt));
2434     }
2435
2436     template<int dstsize, int srcsize>
2437     ALWAYS_INLINE void ucvtf(FPRegisterID vd, RegisterID rn)
2438     {
2439         CHECK_DATASIZE_OF(dstsize);
2440         CHECK_DATASIZE_OF(srcsize);
2441         insn(floatingPointIntegerConversions(DATASIZE_OF(srcsize), DATASIZE_OF(dstsize), FPIntConvOp_UCVTF, rn, vd));
2442     }
2443
2444     // Admin methods:
2445
2446     AssemblerLabel labelIgnoringWatchpoints()
2447     {
2448         return m_buffer.label();
2449     }
2450
2451     AssemblerLabel labelForWatchpoint()
2452     {
2453         AssemblerLabel result = m_buffer.label();
2454         if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
2455             result = label();
2456         m_indexOfLastWatchpoint = result.m_offset;
2457         m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
2458         return result;
2459     }
2460
2461     AssemblerLabel label()
2462     {
2463         AssemblerLabel result = m_buffer.label();
2464         while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
2465             nop();
2466             result = m_buffer.label();
2467         }
2468         return result;
2469     }
2470
2471     AssemblerLabel align(int alignment)
2472     {
2473         ASSERT(!(alignment & 3));
2474         while (!m_buffer.isAligned(alignment))
2475             brk(0);
2476         return label();
2477     }
2478     
2479     static void* getRelocatedAddress(void* code, AssemblerLabel label)
2480     {
2481         ASSERT(label.isSet());
2482         return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + label.m_offset);
2483     }
2484     
2485     static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
2486     {
2487         return b.m_offset - a.m_offset;
2488     }
2489
2490     int executableOffsetFor(int location)
2491     {
2492         if (!location)
2493             return 0;
2494         return static_cast<int32_t*>(m_buffer.data())[location / sizeof(int32_t) - 1];
2495     }
2496     
2497     PassRefPtr<ExecutableMemoryHandle> executableCopy(VM& vm, void* ownerUID, JITCompilationEffort effort)
2498     {
2499         return m_buffer.executableCopy(vm, ownerUID, effort);
2500     }
2501
2502     void* unlinkedCode() { return m_buffer.data(); }
2503     size_t codeSize() const { return m_buffer.codeSize(); }
2504
2505     static unsigned getCallReturnOffset(AssemblerLabel call)
2506     {
2507         ASSERT(call.isSet());
2508         return call.m_offset;
2509     }
2510
2511     // Linking & patching:
2512     //
2513     // 'link' and 'patch' methods are for use on unprotected code - such as the code
2514     // within the AssemblerBuffer, and code being patched by the patch buffer. Once
2515     // code has been finalized it is (platform support permitting) within a non-
2516     // writable region of memory; to modify the code in an execute-only execuable
2517     // pool the 'repatch' and 'relink' methods should be used.
2518
2519     void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition)
2520     {
2521         ASSERT(to.isSet());
2522         ASSERT(from.isSet());
2523         m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition));
2524     }
2525
2526     void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition, bool is64Bit, RegisterID compareRegister)
2527     {
2528         ASSERT(to.isSet());
2529         ASSERT(from.isSet());
2530         m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition, is64Bit, compareRegister));
2531     }
2532
2533     void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition, unsigned bitNumber, RegisterID compareRegister)
2534     {
2535         ASSERT(to.isSet());
2536         ASSERT(from.isSet());
2537         m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition, bitNumber, compareRegister));
2538     }
2539
2540     void linkJump(AssemblerLabel from, AssemblerLabel to)
2541     {
2542         ASSERT(from.isSet());
2543         ASSERT(to.isSet());
2544         relinkJumpOrCall<false>(addressOf(from), addressOf(to));
2545     }
2546     
2547     static void linkJump(void* code, AssemblerLabel from, void* to)
2548     {
2549         ASSERT(from.isSet());
2550         relinkJumpOrCall<false>(addressOf(code, from), to);
2551     }
2552
2553     static void linkCall(void* code, AssemblerLabel from, void* to)
2554     {
2555         ASSERT(from.isSet());
2556         linkJumpOrCall<true>(addressOf(code, from) - 1, to);
2557     }
2558
2559     static void linkPointer(void* code, AssemblerLabel where, void* valuePtr)
2560     {
2561         linkPointer(addressOf(code, where), valuePtr);
2562     }
2563
2564     static void replaceWithJump(void* where, void* to)
2565     {
2566         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(where)) >> 2;
2567         ASSERT(static_cast<int>(offset) == offset);
2568         *static_cast<int*>(where) = unconditionalBranchImmediate(false, static_cast<int>(offset));
2569         cacheFlush(where, sizeof(int));
2570     }
2571     
2572     static ptrdiff_t maxJumpReplacementSize()
2573     {
2574         return 4;
2575     }
2576     
2577     static void replaceWithLoad(void* where)
2578     {
2579         Datasize sf;
2580         AddOp op;
2581         SetFlags S;
2582         int shift;
2583         int imm12;
2584         RegisterID rn;
2585         RegisterID rd;
2586         if (disassembleAddSubtractImmediate(where, sf, op, S, shift, imm12, rn, rd)) {
2587             ASSERT(sf == Datasize_64);
2588             ASSERT(op == AddOp_ADD);
2589             ASSERT(!S);
2590             ASSERT(!shift);
2591             ASSERT(!(imm12 & ~0xff8));
2592             *static_cast<int*>(where) = loadStoreRegisterUnsignedImmediate(MemOpSize_64, false, MemOp_LOAD, encodePositiveImmediate<64>(imm12), rn, rd);
2593             cacheFlush(where, sizeof(int));
2594         }
2595 #if !ASSERT_DISABLED
2596         else {
2597             MemOpSize size;
2598             bool V;
2599             MemOp opc;
2600             int imm12;
2601             RegisterID rn;
2602             RegisterID rt;
2603             ASSERT(disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt));
2604             ASSERT(size == MemOpSize_64);
2605             ASSERT(!V);
2606             ASSERT(opc == MemOp_LOAD);
2607             ASSERT(!(imm12 & ~0x1ff));
2608         }
2609 #endif
2610     }
2611
2612     static void replaceWithAddressComputation(void* where)
2613     {
2614         MemOpSize size;
2615         bool V;
2616         MemOp opc;
2617         int imm12;
2618         RegisterID rn;
2619         RegisterID rt;
2620         if (disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt)) {
2621             ASSERT(size == MemOpSize_64);
2622             ASSERT(!V);
2623             ASSERT(opc == MemOp_LOAD);
2624             ASSERT(!(imm12 & ~0x1ff));
2625             *static_cast<int*>(where) = addSubtractImmediate(Datasize_64, AddOp_ADD, DontSetFlags, 0, imm12 * sizeof(void*), rn, rt);
2626             cacheFlush(where, sizeof(int));
2627         }
2628 #if !ASSERT_DISABLED
2629         else {
2630             Datasize sf;
2631             AddOp op;
2632             SetFlags S;
2633             int shift;
2634             int imm12;
2635             RegisterID rn;
2636             RegisterID rd;
2637             ASSERT(disassembleAddSubtractImmediate(where, sf, op, S, shift, imm12, rn, rd));
2638             ASSERT(sf == Datasize_64);
2639             ASSERT(op == AddOp_ADD);
2640             ASSERT(!S);
2641             ASSERT(!shift);
2642             ASSERT(!(imm12 & ~0xff8));
2643         }
2644 #endif
2645     }
2646
2647     static void repatchPointer(void* where, void* valuePtr)
2648     {
2649         linkPointer(static_cast<int*>(where), valuePtr, true);
2650     }
2651
2652     static void setPointer(int* address, void* valuePtr, RegisterID rd, bool flush)
2653     {
2654         uintptr_t value = reinterpret_cast<uintptr_t>(valuePtr);
2655         address[0] = moveWideImediate(Datasize_64, MoveWideOp_Z, 0, getHalfword(value, 0), rd);
2656         address[1] = moveWideImediate(Datasize_64, MoveWideOp_K, 1, getHalfword(value, 1), rd);
2657         address[2] = moveWideImediate(Datasize_64, MoveWideOp_K, 2, getHalfword(value, 2), rd);
2658
2659         if (flush)
2660             cacheFlush(address, sizeof(int) * 3);
2661     }
2662
2663     static void repatchInt32(void* where, int32_t value)
2664     {
2665         int* address = static_cast<int*>(where);
2666
2667         Datasize sf;
2668         MoveWideOp opc;
2669         int hw;
2670         uint16_t imm16;
2671         RegisterID rd;
2672         bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rd);
2673         ASSERT_UNUSED(expected, expected && !sf && (opc == MoveWideOp_Z || opc == MoveWideOp_N) && !hw);
2674         ASSERT(checkMovk<Datasize_32>(address[1], 1, rd));
2675
2676         if (value >= 0) {
2677             address[0] = moveWideImediate(Datasize_32, MoveWideOp_Z, 0, getHalfword(value, 0), rd);
2678             address[1] = moveWideImediate(Datasize_32, MoveWideOp_K, 1, getHalfword(value, 1), rd);
2679         } else {
2680             address[0] = moveWideImediate(Datasize_32, MoveWideOp_N, 0, ~getHalfword(value, 0), rd);
2681             address[1] = moveWideImediate(Datasize_32, MoveWideOp_K, 1, getHalfword(value, 1), rd);
2682         }
2683
2684         cacheFlush(where, sizeof(int) * 2);
2685     }
2686
2687     static void* readPointer(void* where)
2688     {
2689         int* address = static_cast<int*>(where);
2690
2691         Datasize sf;
2692         MoveWideOp opc;
2693         int hw;
2694         uint16_t imm16;
2695         RegisterID rdFirst, rd;
2696
2697         bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rdFirst);
2698         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_Z && !hw);
2699         uintptr_t result = imm16;
2700
2701         expected = disassembleMoveWideImediate(address + 1, sf, opc, hw, imm16, rd);
2702         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 1 && rd == rdFirst);
2703         result |= static_cast<uintptr_t>(imm16) << 16;
2704
2705         expected = disassembleMoveWideImediate(address + 2, sf, opc, hw, imm16, rd);
2706         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 2 && rd == rdFirst);
2707         result |= static_cast<uintptr_t>(imm16) << 32;
2708
2709         return reinterpret_cast<void*>(result);
2710     }
2711
2712     static void* readCallTarget(void* from)
2713     {
2714         return readPointer(reinterpret_cast<int*>(from) - 4);
2715     }
2716
2717     static void relinkJump(void* from, void* to)
2718     {
2719         relinkJumpOrCall<false>(reinterpret_cast<int*>(from), to);
2720         cacheFlush(from, sizeof(int));
2721     }
2722     
2723     static void relinkCall(void* from, void* to)
2724     {
2725         relinkJumpOrCall<true>(reinterpret_cast<int*>(from) - 1, to);
2726         cacheFlush(reinterpret_cast<int*>(from) - 1, sizeof(int));
2727     }
2728     
2729     static void repatchCompact(void* where, int32_t value)
2730     {
2731         ASSERT(!(value & ~0x3ff8));
2732
2733         MemOpSize size;
2734         bool V;
2735         MemOp opc;
2736         int imm12;
2737         RegisterID rn;
2738         RegisterID rt;
2739         bool expected = disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt);
2740         ASSERT_UNUSED(expected, expected && size >= MemOpSize_32 && !V && opc == MemOp_LOAD); // expect 32/64 bit load to GPR.
2741
2742         if (size == MemOpSize_32)
2743             imm12 = encodePositiveImmediate<32>(value);
2744         else
2745             imm12 = encodePositiveImmediate<64>(value);
2746         *static_cast<int*>(where) = loadStoreRegisterUnsignedImmediate(size, V, opc, imm12, rn, rt);
2747
2748         cacheFlush(where, sizeof(int));
2749     }
2750
2751     unsigned debugOffset() { return m_buffer.debugOffset(); }
2752
2753     static void cacheFlush(void* code, size_t size)
2754     {
2755 #if OS(IOS)
2756         sys_cache_control(kCacheFunctionPrepareForExecution, code, size);
2757 #else
2758 #error "The cacheFlush support is missing on this platform."
2759 #endif
2760     }
2761
2762     // Assembler admin methods:
2763
2764     int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JUMP_ENUM_SIZE(jumpType) - JUMP_ENUM_SIZE(jumpLinkType); }
2765
2766     static ALWAYS_INLINE bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b)
2767     {
2768         return a.from() < b.from();
2769     }
2770
2771     bool canCompact(JumpType jumpType)
2772     {
2773         // Fixed jumps cannot be compacted
2774         return (jumpType == JumpNoCondition) || (jumpType == JumpCondition) || (jumpType == JumpCompareAndBranch) || (jumpType == JumpTestBit);
2775     }
2776
2777     JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to)
2778     {
2779         switch (jumpType) {
2780         case JumpFixed:
2781             return LinkInvalid;
2782         case JumpNoConditionFixedSize:
2783             return LinkJumpNoCondition;
2784         case JumpConditionFixedSize:
2785             return LinkJumpCondition;
2786         case JumpCompareAndBranchFixedSize:
2787             return LinkJumpCompareAndBranch;
2788         case JumpTestBitFixedSize:
2789             return LinkJumpTestBit;
2790         case JumpNoCondition:
2791             return LinkJumpNoCondition;
2792         case JumpCondition: {
2793             ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
2794             ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
2795             intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
2796
2797             if (((relative << 43) >> 43) == relative)
2798                 return LinkJumpConditionDirect;
2799
2800             return LinkJumpCondition;
2801             }
2802         case JumpCompareAndBranch:  {
2803             ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
2804             ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
2805             intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
2806
2807             if (((relative << 43) >> 43) == relative)
2808                 return LinkJumpCompareAndBranchDirect;
2809
2810             return LinkJumpCompareAndBranch;
2811         }
2812         case JumpTestBit:   {
2813             ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
2814             ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
2815             intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
2816
2817             if (((relative << 50) >> 50) == relative)
2818                 return LinkJumpTestBitDirect;
2819
2820             return LinkJumpTestBit;
2821         }
2822         default:
2823             ASSERT_NOT_REACHED();
2824         }
2825
2826         return LinkJumpNoCondition;
2827     }
2828
2829     JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to)
2830     {
2831         JumpLinkType linkType = computeJumpType(record.type(), from, to);
2832         record.setLinkType(linkType);
2833         return linkType;
2834     }
2835
2836     void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset)
2837     {
2838         int32_t ptr = regionStart / sizeof(int32_t);
2839         const int32_t end = regionEnd / sizeof(int32_t);
2840         int32_t* offsets = static_cast<int32_t*>(m_buffer.data());
2841         while (ptr < end)
2842             offsets[ptr++] = offset;
2843     }
2844
2845     Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink()
2846     {
2847         std::sort(m_jumpsToLink.begin(), m_jumpsToLink.end(), linkRecordSourceComparator);
2848         return m_jumpsToLink;
2849     }
2850
2851     void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, uint8_t* to)
2852     {
2853         switch (record.linkType()) {
2854         case LinkJumpNoCondition:
2855             linkJumpOrCall<false>(reinterpret_cast<int*>(from), to);
2856             break;
2857         case LinkJumpConditionDirect:
2858             linkConditionalBranch<true>(record.condition(), reinterpret_cast<int*>(from), to);
2859             break;
2860         case LinkJumpCondition:
2861             linkConditionalBranch<false>(record.condition(), reinterpret_cast<int*>(from) - 1, to);
2862             break;
2863         case LinkJumpCompareAndBranchDirect:
2864             linkCompareAndBranch<true>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from), to);
2865             break;
2866         case LinkJumpCompareAndBranch:
2867             linkCompareAndBranch<false>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, to);
2868             break;
2869         case LinkJumpTestBitDirect:
2870             linkTestAndBranch<true>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from), to);
2871             break;
2872         case LinkJumpTestBit:
2873             linkTestAndBranch<false>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, to);
2874             break;
2875         default:
2876             ASSERT_NOT_REACHED();
2877             break;
2878         }
2879     }
2880
2881 private:
2882     template<Datasize size>
2883     static bool checkMovk(int insn, int _hw, RegisterID _rd)
2884     {
2885         Datasize sf;
2886         MoveWideOp opc;
2887         int hw;
2888         uint16_t imm16;
2889         RegisterID rd;
2890         bool expected = disassembleMoveWideImediate(&insn, sf, opc, hw, imm16, rd);
2891
2892         return expected
2893             && sf == size
2894             && opc == MoveWideOp_K
2895             && hw == _hw
2896             && rd == _rd;
2897     }
2898
2899     static void linkPointer(int* address, void* valuePtr, bool flush = false)
2900     {
2901         Datasize sf;
2902         MoveWideOp opc;
2903         int hw;
2904         uint16_t imm16;
2905         RegisterID rd;
2906         bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rd);
2907         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_Z && !hw);
2908         ASSERT(checkMovk<Datasize_64>(address[1], 1, rd));
2909         ASSERT(checkMovk<Datasize_64>(address[2], 2, rd));
2910
2911         setPointer(address, valuePtr, rd, flush);
2912     }
2913
2914     template<bool isCall>
2915     static void linkJumpOrCall(int* from, void* to)
2916     {
2917         bool link;
2918         int imm26;
2919         bool isUnconditionalBranchImmediateOrNop = disassembleUnconditionalBranchImmediate(from, link, imm26) || disassembleNop(from);
2920
2921         ASSERT_UNUSED(isUnconditionalBranchImmediateOrNop, isUnconditionalBranchImmediateOrNop);
2922         ASSERT_UNUSED(isCall, (link == isCall) || disassembleNop(from));
2923         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
2924         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
2925         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
2926         ASSERT(static_cast<int>(offset) == offset);
2927
2928         *from = unconditionalBranchImmediate(isCall, static_cast<int>(offset));
2929     }
2930
2931     template<bool isDirect>
2932     static void linkCompareAndBranch(Condition condition, bool is64Bit, RegisterID rt, int* from, void* to)
2933     {
2934         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
2935         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
2936         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
2937         ASSERT(((offset << 38) >> 38) == offset);
2938
2939         bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
2940         ASSERT(!isDirect || useDirect);
2941
2942         if (useDirect || isDirect) {
2943             *from = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, condition == ConditionNE, static_cast<int>(offset), rt);
2944             if (!isDirect)
2945                 *(from + 1) = nopPseudo();
2946         } else {
2947             *from = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, invert(condition) == ConditionNE, 2, rt);
2948             linkJumpOrCall<false>(from + 1, to);
2949         }
2950     }
2951
2952     template<bool isDirect>
2953     static void linkConditionalBranch(Condition condition, int* from, void* to)
2954     {
2955         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
2956         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
2957         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
2958         ASSERT(((offset << 38) >> 38) == offset);
2959
2960         bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
2961         ASSERT(!isDirect || useDirect);
2962
2963         if (useDirect || isDirect) {
2964             *from = conditionalBranchImmediate(static_cast<int>(offset), condition);
2965             if (!isDirect)
2966                 *(from + 1) = nopPseudo();
2967         } else {
2968             *from = conditionalBranchImmediate(2, invert(condition));
2969             linkJumpOrCall<false>(from + 1, to);
2970         }
2971     }
2972
2973     template<bool isDirect>
2974     static void linkTestAndBranch(Condition condition, unsigned bitNumber, RegisterID rt, int* from, void* to)
2975     {
2976         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
2977         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
2978         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
2979         ASSERT(static_cast<int>(offset) == offset);
2980         ASSERT(((offset << 38) >> 38) == offset);
2981
2982         bool useDirect = ((offset << 50) >> 50) == offset; // Fits in 14 bits
2983         ASSERT(!isDirect || useDirect);
2984
2985         if (useDirect || isDirect) {
2986             *from = testAndBranchImmediate(condition == ConditionNE, static_cast<int>(bitNumber), static_cast<int>(offset), rt);
2987             if (!isDirect)
2988                 *(from + 1) = nopPseudo();
2989         } else {
2990             *from = testAndBranchImmediate(invert(condition) == ConditionNE, static_cast<int>(bitNumber), 2, rt);
2991             linkJumpOrCall<false>(from + 1, to);
2992         }
2993     }
2994
2995     template<bool isCall>
2996     static void relinkJumpOrCall(int* from, void* to)
2997     {
2998         if (!isCall && disassembleNop(from)) {
2999             unsigned op01;
3000             int imm19;
3001             Condition condition;
3002             bool isConditionalBranchImmediate = disassembleConditionalBranchImmediate(from - 1, op01, imm19, condition);
3003
3004             if (isConditionalBranchImmediate) {
3005                 ASSERT_UNUSED(op01, !op01);
3006                 ASSERT_UNUSED(isCall, !isCall);
3007
3008                 if (imm19 == 8)
3009                     condition = invert(condition);
3010
3011                 linkConditionalBranch<false>(condition, from - 1, to);
3012                 return;
3013             }
3014
3015             Datasize opSize;
3016             bool op;
3017             RegisterID rt;
3018             bool isCompareAndBranchImmediate = disassembleCompareAndBranchImmediate(from - 1, opSize, op, imm19, rt);
3019
3020             if (isCompareAndBranchImmediate) {
3021                 if (imm19 == 8)
3022                     op = !op;
3023
3024                 linkCompareAndBranch<false>(op ? ConditionNE : ConditionEQ, opSize == Datasize_64, rt, from - 1, to);
3025                 return;
3026             }
3027
3028             int imm14;
3029             unsigned bitNumber;
3030             bool isTestAndBranchImmediate = disassembleTestAndBranchImmediate(from - 1, op, bitNumber, imm14, rt);
3031
3032             if (isTestAndBranchImmediate) {
3033                 if (imm14 == 8)
3034                     op = !op;
3035
3036                 linkTestAndBranch<false>(op ? ConditionNE : ConditionEQ, bitNumber, rt, from - 1, to);
3037                 return;
3038             }
3039         }
3040
3041         linkJumpOrCall<isCall>(from, to);
3042     }
3043
3044     static int* addressOf(void* code, AssemblerLabel label)
3045     {
3046         return reinterpret_cast<int*>(static_cast<char*>(code) + label.m_offset);
3047     }
3048
3049     int* addressOf(AssemblerLabel label)
3050     {
3051         return addressOf(m_buffer.data(), label);
3052     }
3053
3054     static RegisterID disassembleXOrSp(int reg) { return reg == 31 ? ARM64Registers::sp : static_cast<RegisterID>(reg); }
3055     static RegisterID disassembleXOrZr(int reg) { return reg == 31 ? ARM64Registers::zr : static_cast<RegisterID>(reg); }
3056     static RegisterID disassembleXOrZrOrSp(bool useZr, int reg) { return reg == 31 ? (useZr ? ARM64Registers::zr : ARM64Registers::sp) : static_cast<RegisterID>(reg); }
3057
3058     static bool disassembleAddSubtractImmediate(void* address, Datasize& sf, AddOp& op, SetFlags& S, int& shift, int& imm12, RegisterID& rn, RegisterID& rd)
3059     {
3060         int insn = *static_cast<int*>(address);
3061         sf = static_cast<Datasize>((insn >> 31) & 1);
3062         op = static_cast<AddOp>((insn >> 30) & 1);
3063         S = static_cast<SetFlags>((insn >> 29) & 1);
3064         shift = (insn >> 22) & 3;
3065         imm12 = (insn >> 10) & 0x3ff;
3066         rn = disassembleXOrSp((insn >> 5) & 0x1f);
3067         rd = disassembleXOrZrOrSp(S, insn & 0x1f);
3068         return (insn & 0x1f000000) == 0x11000000;
3069     }
3070
3071     static bool disassembleLoadStoreRegisterUnsignedImmediate(void* address, MemOpSize& size, bool& V, MemOp& opc, int& imm12, RegisterID& rn, RegisterID& rt)
3072     {
3073         int insn = *static_cast<int*>(address);
3074         size = static_cast<MemOpSize>((insn >> 30) & 3);
3075         V = (insn >> 26) & 1;
3076         opc = static_cast<MemOp>((insn >> 22) & 3);
3077         imm12 = (insn >> 10) & 0xfff;
3078         rn = disassembleXOrSp((insn >> 5) & 0x1f);
3079         rt = disassembleXOrZr(insn & 0x1f);
3080         return (insn & 0x3b000000) == 0x39000000;
3081     }
3082
3083     static bool disassembleMoveWideImediate(void* address, Datasize& sf, MoveWideOp& opc, int& hw, uint16_t& imm16, RegisterID& rd)
3084     {
3085         int insn = *static_cast<int*>(address);
3086         sf = static_cast<Datasize>((insn >> 31) & 1);
3087         opc = static_cast<MoveWideOp>((insn >> 29) & 3);
3088         hw = (insn >> 21) & 3;
3089         imm16 = insn >> 5;
3090         rd = disassembleXOrZr(insn & 0x1f);
3091         return (insn & 0x1f800000) == 0x12800000;
3092     }
3093
3094     static bool disassembleNop(void* address)
3095     {
3096         unsigned insn = *static_cast<unsigned*>(address);
3097         return insn == 0xd503201f;
3098     }
3099
3100     static bool disassembleCompareAndBranchImmediate(void* address, Datasize& sf, bool& op, int& imm19, RegisterID& rt)
3101     {
3102         int insn = *static_cast<int*>(address);
3103         sf = static_cast<Datasize>((insn >> 31) & 1);
3104         op = (insn >> 24) & 0x1;
3105         imm19 = (insn << 8) >> 13;
3106         rt = static_cast<RegisterID>(insn & 0x1f);
3107         return (insn & 0x7e000000) == 0x34000000;
3108         
3109     }
3110
3111     static bool disassembleConditionalBranchImmediate(void* address, unsigned& op01, int& imm19, Condition &condition)
3112     {
3113         int insn = *static_cast<int*>(address);
3114         op01 = ((insn >> 23) & 0x2) | ((insn >> 4) & 0x1);
3115         imm19 = (insn << 8) >> 13;
3116         condition = static_cast<Condition>(insn & 0xf);
3117         return (insn & 0xfe000000) == 0x54000000;
3118     }
3119
3120     static bool disassembleTestAndBranchImmediate(void* address, bool& op, unsigned& bitNumber, int& imm14, RegisterID& rt)
3121     {
3122         int insn = *static_cast<int*>(address);
3123         op = (insn >> 24) & 0x1;
3124         imm14 = (insn << 13) >> 18;
3125         bitNumber = static_cast<unsigned>((((insn >> 26) & 0x20)) | ((insn > 19) & 0x1f));
3126         rt = static_cast<RegisterID>(insn & 0x1f);
3127         return (insn & 0x7e000000) == 0x36000000;
3128         
3129     }
3130
3131     static bool disassembleUnconditionalBranchImmediate(void* address, bool& op, int& imm26)
3132     {
3133         int insn = *static_cast<int*>(address);
3134         op = (insn >> 31) & 1;
3135         imm26 = (insn << 6) >> 6;
3136         return (insn & 0x7c000000) == 0x14000000;
3137     }
3138
3139     static int xOrSp(RegisterID reg) { ASSERT(!isZr(reg)); return reg; }
3140     static int xOrZr(RegisterID reg) { ASSERT(!isSp(reg)); return reg & 31; }
3141     static FPRegisterID xOrZrAsFPR(RegisterID reg) { return static_cast<FPRegisterID>(xOrZr(reg)); }
3142     static int xOrZrOrSp(bool useZr, RegisterID reg) { return useZr ? xOrZr(reg) : xOrSp(reg); }
3143
3144     ALWAYS_INLINE void insn(int instruction)
3145     {
3146         m_buffer.putInt(instruction);
3147     }
3148
3149     ALWAYS_INLINE static int addSubtractExtendedRegister(Datasize sf, AddOp op, SetFlags S, RegisterID rm, ExtendType option, int imm3, RegisterID rn, RegisterID rd)
3150     {
3151         ASSERT(imm3 < 5);
3152         // The only allocated values for opt is 0.
3153         const int opt = 0;
3154         return (0x0b200000 | sf << 31 | op << 30 | S << 29 | opt << 22 | xOrZr(rm) << 16 | option << 13 | (imm3 & 0x7) << 10 | xOrSp(rn) << 5 | xOrZrOrSp(S, rd));
3155     }
3156
3157     ALWAYS_INLINE static int addSubtractImmediate(Datasize sf, AddOp op, SetFlags S, int shift, int imm12, RegisterID rn, RegisterID rd)
3158     {
3159         ASSERT(shift < 2);
3160         ASSERT(isUInt12(imm12));
3161         return (0x11000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | (imm12 & 0xfff) << 10 | xOrSp(rn) << 5 | xOrZrOrSp(S, rd));
3162     }
3163
3164     ALWAYS_INLINE static int addSubtractShiftedRegister(Datasize sf, AddOp op, SetFlags S, ShiftType shift, RegisterID rm, int imm6, RegisterID rn, RegisterID rd)
3165     {
3166         ASSERT(shift < 3);
3167         ASSERT(!(imm6 & (sf ? ~63 : ~31)));
3168         return (0x0b000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | xOrZr(rm) << 16 | (imm6 & 0x3f) << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3169     }
3170
3171     ALWAYS_INLINE static int addSubtractWithCarry(Datasize sf, AddOp op, SetFlags S, RegisterID rm, RegisterID rn, RegisterID rd)
3172     {
3173         const int opcode2 = 0;
3174         return (0x1a000000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | opcode2 << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3175     }
3176
3177     ALWAYS_INLINE static int bitfield(Datasize sf, BitfieldOp opc, int immr, int imms, RegisterID rn, RegisterID rd)
3178     {
3179         ASSERT(immr < (sf ? 64 : 32));
3180         ASSERT(imms < (sf ? 64 : 32));
3181         const int N = sf;
3182         return (0x13000000 | sf << 31 | opc << 29 | N << 22 | immr << 16 | imms << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3183     }
3184
3185     // 'op' means negate
3186     ALWAYS_INLINE static int compareAndBranchImmediate(Datasize sf, bool op, int32_t imm19, RegisterID rt)
3187     {
3188         ASSERT(imm19 == (imm19 << 13) >> 13);
3189         return (0x34000000 | sf << 31 | op << 24 | (imm19 & 0x7ffff) << 5 | xOrZr(rt));
3190     }
3191
3192     ALWAYS_INLINE static int conditionalBranchImmediate(int32_t imm19, Condition cond)
3193     {
3194         ASSERT(imm19 == (imm19 << 13) >> 13);
3195         ASSERT(!(cond & ~15));
3196         // The only allocated values for o1 & o0 are 0.
3197         const int o1 = 0;
3198         const int o0 = 0;
3199         return (0x54000000 | o1 << 24 | (imm19 & 0x7ffff) << 5 | o0 << 4 | cond);
3200     }
3201
3202     ALWAYS_INLINE static int conditionalCompareImmediate(Datasize sf, AddOp op, int imm5, Condition cond, RegisterID rn, int nzcv)
3203     {
3204         ASSERT(!(imm5 & ~0x1f));
3205         ASSERT(nzcv < 16);
3206         const int S = 1;
3207         const int o2 = 0;
3208         const int o3 = 0;
3209         return (0x1a400800 | sf << 31 | op << 30 | S << 29 | (imm5 & 0x1f) << 16 | cond << 12 | o2 << 10 | xOrZr(rn) << 5 | o3 << 4 | nzcv);
3210     }
3211
3212     ALWAYS_INLINE static int conditionalCompareRegister(Datasize sf, AddOp op, RegisterID rm, Condition cond, RegisterID rn, int nzcv)
3213     {
3214         ASSERT(nzcv < 16);
3215         const int S = 1;
3216         const int o2 = 0;
3217         const int o3 = 0;
3218         return (0x1a400000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | cond << 12 | o2 << 10 | xOrZr(rn) << 5 | o3 << 4 | nzcv);
3219     }
3220
3221     // 'op' means negate
3222     // 'op2' means increment
3223     ALWAYS_INLINE static int conditionalSelect(Datasize sf, bool op, RegisterID rm, Condition cond, bool op2, RegisterID rn, RegisterID rd)
3224     {
3225         const int S = 0;
3226         return (0x1a800000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | cond << 12 | op2 << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3227     }
3228
3229     ALWAYS_INLINE static int dataProcessing1Source(Datasize sf, DataOp1Source opcode, RegisterID rn, RegisterID rd)
3230     {
3231         const int S = 0;
3232         const int opcode2 = 0;
3233         return (0x5ac00000 | sf << 31 | S << 29 | opcode2 << 16 | opcode << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3234     }
3235
3236     ALWAYS_INLINE static int dataProcessing2Source(Datasize sf, RegisterID rm, DataOp2Source opcode, RegisterID rn, RegisterID rd)
3237     {
3238         const int S = 0;
3239         return (0x1ac00000 | sf << 31 | S << 29 | xOrZr(rm) << 16 | opcode << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3240     }
3241
3242     ALWAYS_INLINE static int dataProcessing3Source(Datasize sf, DataOp3Source opcode, RegisterID rm, RegisterID ra, RegisterID rn, RegisterID rd)
3243     {
3244         int op54 = opcode >> 4;
3245         int op31 = (opcode >> 1) & 7;
3246         int op0 = opcode & 1;
3247         return (0x1b000000 | sf << 31 | op54 << 29 | op31 << 21 | xOrZr(rm) << 16 | op0 << 15 | xOrZr(ra) << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3248     }
3249
3250     ALWAYS_INLINE static int excepnGeneration(ExcepnOp opc, uint16_t imm16, int LL)
3251     {
3252         ASSERT((opc == ExcepnOp_BREAKPOINT || opc == ExcepnOp_HALT) ? !LL : (LL && (LL < 4)));
3253         const int op2 = 0;
3254         return (0xd4000000 | opc << 21 | imm16 << 5 | op2 << 2 | LL);
3255     }
3256
3257     ALWAYS_INLINE static int extract(Datasize sf, RegisterID rm, int imms, RegisterID rn, RegisterID rd)
3258     {
3259         ASSERT(imms < (sf ? 64 : 32));
3260         const int op21 = 0;
3261         const int N = sf;
3262         const int o0 = 0;
3263         return (0x13800000 | sf << 31 | op21 << 29 | N << 22 | o0 << 21 | xOrZr(rm) << 16 | imms << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3264     }
3265
3266     ALWAYS_INLINE static int floatingPointCompare(Datasize type, FPRegisterID rm, FPRegisterID rn, FPCmpOp opcode2)
3267     {
3268         const int M = 0;
3269         const int S = 0;
3270         const int op = 0;
3271         return (0x1e202000 | M << 31 | S << 29 | type << 22 | rm << 16 | op << 14 | rn << 5 | opcode2);
3272     }
3273
3274     ALWAYS_INLINE static int floatingPointConditionalCompare(Datasize type, FPRegisterID rm, Condition cond, FPRegisterID rn, FPCondCmpOp op, int nzcv)
3275     {
3276         ASSERT(nzcv < 16);
3277         const int M = 0;
3278         const int S = 0;
3279         return (0x1e200400 | M << 31 | S << 29 | type << 22 | rm << 16 | cond << 12 | rn << 5 | op << 4 | nzcv);
3280     }
3281
3282     ALWAYS_INLINE static int floatingPointConditionalSelect(Datasize type, FPRegisterID rm, Condition cond, FPRegisterID rn, FPRegisterID rd)
3283     {
3284         const int M = 0;
3285         const int S = 0;
3286         return (0x1e200c00 | M << 31 | S << 29 | type << 22 | rm << 16 | cond << 12 | rn << 5 | rd);
3287     }
3288
3289     ALWAYS_INLINE static int floatingPointImmediate(Datasize type, int imm8, FPRegisterID rd)
3290     {
3291         const int M = 0;
3292         const int S = 0;
3293         const int imm5 = 0;
3294         return (0x1e201000 | M << 31 | S << 29 | type << 22 | (imm8 & 0xff) << 13 | imm5 << 5 | rd);
3295     }
3296
3297     ALWAYS_INLINE static int floatingPointIntegerConversions(Datasize sf, Datasize type, FPIntConvOp rmodeOpcode, FPRegisterID rn, FPRegisterID rd)
3298     {
3299         const int S = 0;
3300         return (0x1e200000 | sf << 31 | S << 29 | type << 22 | rmodeOpcode << 16 | rn << 5 | rd);
3301     }
3302
3303     ALWAYS_INLINE static int floatingPointIntegerConversions(Datasize sf, Datasize type, FPIntConvOp rmodeOpcode, FPRegisterID rn, RegisterID rd)
3304     {
3305         return floatingPointIntegerConversions(sf, type, rmodeOpcode, rn, xOrZrAsFPR(rd));
3306     }
3307
3308     ALWAYS_INLINE static int floatingPointIntegerConversions(Datasize sf, Datasize type, FPIntConvOp rmodeOpcode, RegisterID rn, FPRegisterID rd)
3309     {
3310         return floatingPointIntegerConversions(sf, type, rmodeOpcode, xOrZrAsFPR(rn), rd);
3311     }
3312
3313     ALWAYS_INLINE static int floatingPointDataProcessing1Source(Datasize type, FPDataOp1Source opcode, FPRegisterID rn, FPRegisterID rd)
3314     {
3315         const int M = 0;
3316         const int S = 0;
3317         return (0x1e204000 | M << 31 | S << 29 | type << 22 | opcode << 15 | rn << 5 | rd);