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