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