86f13ed9e7b24fc4ba7bc75e706b841dfe2c3230
[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 void replaceWithLoad(void* where)
2517     {
2518         Datasize sf;
2519         AddOp op;
2520         SetFlags S;
2521         int shift;
2522         int imm12;
2523         RegisterID rn;
2524         RegisterID rd;
2525         if (disassembleAddSubtractImmediate(where, sf, op, S, shift, imm12, rn, rd)) {
2526             ASSERT(sf == Datasize_64);
2527             ASSERT(op == AddOp_ADD);
2528             ASSERT(!S);
2529             ASSERT(!shift);
2530             ASSERT(!(imm12 & ~0xff8));
2531             int insn = loadStoreRegisterUnsignedImmediate(MemOpSize_64, false, MemOp_LOAD, encodePositiveImmediate<64>(imm12), rn, rd);
2532             performJITMemcpy(where, &insn, sizeof(int));
2533             cacheFlush(where, sizeof(int));
2534         }
2535 #if !ASSERT_DISABLED
2536         else {
2537             MemOpSize size;
2538             bool V;
2539             MemOp opc;
2540             int imm12;
2541             RegisterID rn;
2542             RegisterID rt;
2543             ASSERT(disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt));
2544             ASSERT(size == MemOpSize_64);
2545             ASSERT(!V);
2546             ASSERT(opc == MemOp_LOAD);
2547             ASSERT(!(imm12 & ~0x1ff));
2548         }
2549 #endif
2550     }
2551
2552     static void replaceWithAddressComputation(void* where)
2553     {
2554         MemOpSize size;
2555         bool V;
2556         MemOp opc;
2557         int imm12;
2558         RegisterID rn;
2559         RegisterID rt;
2560         if (disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt)) {
2561             ASSERT(size == MemOpSize_64);
2562             ASSERT(!V);
2563             ASSERT(opc == MemOp_LOAD);
2564             ASSERT(!(imm12 & ~0x1ff));
2565             int insn = addSubtractImmediate(Datasize_64, AddOp_ADD, DontSetFlags, 0, imm12 * sizeof(void*), rn, rt);
2566             performJITMemcpy(where, &insn, sizeof(int));
2567             cacheFlush(where, sizeof(int));
2568         }
2569 #if !ASSERT_DISABLED
2570         else {
2571             Datasize sf;
2572             AddOp op;
2573             SetFlags S;
2574             int shift;
2575             int imm12;
2576             RegisterID rn;
2577             RegisterID rd;
2578             ASSERT(disassembleAddSubtractImmediate(where, sf, op, S, shift, imm12, rn, rd));
2579             ASSERT(sf == Datasize_64);
2580             ASSERT(op == AddOp_ADD);
2581             ASSERT(!S);
2582             ASSERT(!shift);
2583             ASSERT(!(imm12 & ~0xff8));
2584         }
2585 #endif
2586     }
2587
2588     static void repatchPointer(void* where, void* valuePtr)
2589     {
2590         linkPointer(static_cast<int*>(where), valuePtr, true);
2591     }
2592
2593     static void setPointer(int* address, void* valuePtr, RegisterID rd, bool flush)
2594     {
2595         uintptr_t value = reinterpret_cast<uintptr_t>(valuePtr);
2596         int buffer[3];
2597         buffer[0] = moveWideImediate(Datasize_64, MoveWideOp_Z, 0, getHalfword(value, 0), rd);
2598         buffer[1] = moveWideImediate(Datasize_64, MoveWideOp_K, 1, getHalfword(value, 1), rd);
2599         buffer[2] = moveWideImediate(Datasize_64, MoveWideOp_K, 2, getHalfword(value, 2), rd);
2600         performJITMemcpy(address, buffer, sizeof(int) * 3);
2601
2602         if (flush)
2603             cacheFlush(address, sizeof(int) * 3);
2604     }
2605
2606     static void repatchInt32(void* where, int32_t value)
2607     {
2608         int* address = static_cast<int*>(where);
2609
2610         Datasize sf;
2611         MoveWideOp opc;
2612         int hw;
2613         uint16_t imm16;
2614         RegisterID rd;
2615         bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rd);
2616         ASSERT_UNUSED(expected, expected && !sf && (opc == MoveWideOp_Z || opc == MoveWideOp_N) && !hw);
2617         ASSERT(checkMovk<Datasize_32>(address[1], 1, rd));
2618
2619         int buffer[2];
2620         if (value >= 0) {
2621             buffer[0] = moveWideImediate(Datasize_32, MoveWideOp_Z, 0, getHalfword(value, 0), rd);
2622             buffer[1] = moveWideImediate(Datasize_32, MoveWideOp_K, 1, getHalfword(value, 1), rd);
2623         } else {
2624             buffer[0] = moveWideImediate(Datasize_32, MoveWideOp_N, 0, ~getHalfword(value, 0), rd);
2625             buffer[1] = moveWideImediate(Datasize_32, MoveWideOp_K, 1, getHalfword(value, 1), rd);
2626         }
2627         performJITMemcpy(where, &buffer, sizeof(int) * 2);
2628
2629         cacheFlush(where, sizeof(int) * 2);
2630     }
2631
2632     static void* readPointer(void* where)
2633     {
2634         int* address = static_cast<int*>(where);
2635
2636         Datasize sf;
2637         MoveWideOp opc;
2638         int hw;
2639         uint16_t imm16;
2640         RegisterID rdFirst, rd;
2641
2642         bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rdFirst);
2643         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_Z && !hw);
2644         uintptr_t result = imm16;
2645
2646         expected = disassembleMoveWideImediate(address + 1, sf, opc, hw, imm16, rd);
2647         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 1 && rd == rdFirst);
2648         result |= static_cast<uintptr_t>(imm16) << 16;
2649
2650         expected = disassembleMoveWideImediate(address + 2, sf, opc, hw, imm16, rd);
2651         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 2 && rd == rdFirst);
2652         result |= static_cast<uintptr_t>(imm16) << 32;
2653
2654         return reinterpret_cast<void*>(result);
2655     }
2656
2657     static void* readCallTarget(void* from)
2658     {
2659         return readPointer(reinterpret_cast<int*>(from) - 4);
2660     }
2661
2662     // The static relink, repatch, and replace methods can use can
2663     // use |from| for both the write and executable address for call
2664     // and jump patching as they're modifying existing (linked) code,
2665     // so the address being provided is correct for relative address
2666     // computation.
2667     static void relinkJump(void* from, void* to)
2668     {
2669         relinkJumpOrCall<false>(reinterpret_cast<int*>(from), reinterpret_cast<const int*>(from), to);
2670         cacheFlush(from, sizeof(int));
2671     }
2672     
2673     static void relinkCall(void* from, void* to)
2674     {
2675         relinkJumpOrCall<true>(reinterpret_cast<int*>(from) - 1, reinterpret_cast<const int*>(from) - 1, to);
2676         cacheFlush(reinterpret_cast<int*>(from) - 1, sizeof(int));
2677     }
2678     
2679     static void repatchCompact(void* where, int32_t value)
2680     {
2681         ASSERT(!(value & ~0x3ff8));
2682
2683         MemOpSize size;
2684         bool V;
2685         MemOp opc;
2686         int imm12;
2687         RegisterID rn;
2688         RegisterID rt;
2689         bool expected = disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt);
2690         ASSERT_UNUSED(expected, expected && size >= MemOpSize_32 && !V && opc == MemOp_LOAD); // expect 32/64 bit load to GPR.
2691
2692         if (size == MemOpSize_32)
2693             imm12 = encodePositiveImmediate<32>(value);
2694         else
2695             imm12 = encodePositiveImmediate<64>(value);
2696         int insn = loadStoreRegisterUnsignedImmediate(size, V, opc, imm12, rn, rt);
2697         performJITMemcpy(where, &insn, sizeof(int));
2698
2699         cacheFlush(where, sizeof(int));
2700     }
2701
2702     unsigned debugOffset() { return m_buffer.debugOffset(); }
2703
2704 #if OS(LINUX) && COMPILER(GCC_OR_CLANG)
2705     static inline void linuxPageFlush(uintptr_t begin, uintptr_t end)
2706     {
2707         __builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
2708     }
2709 #endif
2710
2711     static void cacheFlush(void* code, size_t size)
2712     {
2713 #if OS(IOS)
2714         sys_cache_control(kCacheFunctionPrepareForExecution, code, size);
2715 #elif OS(LINUX)
2716         size_t page = pageSize();
2717         uintptr_t current = reinterpret_cast<uintptr_t>(code);
2718         uintptr_t end = current + size;
2719         uintptr_t firstPageEnd = (current & ~(page - 1)) + page;
2720
2721         if (end <= firstPageEnd) {
2722             linuxPageFlush(current, end);
2723             return;
2724         }
2725
2726         linuxPageFlush(current, firstPageEnd);
2727
2728         for (current = firstPageEnd; current + page < end; current += page)
2729             linuxPageFlush(current, current + page);
2730
2731         linuxPageFlush(current, end);
2732 #else
2733 #error "The cacheFlush support is missing on this platform."
2734 #endif
2735     }
2736
2737     // Assembler admin methods:
2738
2739     static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JUMP_ENUM_SIZE(jumpType) - JUMP_ENUM_SIZE(jumpLinkType); }
2740
2741     static ALWAYS_INLINE bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b)
2742     {
2743         return a.from() < b.from();
2744     }
2745
2746     static bool canCompact(JumpType jumpType)
2747     {
2748         // Fixed jumps cannot be compacted
2749         return (jumpType == JumpNoCondition) || (jumpType == JumpCondition) || (jumpType == JumpCompareAndBranch) || (jumpType == JumpTestBit);
2750     }
2751
2752     static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to)
2753     {
2754         switch (jumpType) {
2755         case JumpFixed:
2756             return LinkInvalid;
2757         case JumpNoConditionFixedSize:
2758             return LinkJumpNoCondition;
2759         case JumpConditionFixedSize:
2760             return LinkJumpCondition;
2761         case JumpCompareAndBranchFixedSize:
2762             return LinkJumpCompareAndBranch;
2763         case JumpTestBitFixedSize:
2764             return LinkJumpTestBit;
2765         case JumpNoCondition:
2766             return LinkJumpNoCondition;
2767         case JumpCondition: {
2768             ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
2769             ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
2770             intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
2771
2772             if (((relative << 43) >> 43) == relative)
2773                 return LinkJumpConditionDirect;
2774
2775             return LinkJumpCondition;
2776             }
2777         case JumpCompareAndBranch:  {
2778             ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
2779             ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
2780             intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
2781
2782             if (((relative << 43) >> 43) == relative)
2783                 return LinkJumpCompareAndBranchDirect;
2784
2785             return LinkJumpCompareAndBranch;
2786         }
2787         case JumpTestBit:   {
2788             ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
2789             ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
2790             intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
2791
2792             if (((relative << 50) >> 50) == relative)
2793                 return LinkJumpTestBitDirect;
2794
2795             return LinkJumpTestBit;
2796         }
2797         default:
2798             ASSERT_NOT_REACHED();
2799         }
2800
2801         return LinkJumpNoCondition;
2802     }
2803
2804     static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to)
2805     {
2806         JumpLinkType linkType = computeJumpType(record.type(), from, to);
2807         record.setLinkType(linkType);
2808         return linkType;
2809     }
2810
2811     Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink()
2812     {
2813         std::sort(m_jumpsToLink.begin(), m_jumpsToLink.end(), linkRecordSourceComparator);
2814         return m_jumpsToLink;
2815     }
2816
2817     static void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, const uint8_t* fromInstruction8, uint8_t* to)
2818     {
2819         const int* fromInstruction = reinterpret_cast<const int*>(fromInstruction8);
2820         switch (record.linkType()) {
2821         case LinkJumpNoCondition:
2822             linkJumpOrCall<false>(reinterpret_cast<int*>(from), fromInstruction, to);
2823             break;
2824         case LinkJumpConditionDirect:
2825             linkConditionalBranch<true>(record.condition(), reinterpret_cast<int*>(from), fromInstruction, to);
2826             break;
2827         case LinkJumpCondition:
2828             linkConditionalBranch<false>(record.condition(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to);
2829             break;
2830         case LinkJumpCompareAndBranchDirect:
2831             linkCompareAndBranch<true>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from), fromInstruction, to);
2832             break;
2833         case LinkJumpCompareAndBranch:
2834             linkCompareAndBranch<false>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to);
2835             break;
2836         case LinkJumpTestBitDirect:
2837             linkTestAndBranch<true>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from), fromInstruction, to);
2838             break;
2839         case LinkJumpTestBit:
2840             linkTestAndBranch<false>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to);
2841             break;
2842         default:
2843             ASSERT_NOT_REACHED();
2844             break;
2845         }
2846     }
2847
2848 private:
2849     template<Datasize size>
2850     static bool checkMovk(int insn, int _hw, RegisterID _rd)
2851     {
2852         Datasize sf;
2853         MoveWideOp opc;
2854         int hw;
2855         uint16_t imm16;
2856         RegisterID rd;
2857         bool expected = disassembleMoveWideImediate(&insn, sf, opc, hw, imm16, rd);
2858
2859         return expected
2860             && sf == size
2861             && opc == MoveWideOp_K
2862             && hw == _hw
2863             && rd == _rd;
2864     }
2865
2866     static void linkPointer(int* address, void* valuePtr, bool flush = false)
2867     {
2868         Datasize sf;
2869         MoveWideOp opc;
2870         int hw;
2871         uint16_t imm16;
2872         RegisterID rd;
2873         bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rd);
2874         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_Z && !hw);
2875         ASSERT(checkMovk<Datasize_64>(address[1], 1, rd));
2876         ASSERT(checkMovk<Datasize_64>(address[2], 2, rd));
2877
2878         setPointer(address, valuePtr, rd, flush);
2879     }
2880
2881     template<bool isCall>
2882     static void linkJumpOrCall(int* from, const int* fromInstruction, void* to)
2883     {
2884         bool link;
2885         int imm26;
2886         bool isUnconditionalBranchImmediateOrNop = disassembleUnconditionalBranchImmediate(from, link, imm26) || disassembleNop(from);
2887
2888         ASSERT_UNUSED(isUnconditionalBranchImmediateOrNop, isUnconditionalBranchImmediateOrNop);
2889         ASSERT_UNUSED(isCall, (link == isCall) || disassembleNop(from));
2890         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
2891         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
2892         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(fromInstruction)) >> 2;
2893         ASSERT(static_cast<int>(offset) == offset);
2894
2895         int insn = unconditionalBranchImmediate(isCall, static_cast<int>(offset));
2896         performJITMemcpy(from, &insn, sizeof(int));
2897     }
2898
2899     template<bool isDirect>
2900     static void linkCompareAndBranch(Condition condition, bool is64Bit, RegisterID rt, int* from, const int* fromInstruction, void* to)
2901     {
2902         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
2903         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
2904         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(fromInstruction)) >> 2;
2905         ASSERT(((offset << 38) >> 38) == offset);
2906
2907         bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
2908         ASSERT(!isDirect || useDirect);
2909
2910         if (useDirect || isDirect) {
2911             int insn = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, condition == ConditionNE, static_cast<int>(offset), rt);
2912             performJITMemcpy(from, &insn, sizeof(int));
2913             if (!isDirect) {
2914                 insn = nopPseudo();
2915                 performJITMemcpy(from + 1, &insn, sizeof(int));
2916             }
2917         } else {
2918             int insn = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, invert(condition) == ConditionNE, 2, rt);
2919             performJITMemcpy(from, &insn, sizeof(int));
2920             linkJumpOrCall<false>(from + 1, fromInstruction + 1, to);
2921         }
2922     }
2923
2924     template<bool isDirect>
2925     static void linkConditionalBranch(Condition condition, int* from, const int* fromInstruction, void* to)
2926     {
2927         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
2928         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
2929         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(fromInstruction)) >> 2;
2930         ASSERT(((offset << 38) >> 38) == offset);
2931
2932         bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
2933         ASSERT(!isDirect || useDirect);
2934
2935         if (useDirect || isDirect) {
2936             int insn = conditionalBranchImmediate(static_cast<int>(offset), condition);
2937             performJITMemcpy(from, &insn, sizeof(int));
2938             if (!isDirect) {
2939                 insn = nopPseudo();
2940                 performJITMemcpy(from + 1, &insn, sizeof(int));
2941             }
2942         } else {
2943             int insn = conditionalBranchImmediate(2, invert(condition));
2944             performJITMemcpy(from, &insn, sizeof(int));
2945             linkJumpOrCall<false>(from + 1, fromInstruction + 1, to);
2946         }
2947     }
2948
2949     template<bool isDirect>
2950     static void linkTestAndBranch(Condition condition, unsigned bitNumber, RegisterID rt, int* from, const int* fromInstruction, void* to)
2951     {
2952         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
2953         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
2954         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(fromInstruction)) >> 2;
2955         ASSERT(static_cast<int>(offset) == offset);
2956         ASSERT(((offset << 38) >> 38) == offset);
2957
2958         bool useDirect = ((offset << 50) >> 50) == offset; // Fits in 14 bits
2959         ASSERT(!isDirect || useDirect);
2960
2961         if (useDirect || isDirect) {
2962             int insn = testAndBranchImmediate(condition == ConditionNE, static_cast<int>(bitNumber), static_cast<int>(offset), rt);
2963             performJITMemcpy(from, &insn, sizeof(int));
2964             if (!isDirect) {
2965                 insn = nopPseudo();
2966                 performJITMemcpy(from + 1, &insn, sizeof(int));
2967             }
2968         } else {
2969             int insn = testAndBranchImmediate(invert(condition) == ConditionNE, static_cast<int>(bitNumber), 2, rt);
2970             performJITMemcpy(from, &insn, sizeof(int));
2971             linkJumpOrCall<false>(from + 1, fromInstruction + 1, to);
2972         }
2973     }
2974
2975     template<bool isCall>
2976     static void relinkJumpOrCall(int* from, const int* fromInstruction, void* to)
2977     {
2978         if (!isCall && disassembleNop(from)) {
2979             unsigned op01;
2980             int imm19;
2981             Condition condition;
2982             bool isConditionalBranchImmediate = disassembleConditionalBranchImmediate(from - 1, op01, imm19, condition);
2983
2984             if (isConditionalBranchImmediate) {
2985                 ASSERT_UNUSED(op01, !op01);
2986                 ASSERT_UNUSED(isCall, !isCall);
2987
2988                 if (imm19 == 8)
2989                     condition = invert(condition);
2990
2991                 linkConditionalBranch<false>(condition, from - 1, fromInstruction - 1, to);
2992                 return;
2993             }
2994
2995             Datasize opSize;
2996             bool op;
2997             RegisterID rt;
2998             bool isCompareAndBranchImmediate = disassembleCompareAndBranchImmediate(from - 1, opSize, op, imm19, rt);
2999
3000             if (isCompareAndBranchImmediate) {
3001                 if (imm19 == 8)
3002                     op = !op;
3003
3004                 linkCompareAndBranch<false>(op ? ConditionNE : ConditionEQ, opSize == Datasize_64, rt, from - 1, fromInstruction - 1, to);
3005                 return;
3006             }
3007
3008             int imm14;
3009             unsigned bitNumber;
3010             bool isTestAndBranchImmediate = disassembleTestAndBranchImmediate(from - 1, op, bitNumber, imm14, rt);
3011
3012             if (isTestAndBranchImmediate) {
3013                 if (imm14 == 8)
3014                     op = !op;
3015
3016                 linkTestAndBranch<false>(op ? ConditionNE : ConditionEQ, bitNumber, rt, from - 1, fromInstruction - 1, to);
3017                 return;
3018             }
3019         }
3020
3021         linkJumpOrCall<isCall>(from, fromInstruction, to);
3022     }
3023
3024     static int* addressOf(void* code, AssemblerLabel label)
3025     {
3026         return reinterpret_cast<int*>(static_cast<char*>(code) + label.m_offset);
3027     }
3028
3029     int* addressOf(AssemblerLabel label)
3030     {
3031         return addressOf(m_buffer.data(), label);
3032     }
3033
3034     static RegisterID disassembleXOrSp(int reg) { return reg == 31 ? ARM64Registers::sp : static_cast<RegisterID>(reg); }
3035     static RegisterID disassembleXOrZr(int reg) { return reg == 31 ? ARM64Registers::zr : static_cast<RegisterID>(reg); }
3036     static RegisterID disassembleXOrZrOrSp(bool useZr, int reg) { return reg == 31 ? (useZr ? ARM64Registers::zr : ARM64Registers::sp) : static_cast<RegisterID>(reg); }
3037
3038     static bool disassembleAddSubtractImmediate(void* address, Datasize& sf, AddOp& op, SetFlags& S, int& shift, int& imm12, RegisterID& rn, RegisterID& rd)
3039     {
3040         int insn = *static_cast<int*>(address);
3041         sf = static_cast<Datasize>((insn >> 31) & 1);
3042         op = static_cast<AddOp>((insn >> 30) & 1);
3043         S = static_cast<SetFlags>((insn >> 29) & 1);
3044         shift = (insn >> 22) & 3;
3045         imm12 = (insn >> 10) & 0x3ff;
3046         rn = disassembleXOrSp((insn >> 5) & 0x1f);
3047         rd = disassembleXOrZrOrSp(S, insn & 0x1f);
3048         return (insn & 0x1f000000) == 0x11000000;
3049     }
3050
3051     static bool disassembleLoadStoreRegisterUnsignedImmediate(void* address, MemOpSize& size, bool& V, MemOp& opc, int& imm12, RegisterID& rn, RegisterID& rt)
3052     {
3053         int insn = *static_cast<int*>(address);
3054         size = static_cast<MemOpSize>((insn >> 30) & 3);
3055         V = (insn >> 26) & 1;
3056         opc = static_cast<MemOp>((insn >> 22) & 3);
3057         imm12 = (insn >> 10) & 0xfff;
3058         rn = disassembleXOrSp((insn >> 5) & 0x1f);
3059         rt = disassembleXOrZr(insn & 0x1f);
3060         return (insn & 0x3b000000) == 0x39000000;
3061     }
3062
3063     static bool disassembleMoveWideImediate(void* address, Datasize& sf, MoveWideOp& opc, int& hw, uint16_t& imm16, RegisterID& rd)
3064     {
3065         int insn = *static_cast<int*>(address);
3066         sf = static_cast<Datasize>((insn >> 31) & 1);
3067         opc = static_cast<MoveWideOp>((insn >> 29) & 3);
3068         hw = (insn >> 21) & 3;
3069         imm16 = insn >> 5;
3070         rd = disassembleXOrZr(insn & 0x1f);
3071         return (insn & 0x1f800000) == 0x12800000;
3072     }
3073
3074     static bool disassembleNop(void* address)
3075     {
3076         unsigned insn = *static_cast<unsigned*>(address);
3077         return insn == 0xd503201f;
3078     }
3079
3080     static bool disassembleCompareAndBranchImmediate(void* address, Datasize& sf, bool& op, int& imm19, RegisterID& rt)
3081     {
3082         int insn = *static_cast<int*>(address);
3083         sf = static_cast<Datasize>((insn >> 31) & 1);
3084         op = (insn >> 24) & 0x1;
3085         imm19 = (insn << 8) >> 13;
3086         rt = static_cast<RegisterID>(insn & 0x1f);
3087         return (insn & 0x7e000000) == 0x34000000;
3088         
3089     }
3090
3091     static bool disassembleConditionalBranchImmediate(void* address, unsigned& op01, int& imm19, Condition &condition)
3092     {
3093         int insn = *static_cast<int*>(address);
3094         op01 = ((insn >> 23) & 0x2) | ((insn >> 4) & 0x1);
3095         imm19 = (insn << 8) >> 13;
3096         condition = static_cast<Condition>(insn & 0xf);
3097         return (insn & 0xfe000000) == 0x54000000;
3098     }
3099
3100     static bool disassembleTestAndBranchImmediate(void* address, bool& op, unsigned& bitNumber, int& imm14, RegisterID& rt)
3101     {
3102         int insn = *static_cast<int*>(address);
3103         op = (insn >> 24) & 0x1;
3104         imm14 = (insn << 13) >> 18;
3105         bitNumber = static_cast<unsigned>((((insn >> 26) & 0x20)) | ((insn >> 19) & 0x1f));
3106         rt = static_cast<RegisterID>(insn & 0x1f);
3107         return (insn & 0x7e000000) == 0x36000000;
3108         
3109     }
3110
3111     static bool disassembleUnconditionalBranchImmediate(void* address, bool& op, int& imm26)
3112     {
3113         int insn = *static_cast<int*>(address);
3114         op = (insn >> 31) & 1;
3115         imm26 = (insn << 6) >> 6;
3116         return (insn & 0x7c000000) == 0x14000000;
3117     }
3118
3119     static int xOrSp(RegisterID reg)
3120     {
3121         ASSERT(!isZr(reg));
3122         ASSERT(!isIOS() || reg != ARM64Registers::x18);
3123         return reg;
3124     }
3125     static int xOrZr(RegisterID reg)
3126     {
3127         ASSERT(!isSp(reg));
3128         ASSERT(!isIOS() || reg != ARM64Registers::x18);
3129         return reg & 31;
3130     }
3131     static FPRegisterID xOrZrAsFPR(RegisterID reg) { return static_cast<FPRegisterID>(xOrZr(reg)); }
3132     static int xOrZrOrSp(bool useZr, RegisterID reg) { return useZr ? xOrZr(reg) : xOrSp(reg); }
3133
3134     ALWAYS_INLINE void insn(int instruction)
3135     {
3136         m_buffer.putInt(instruction);
3137     }
3138
3139     ALWAYS_INLINE static int addSubtractExtendedRegister(Datasize sf, AddOp op, SetFlags S, RegisterID rm, ExtendType option, int imm3, RegisterID rn, RegisterID rd)
3140     {
3141         ASSERT(imm3 < 5);
3142         // The only allocated values for opt is 0.
3143         const int opt = 0;
3144         return (0x0b200000 | sf << 31 | op << 30 | S << 29 | opt << 22 | xOrZr(rm) << 16 | option << 13 | (imm3 & 0x7) << 10 | xOrSp(rn) << 5 | xOrZrOrSp(S, rd));
3145     }
3146
3147     ALWAYS_INLINE static int addSubtractImmediate(Datasize sf, AddOp op, SetFlags S, int shift, int imm12, RegisterID rn, RegisterID rd)
3148     {
3149         ASSERT(shift < 2);
3150         ASSERT(isUInt12(imm12));
3151         return (0x11000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | (imm12 & 0xfff) << 10 | xOrSp(rn) << 5 | xOrZrOrSp(S, rd));
3152     }
3153
3154     ALWAYS_INLINE static int addSubtractShiftedRegister(Datasize sf, AddOp op, SetFlags S, ShiftType shift, RegisterID rm, int imm6, RegisterID rn, RegisterID rd)
3155     {
3156         ASSERT(shift < 3);
3157         ASSERT(!(imm6 & (sf ? ~63 : ~31)));
3158         return (0x0b000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | xOrZr(rm) << 16 | (imm6 & 0x3f) << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3159     }
3160
3161     ALWAYS_INLINE static int addSubtractWithCarry(Datasize sf, AddOp op, SetFlags S, RegisterID rm, RegisterID rn, RegisterID rd)
3162     {
3163         const int opcode2 = 0;
3164         return (0x1a000000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | opcode2 << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3165     }
3166
3167     ALWAYS_INLINE static int bitfield(Datasize sf, BitfieldOp opc, int immr, int imms, RegisterID rn, RegisterID rd)
3168     {
3169         ASSERT(immr < (sf ? 64 : 32));
3170         ASSERT(imms < (sf ? 64 : 32));
3171         const int N = sf;
3172         return (0x13000000 | sf << 31 | opc << 29 | N << 22 | immr << 16 | imms << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3173     }
3174
3175     // 'op' means negate
3176     ALWAYS_INLINE static int compareAndBranchImmediate(Datasize sf, bool op, int32_t imm19, RegisterID rt)
3177     {
3178         ASSERT(imm19 == (imm19 << 13) >> 13);
3179         return (0x34000000 | sf << 31 | op << 24 | (imm19 & 0x7ffff) << 5 | xOrZr(rt));
3180     }
3181
3182     ALWAYS_INLINE static int conditionalBranchImmediate(int32_t imm19, Condition cond)
3183     {
3184         ASSERT(imm19 == (imm19 << 13) >> 13);
3185         ASSERT(!(cond & ~15));
3186         // The only allocated values for o1 & o0 are 0.
3187         const int o1 = 0;
3188         const int o0 = 0;
3189         return (0x54000000 | o1 << 24 | (imm19 & 0x7ffff) << 5 | o0 << 4 | cond);
3190     }
3191
3192     ALWAYS_INLINE static int conditionalCompareImmediate(Datasize sf, AddOp op, int imm5, Condition cond, RegisterID rn, int nzcv)
3193     {
3194         ASSERT(!(imm5 & ~0x1f));
3195         ASSERT(nzcv < 16);
3196         const int S = 1;
3197         const int o2 = 0;
3198         const int o3 = 0;
3199         return (0x1a400800 | sf << 31 | op << 30 | S << 29 | (imm5 & 0x1f) << 16 | cond << 12 | o2 << 10 | xOrZr(rn) << 5 | o3 << 4 | nzcv);
3200     }
3201
3202     ALWAYS_INLINE static int conditionalCompareRegister(Datasize sf, AddOp op, RegisterID rm, Condition cond, RegisterID rn, int nzcv)
3203     {
3204         ASSERT(nzcv < 16);
3205         const int S = 1;
3206         const int o2 = 0;
3207         const int o3 = 0;
3208         return (0x1a400000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | cond << 12 | o2 << 10 | xOrZr(rn) << 5 | o3 << 4 | nzcv);
3209     }
3210
3211     // 'op' means negate
3212     // 'op2' means increment
3213     ALWAYS_INLINE static int conditionalSelect(Datasize sf, bool op, RegisterID rm, Condition cond, bool op2, RegisterID rn, RegisterID rd)
3214     {
3215         const int S = 0;
3216         return (0x1a800000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | cond << 12 | op2 << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3217     }
3218
3219     ALWAYS_INLINE static int dataProcessing1Source(Datasize sf, DataOp1Source opcode, RegisterID rn, RegisterID rd)
3220     {
3221         const int S = 0;
3222         const int opcode2 = 0;
3223         return (0x5ac00000 | sf << 31 | S << 29 | opcode2 << 16 | opcode << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3224     }
3225
3226     ALWAYS_INLINE static int dataProcessing2Source(Datasize sf, RegisterID rm, DataOp2Source opcode, RegisterID rn, RegisterID rd)
3227     {
3228         const int S = 0;
3229         return (0x1ac00000 | sf << 31 | S << 29 | xOrZr(rm) << 16 | opcode << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3230     }
3231
3232     ALWAYS_INLINE static int dataProcessing3Source(Datasize sf, DataOp3Source opcode, RegisterID rm, RegisterID ra, RegisterID rn, RegisterID rd)
3233     {
3234         int op54 = opcode >> 4;
3235         int op31 = (opcode >> 1) & 7;
3236         int op0 = opcode & 1;
3237         return (0x1b000000 | sf << 31 | op54 << 29 | op31 << 21 | xOrZr(rm) << 16 | op0 << 15 | xOrZr(ra) << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3238     }
3239
3240     ALWAYS_INLINE static int excepnGeneration(ExcepnOp opc, uint16_t imm16, int LL)
3241     {
3242         ASSERT((opc == ExcepnOp_BREAKPOINT || opc == ExcepnOp_HALT) ? !LL : (LL && (LL < 4)));
3243         const int op2 = 0;
3244         return (0xd4000000 | opc << 21 | imm16 << 5 | op2 << 2 | LL);
3245     }
3246
3247     ALWAYS_INLINE static int extract(Datasize sf, RegisterID rm, int imms, RegisterID rn, RegisterID rd)
3248     {
3249         ASSERT(imms < (sf ? 64 : 32));
3250         const int op21 = 0;
3251         const int N = sf;
3252         const int o0 = 0;
3253         return (0x13800000 | sf << 31 | op21 << 29 | N << 22 | o0 << 21 | xOrZr(rm) << 16 | imms << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3254     }
3255
3256     ALWAYS_INLINE static int floatingPointCompare(Datasize type, FPRegisterID rm, FPRegisterID rn, FPCmpOp opcode2)
3257     {
3258         const int M = 0;
3259         const int S = 0;
3260         const int op = 0;
3261         return (0x1e202000 | M << 31 | S << 29 | type << 22 | rm << 16 | op << 14 | rn << 5 | opcode2);
3262     }
3263
3264     ALWAYS_INLINE static int floatingPointConditionalCompare(Datasize type, FPRegisterID rm, Condition cond, FPRegisterID rn, FPCondCmpOp op, int nzcv)
3265     {
3266         ASSERT(nzcv < 16);
3267         const int M = 0;
3268         const int S = 0;
3269         return (0x1e200400 | M << 31 | S << 29 | type << 22 | rm << 16 | cond << 12 | rn << 5 | op << 4 | nzcv);
3270     }
3271
3272     ALWAYS_INLINE static int floatingPointConditionalSelect(Datasize type, FPRegisterID rm, Condition cond, FPRegisterID rn, FPRegisterID rd)
3273     {
3274         const int M = 0;
3275         const int S = 0;
3276         return (0x1e200c00 | M << 31 | S << 29 | type << 22 | rm << 16 | cond << 12 | rn << 5 | rd);
3277     }
3278
3279     ALWAYS_INLINE static int floatingPointImmediate(Datasize type, int imm8, FPRegisterID rd)
3280     {
3281         const int M = 0;
3282         const int S = 0;
3283         const int imm5 = 0;
3284         return (0x1e201000 | M << 31 | S << 29 | type << 22 | (imm8 & 0xff) << 13 | imm5 << 5 | rd);
3285     }
3286
3287     ALWAYS_INLINE static int floatingPointIntegerConversions(Datasize sf, Datasize type, FPIntConvOp rmodeOpcode, FPRegisterID rn, FPRegisterID rd)
3288     {
3289         const int S = 0;
3290         return (0x1e200000 | sf << 31 | S << 29 | type << 22 | rmodeOpcode << 16 | rn << 5 | rd);
3291     }
3292
3293     ALWAYS_INLINE static int floatingPointIntegerConversions(Datasize sf, Datasize type, FPIntConvOp rmodeOpcode, FPRegisterID rn, RegisterID rd)
3294     {
3295         return floatingPointIntegerConversions(sf, type, rmodeOpcode, rn, xOrZrAsFPR(rd));
3296     }
3297
3298     ALWAYS_INLINE static int floatingPointIntegerConversions(Datasize sf, Datasize type, FPIntConvOp rmodeOpcode, RegisterID rn, FPRegisterID rd)
3299     {
3300         return floatingPointIntegerConversions(sf, type, rmodeOpcode, xOrZrAsFPR(rn), rd);
3301     }
3302
3303     ALWAYS_INLINE static int floatingPointDataProcessing1Source(Datasize type, FPDataOp1Source opcode, FPRegisterID rn, FPRegisterID rd)
3304     {
3305         const int M = 0;
3306         const int S = 0;
3307         return (0x1e204000 | M << 31 | S << 29 | type << 22 | opcode << 15 | rn << 5 | rd);
3308     }
3309
3310     ALWAYS_INLINE static int floatingPointDataProcessing2Source(Datasize type, FPRegisterID rm, FPDataOp2Source opcode, FPRegisterID rn, FPRegisterID rd)
3311     {
3312         const int M = 0;
3313         const int S = 0;
3314         return (0x1e200800 | M << 31 | S << 29 | type << 22 | rm << 16 | opcode << 12 | rn << 5 | rd);
3315     }
3316
3317     ALWAYS_INLINE static int vectorDataProcessing2Source(SIMD3Same opcode, unsigned size, FPRegisterID vm, FPRegisterID vn, FPRegisterID vd)
3318     {
3319         const int Q = 0;
3320         return (0xe201c00 | Q << 30 | size << 22 | vm << 16 | opcode << 11 | vn << 5 | vd);
3321     }
3322
3323     ALWAYS_INLINE static int vectorDataProcessing2Source(SIMD3Same opcode, FPRegisterID vm, FPRegisterID vn, FPRegisterID vd)
3324     {
3325         return vectorDataProcessing2Source(opcode, 0, vm, vn, vd);
3326     }
3327
3328
3329     // 'o1' means negate
3330     ALWAYS_INLINE static int floatingPointDataProcessing3Source(Datasize type, bool o1, FPRegisterID rm, AddOp o2, FPRegisterID ra, FPRegisterID rn, FPRegisterID rd)
3331     {
3332         const int M = 0;
3333         const int S = 0;
3334         return (0x1f000000 | M << 31 | S << 29 | type << 22 | o1 << 21 | rm << 16 | o2 << 15 | ra << 10 | rn << 5 | rd);
3335     }
3336
3337     // 'V' means vector
3338     ALWAYS_INLINE static int loadRegisterLiteral(LdrLiteralOp opc, bool V, int imm19, FPRegisterID rt)
3339     {
3340         ASSERT(((imm19 << 13) >> 13) == imm19);
3341         return (0x18000000 | opc << 30 | V << 26 | (imm19 & 0x7ffff) << 5 | rt);
3342     }
3343
3344     ALWAYS_INLINE static int loadRegisterLiteral(LdrLiteralOp opc, bool V, int imm19, RegisterID rt)
3345     {
3346         return loadRegisterLiteral(opc, V, imm19, xOrZrAsFPR(rt));
3347     }
3348
3349     // 'V' means vector
3350     ALWAYS_INLINE static int loadStoreRegisterPostIndex(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, FPRegisterID rt)
3351     {
3352         ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
3353         ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
3354         ASSERT(isInt9(imm9));
3355         return (0x38000400 | size << 30 | V << 26 | opc << 22 | (imm9 & 0x1ff) << 12 | xOrSp(rn) << 5 | rt);
3356     }
3357
3358     ALWAYS_INLINE static int loadStoreRegisterPostIndex(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, RegisterID rt)
3359     {
3360         return loadStoreRegisterPostIndex(size, V, opc, imm9, rn, xOrZrAsFPR(rt));
3361     }
3362
3363     // 'V' means vector
3364     ALWAYS_INLINE static int loadStoreRegisterPairPostIndex(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, FPRegisterID rt, FPRegisterID rt2)
3365     {
3366         ASSERT(size < 3);
3367         ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
3368         ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
3369         unsigned immedShiftAmount = memPairOffsetShift(V, size);
3370         int imm7 = immediate >> immedShiftAmount;
3371         ASSERT((imm7 << immedShiftAmount) == immediate && isInt7(imm7));
3372         return (0x28800000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
3373     }
3374
3375     ALWAYS_INLINE static int loadStoreRegisterPairPostIndex(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, RegisterID rt, RegisterID rt2)
3376     {
3377         return loadStoreRegisterPairPostIndex(size, V, opc, immediate, rn, xOrZrAsFPR(rt), xOrZrAsFPR(rt2));
3378     }
3379
3380     // 'V' means vector
3381     ALWAYS_INLINE static int loadStoreRegisterPreIndex(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, FPRegisterID rt)
3382     {
3383         ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
3384         ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
3385         ASSERT(isInt9(imm9));
3386         return (0x38000c00 | size << 30 | V << 26 | opc << 22 | (imm9 & 0x1ff) << 12 | xOrSp(rn) << 5 | rt);
3387     }
3388
3389     ALWAYS_INLINE static int loadStoreRegisterPreIndex(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, RegisterID rt)
3390     {
3391         return loadStoreRegisterPreIndex(size, V, opc, imm9, rn, xOrZrAsFPR(rt));
3392     }
3393
3394     // 'V' means vector
3395     ALWAYS_INLINE static int loadStoreRegisterPairPreIndex(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, FPRegisterID rt, FPRegisterID rt2)
3396     {
3397         ASSERT(size < 3);
3398         ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
3399         ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
3400         unsigned immedShiftAmount = memPairOffsetShift(V, size);
3401         int imm7 = immediate >> immedShiftAmount;
3402         ASSERT((imm7 << immedShiftAmount) == immediate && isInt7(imm7));
3403         return (0x29800000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
3404     }
3405
3406     ALWAYS_INLINE static int loadStoreRegisterPairPreIndex(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, RegisterID rt, RegisterID rt2)
3407     {
3408         return loadStoreRegisterPairPreIndex(size, V, opc, immediate, rn, xOrZrAsFPR(rt), xOrZrAsFPR(rt2));
3409     }
3410
3411     // 'V' means vector
3412     ALWAYS_INLINE static int loadStoreRegisterPairOffset(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, FPRegisterID rt, FPRegisterID rt2)
3413     {
3414         ASSERT(size < 3);
3415         ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
3416         ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
3417         unsigned immedShiftAmount = memPairOffsetShift(V, size);
3418         int imm7 = immediate >> immedShiftAmount;
3419         ASSERT((imm7 << immedShiftAmount) == immediate && isInt7(imm7));
3420         return (0x29000000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
3421     }
3422
3423     ALWAYS_INLINE static int loadStoreRegisterPairOffset(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, RegisterID rt, RegisterID rt2)
3424     {
3425         return loadStoreRegisterPairOffset(size, V, opc, immediate, rn, xOrZrAsFPR(rt), xOrZrAsFPR(rt2));
3426     }
3427
3428     // 'V' means vector
3429     ALWAYS_INLINE static int loadStoreRegisterPairNonTemporal(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, FPRegisterID rt, FPRegisterID rt2)
3430     {
3431         ASSERT(size < 3);
3432         ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
3433         ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
3434         unsigned immedShiftAmount = memPairOffsetShift(V, size);
3435         int imm7 = immediate >> immedShiftAmount;
3436         ASSERT((imm7 << immedShiftAmount) == immediate && isInt7(imm7));
3437         return (0x28000000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
3438     }
3439
3440     ALWAYS_INLINE static int loadStoreRegisterPairNonTemporal(MemPairOpSize size, bool V, MemOp opc, int immediate, RegisterID rn, RegisterID rt, RegisterID rt2)
3441     {
3442         return loadStoreRegisterPairNonTemporal(size, V, opc, immediate, rn, xOrZrAsFPR(rt), xOrZrAsFPR(rt2));
3443     }
3444
3445     // 'V' means vector
3446     // 'S' means shift rm
3447     ALWAYS_INLINE static int loadStoreRegisterRegisterOffset(MemOpSize size, bool V, MemOp opc, RegisterID rm, ExtendType option, bool S, RegisterID rn, FPRegisterID rt)
3448     {
3449         ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
3450         ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
3451         ASSERT(option & 2); // The ExtendType for the address must be 32/64 bit, signed or unsigned - not 8/16bit.
3452         return (0x38200800 | size << 30 | V << 26 | opc << 22 | xOrZr(rm) << 16 | option << 13 | S << 12 | xOrSp(rn) << 5 | rt);
3453     }
3454
3455     ALWAYS_INLINE static int loadStoreRegisterRegisterOffset(MemOpSize size, bool V, MemOp opc, RegisterID rm, ExtendType option, bool S, RegisterID rn, RegisterID rt)
3456     {
3457         return loadStoreRegisterRegisterOffset(size, V, opc, rm, option, S, rn, xOrZrAsFPR(rt));
3458     }
3459
3460     // 'V' means vector
3461     ALWAYS_INLINE static int loadStoreRegisterUnscaledImmediate(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, FPRegisterID rt)
3462     {
3463         ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
3464         ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
3465         ASSERT(isInt9(imm9));
3466         return (0x38000000 | size << 30 | V << 26 | opc << 22 | (imm9 & 0x1ff) << 12 | xOrSp(rn) << 5 | rt);
3467     }
3468
3469     ALWAYS_INLINE static int loadStoreRegisterUnscaledImmediate(MemOpSize size, bool V, MemOp opc, int imm9, RegisterID rn, RegisterID rt)
3470     {
3471         ASSERT(isInt9(imm9));
3472         return loadStoreRegisterUnscaledImmediate(size, V, opc, imm9, rn, xOrZrAsFPR(rt));
3473     }
3474
3475     // 'V' means vector
3476     ALWAYS_INLINE static int loadStoreRegisterUnsignedImmediate(MemOpSize size, bool V, MemOp opc, int imm12, RegisterID rn, FPRegisterID rt)
3477     {
3478         ASSERT(!(size && V && (opc & 2))); // Maximum vector size is 128 bits.
3479         ASSERT(!((size & 2) && !V && (opc == 3))); // signed 32-bit load must be extending from 8/16 bits.
3480         ASSERT(isUInt12(imm12));
3481         return (0x39000000 | size << 30 | V << 26 | opc << 22 | (imm12 & 0xfff) << 10 | xOrSp(rn) << 5 | rt);
3482     }
3483
3484     ALWAYS_INLINE static int loadStoreRegisterUnsignedImmediate(MemOpSize size, bool V, MemOp opc, int imm12, RegisterID rn, RegisterID rt)
3485     {
3486         return loadStoreRegisterUnsignedImmediate(size, V, opc, imm12, rn, xOrZrAsFPR(rt));
3487     }
3488
3489     ALWAYS_INLINE static int logicalImmediate(Datasize sf, LogicalOp opc, int N_immr_imms, RegisterID rn, RegisterID rd)
3490     {
3491         ASSERT(!(N_immr_imms & (sf ? ~0x1fff : ~0xfff)));
3492         return (0x12000000 | sf << 31 | opc << 29 | N_immr_imms << 10 | xOrZr(rn) << 5 | xOrZrOrSp(opc == LogicalOp_ANDS, rd));
3493     }
3494
3495     // 'N' means negate rm
3496     ALWAYS_INLINE static int logicalShiftedRegister(Datasize sf, LogicalOp opc, ShiftType shift, bool N, RegisterID rm, int imm6, RegisterID rn, RegisterID rd)
3497     {
3498         ASSERT(!(imm6 & (sf ? ~63 : ~31)));
3499         return (0x0a000000 | sf << 31 | opc << 29 | shift << 22 | N << 21 | xOrZr(rm) << 16 | (imm6 & 0x3f) << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3500     }
3501
3502     ALWAYS_INLINE static int moveWideImediate(Datasize sf, MoveWideOp opc, int hw, uint16_t imm16, RegisterID rd)
3503     {
3504         ASSERT(hw < (sf ? 4 : 2));
3505         return (0x12800000 | sf << 31 | opc << 29 | hw << 21 | (int)imm16 << 5 | xOrZr(rd));
3506     }
3507
3508     // 'op' means link
3509     ALWAYS_INLINE static int unconditionalBranchImmediate(bool op, int32_t imm26)
3510     {
3511         ASSERT(imm26 == (imm26 << 6) >> 6);
3512         return (0x14000000 | op << 31 | (imm26 & 0x3ffffff));
3513     }
3514
3515     // 'op' means page
3516     ALWAYS_INLINE static int pcRelative(bool op, int32_t imm21, RegisterID rd)
3517     {
3518         ASSERT(imm21 == (imm21 << 11) >> 11);
3519         int32_t immlo = imm21 & 3;
3520         int32_t immhi = (imm21 >> 2) & 0x7ffff;
3521         return (0x10000000 | op << 31 | immlo << 29 | immhi << 5 | xOrZr(rd));
3522     }
3523
3524     ALWAYS_INLINE static int system(bool L, int op0, int op1, int crn, int crm, int op2, RegisterID rt)
3525     {
3526         return (0xd5000000 | L << 21 | op0 << 19 | op1 << 16 | crn << 12 | crm << 8 | op2 << 5 | xOrZr(rt));
3527     }
3528
3529     ALWAYS_INLINE static int hintPseudo(int imm)
3530     {
3531         ASSERT(!(imm & ~0x7f));
3532         return system(0, 0, 3, 2, (imm >> 3) & 0xf, imm & 0x7, ARM64Registers::zr);
3533     }
3534
3535     ALWAYS_INLINE static int nopPseudo()
3536     {
3537         return hintPseudo(0);
3538     }
3539     
3540     // 'op' means negate
3541     ALWAYS_INLINE static int testAndBranchImmediate(bool op, int b50, int imm14, RegisterID rt)
3542     {
3543         ASSERT(!(b50 & ~0x3f));
3544         ASSERT(imm14 == (imm14 << 18) >> 18);
3545         int b5 = b50 >> 5;
3546         int b40 = b50 & 0x1f;
3547         return (0x36000000 | b5 << 31 | op << 24 | b40 << 19 | (imm14 & 0x3fff) << 5 | xOrZr(rt));
3548     }
3549
3550     ALWAYS_INLINE static int unconditionalBranchRegister(BranchType opc, RegisterID rn)
3551     {
3552         // The only allocated values for op2 is 0x1f, for op3 & op4 are 0.
3553         const int op2 = 0x1f;
3554         const int op3 = 0;
3555         const int op4 = 0;
3556         return (0xd6000000 | opc << 21 | op2 << 16 | op3 << 10 | xOrZr(rn) << 5 | op4);
3557     }
3558
3559     // Workaround for Cortex-A53 erratum (835769). Emit an extra nop if the
3560     // last instruction in the buffer is a load, store or prefetch. Needed
3561     // before 64-bit multiply-accumulate instructions.
3562     template<int datasize>
3563     ALWAYS_INLINE void nopCortexA53Fix835769()
3564     {
3565 #if CPU(ARM64_CORTEXA53)
3566         CHECK_DATASIZE();
3567         if (datasize == 64) {
3568             if (LIKELY(m_buffer.codeSize() >= sizeof(int32_t))) {
3569                 // From ARMv8 Reference Manual, Section C4.1: the encoding of the
3570                 // instructions in the Loads and stores instruction group is:
3571                 // ---- 1-0- ---- ---- ---- ---- ---- ----
3572                 if (UNLIKELY((*reinterpret_cast_ptr<int32_t*>(reinterpret_cast_ptr<char*>(m_buffer.data()) + m_buffer.codeSize() - sizeof(int32_t)) & 0x0a000000) == 0x08000000))
3573                     nop();
3574             }
3575         }
3576 #endif
3577     }
3578
3579     // Workaround for Cortex-A53 erratum (843419). Emit extra nops to avoid
3580     // wrong address access after ADRP instruction.
3581     ALWAYS_INLINE void nopCortexA53Fix843419()
3582     {
3583 #if CPU(ARM64_CORTEXA53)
3584         nop();
3585         nop();
3586         nop();
3587 #endif
3588     }
3589
3590     AssemblerBuffer m_buffer;
3591     Vector<LinkRecord, 0, UnsafeVectorOverflow> m_jumpsToLink;
3592     int m_indexOfLastWatchpoint;
3593     int m_indexOfTailOfLastWatchpoint;
3594 };
3595
3596 } // namespace JSC
3597
3598 #undef CHECK_DATASIZE_OF
3599 #undef DATASIZE_OF
3600 #undef MEMOPSIZE_OF
3601 #undef CHECK_DATASIZE
3602 #undef DATASIZE
3603 #undef MEMOPSIZE
3604 #undef CHECK_FP_MEMOP_DATASIZE
3605
3606 #endif // ENABLE(ASSEMBLER) && CPU(ARM64)
3607
3608 #endif // ARM64Assembler_h