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