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