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