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