Remove the need to pass performJITMemcpy as a pointer.
[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     enum BranchTargetType { DirectBranch, IndirectBranch  };
1498     using CopyFunction = void*(&)(void*, const void*, size_t);
1499
1500     template <CopyFunction copy>
1501     static void fillNops(void* base, size_t size)
1502     {
1503         RELEASE_ASSERT(!(size % sizeof(int32_t)));
1504         size_t n = size / sizeof(int32_t);
1505         for (int32_t* ptr = static_cast<int32_t*>(base); n--;) {
1506             int insn = nopPseudo();
1507             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(ptr) == ptr);
1508             copy(ptr++, &insn, sizeof(int));
1509         }
1510     }
1511     
1512     ALWAYS_INLINE void dmbISH()
1513     {
1514         insn(0xd5033bbf);
1515     }
1516
1517     ALWAYS_INLINE void dmbISHST()
1518     {
1519         insn(0xd5033abf);
1520     }
1521     
1522     template<int datasize>
1523     void ldar(RegisterID dst, RegisterID src)
1524     {
1525         CHECK_MEMOPSIZE();
1526         insn(exoticLoad(MEMOPSIZE, ExoticLoadFence_Acquire, ExoticLoadAtomic_None, dst, src));
1527     }
1528
1529     template<int datasize>
1530     void ldxr(RegisterID dst, RegisterID src)
1531     {
1532         CHECK_MEMOPSIZE();
1533         insn(exoticLoad(MEMOPSIZE, ExoticLoadFence_None, ExoticLoadAtomic_Link, dst, src));
1534     }
1535
1536     template<int datasize>
1537     void ldaxr(RegisterID dst, RegisterID src)
1538     {
1539         CHECK_MEMOPSIZE();
1540         insn(exoticLoad(MEMOPSIZE, ExoticLoadFence_Acquire, ExoticLoadAtomic_Link, dst, src));
1541     }
1542     
1543     template<int datasize>
1544     void stxr(RegisterID result, RegisterID src, RegisterID dst)
1545     {
1546         CHECK_MEMOPSIZE();
1547         insn(exoticStore(MEMOPSIZE, ExoticStoreFence_None, result, src, dst));
1548     }
1549
1550     template<int datasize>
1551     void stlr(RegisterID src, RegisterID dst)
1552     {
1553         CHECK_MEMOPSIZE();
1554         insn(storeRelease(MEMOPSIZE, src, dst));
1555     }
1556
1557     template<int datasize>
1558     void stlxr(RegisterID result, RegisterID src, RegisterID dst)
1559     {
1560         CHECK_MEMOPSIZE();
1561         insn(exoticStore(MEMOPSIZE, ExoticStoreFence_Release, result, src, dst));
1562     }
1563     
1564 #if ENABLE(FAST_TLS_JIT)
1565     void mrs_TPIDRRO_EL0(RegisterID dst)
1566     {
1567         insn(0xd53bd060 | dst); // Thanks, otool -t!
1568     }
1569 #endif
1570
1571     template<int datasize>
1572     ALWAYS_INLINE void orn(RegisterID rd, RegisterID rn, RegisterID rm)
1573     {
1574         orn<datasize>(rd, rn, rm, LSL, 0);
1575     }
1576
1577     template<int datasize>
1578     ALWAYS_INLINE void orn(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1579     {
1580         CHECK_DATASIZE();
1581         insn(logicalShiftedRegister(DATASIZE, LogicalOp_ORR, shift, true, rm, amount, rn, rd));
1582     }
1583
1584     template<int datasize>
1585     ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm)
1586     {
1587         orr<datasize>(rd, rn, rm, LSL, 0);
1588     }
1589
1590     template<int datasize>
1591     ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1592     {
1593         CHECK_DATASIZE();
1594         insn(logicalShiftedRegister(DATASIZE, LogicalOp_ORR, shift, false, rm, amount, rn, rd));
1595     }
1596
1597     template<int datasize>
1598     ALWAYS_INLINE void orr(RegisterID rd, RegisterID rn, LogicalImmediate imm)
1599     {
1600         CHECK_DATASIZE();
1601         insn(logicalImmediate(DATASIZE, LogicalOp_ORR, imm.value(), rn, rd));
1602     }
1603
1604     template<int datasize>
1605     ALWAYS_INLINE void rbit(RegisterID rd, RegisterID rn)
1606     {
1607         CHECK_DATASIZE();
1608         insn(dataProcessing1Source(DATASIZE, DataOp_RBIT, rn, rd));
1609     }
1610
1611     ALWAYS_INLINE void ret(RegisterID rn = ARM64Registers::lr)
1612     {
1613         insn(unconditionalBranchRegister(BranchType_RET, rn));
1614     }
1615
1616     template<int datasize>
1617     ALWAYS_INLINE void rev(RegisterID rd, RegisterID rn)
1618     {
1619         CHECK_DATASIZE();
1620         if (datasize == 32) // 'rev' mnemonic means REV32 or REV64 depending on the operand width.
1621             insn(dataProcessing1Source(Datasize_32, DataOp_REV32, rn, rd));
1622         else
1623             insn(dataProcessing1Source(Datasize_64, DataOp_REV64, rn, rd));
1624     }
1625
1626     template<int datasize>
1627     ALWAYS_INLINE void rev16(RegisterID rd, RegisterID rn)
1628     {
1629         CHECK_DATASIZE();
1630         insn(dataProcessing1Source(DATASIZE, DataOp_REV16, rn, rd));
1631     }
1632
1633     template<int datasize>
1634     ALWAYS_INLINE void rev32(RegisterID rd, RegisterID rn)
1635     {
1636         ASSERT(datasize == 64); // 'rev32' only valid with 64-bit operands.
1637         insn(dataProcessing1Source(Datasize_64, DataOp_REV32, rn, rd));
1638     }
1639
1640     template<int datasize>
1641     ALWAYS_INLINE void ror(RegisterID rd, RegisterID rn, RegisterID rm)
1642     {
1643         rorv<datasize>(rd, rn, rm);
1644     }
1645
1646     template<int datasize>
1647     ALWAYS_INLINE void ror(RegisterID rd, RegisterID rs, int shift)
1648     {
1649         extr<datasize>(rd, rs, rs, shift);
1650     }
1651
1652     template<int datasize>
1653     ALWAYS_INLINE void rorv(RegisterID rd, RegisterID rn, RegisterID rm)
1654     {
1655         CHECK_DATASIZE();
1656         insn(dataProcessing2Source(DATASIZE, rm, DataOp_RORV, rn, rd));
1657     }
1658
1659     template<int datasize, SetFlags setFlags = DontSetFlags>
1660     ALWAYS_INLINE void sbc(RegisterID rd, RegisterID rn, RegisterID rm)
1661     {
1662         CHECK_DATASIZE();
1663         insn(addSubtractWithCarry(DATASIZE, AddOp_SUB, setFlags, rm, rn, rd));
1664     }
1665
1666     template<int datasize>
1667     ALWAYS_INLINE void sbfiz(RegisterID rd, RegisterID rn, int lsb, int width)
1668     {
1669         sbfm<datasize>(rd, rn, (datasize - lsb) & (datasize - 1), width - 1);
1670     }
1671
1672     template<int datasize>
1673     ALWAYS_INLINE void sbfm(RegisterID rd, RegisterID rn, int immr, int imms)
1674     {
1675         CHECK_DATASIZE();
1676         insn(bitfield(DATASIZE, BitfieldOp_SBFM, immr, imms, rn, rd));
1677     }
1678
1679     template<int datasize>
1680     ALWAYS_INLINE void sbfx(RegisterID rd, RegisterID rn, int lsb, int width)
1681     {
1682         sbfm<datasize>(rd, rn, lsb, lsb + width - 1);
1683     }
1684
1685     template<int datasize>
1686     ALWAYS_INLINE void sdiv(RegisterID rd, RegisterID rn, RegisterID rm)
1687     {
1688         CHECK_DATASIZE();
1689         insn(dataProcessing2Source(DATASIZE, rm, DataOp_SDIV, rn, rd));
1690     }
1691
1692     ALWAYS_INLINE void smaddl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1693     {
1694         nopCortexA53Fix835769<64>();
1695         insn(dataProcessing3Source(Datasize_64, DataOp_SMADDL, rm, ra, rn, rd));
1696     }
1697
1698     ALWAYS_INLINE void smnegl(RegisterID rd, RegisterID rn, RegisterID rm)
1699     {
1700         smsubl(rd, rn, rm, ARM64Registers::zr);
1701     }
1702
1703     ALWAYS_INLINE void smsubl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1704     {
1705         nopCortexA53Fix835769<64>();
1706         insn(dataProcessing3Source(Datasize_64, DataOp_SMSUBL, rm, ra, rn, rd));
1707     }
1708
1709     ALWAYS_INLINE void smulh(RegisterID rd, RegisterID rn, RegisterID rm)
1710     {
1711         insn(dataProcessing3Source(Datasize_64, DataOp_SMULH, rm, ARM64Registers::zr, rn, rd));
1712     }
1713
1714     ALWAYS_INLINE void smull(RegisterID rd, RegisterID rn, RegisterID rm)
1715     {
1716         smaddl(rd, rn, rm, ARM64Registers::zr);
1717     }
1718
1719     template<int datasize>
1720     ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPostIndex simm)
1721     {
1722         CHECK_DATASIZE();
1723         insn(loadStoreRegisterPairPostIndex(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, simm, rn, rt, rt2));
1724     }
1725
1726     template<int datasize>
1727     ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPreIndex simm)
1728     {
1729         CHECK_DATASIZE();
1730         insn(loadStoreRegisterPairPreIndex(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, simm, rn, rt, rt2));
1731     }
1732
1733     template<int datasize>
1734     ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
1735     {
1736         CHECK_DATASIZE();
1737         insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, pimm, rn, rt, rt2));
1738     }
1739
1740     template<int datasize>
1741     ALWAYS_INLINE void stnp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
1742     {
1743         CHECK_DATASIZE();
1744         insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, pimm, rn, rt, rt2));
1745     }
1746
1747     template<int datasize>
1748     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm)
1749     {
1750         str<datasize>(rt, rn, rm, UXTX, 0);
1751     }
1752
1753     template<int datasize>
1754     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1755     {
1756         CHECK_DATASIZE();
1757         insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, false, MemOp_STORE, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
1758     }
1759
1760     template<int datasize>
1761     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, unsigned pimm)
1762     {
1763         CHECK_DATASIZE();
1764         insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, false, MemOp_STORE, encodePositiveImmediate<datasize>(pimm), rn, rt));
1765     }
1766
1767     template<int datasize>
1768     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, PostIndex simm)
1769     {
1770         CHECK_DATASIZE();
1771         insn(loadStoreRegisterPostIndex(MEMOPSIZE, false, MemOp_STORE, simm, rn, rt));
1772     }
1773
1774     template<int datasize>
1775     ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, PreIndex simm)
1776     {
1777         CHECK_DATASIZE();
1778         insn(loadStoreRegisterPreIndex(MEMOPSIZE, false, MemOp_STORE, simm, rn, rt));
1779     }
1780
1781     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, RegisterID rm)
1782     {
1783         // Not calling the 5 argument form of strb, since is amount is ommitted S is false.
1784         insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_STORE, rm, UXTX, false, rn, rt));
1785     }
1786
1787     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1788     {
1789         ASSERT_UNUSED(amount, !amount);
1790         insn(loadStoreRegisterRegisterOffset(MemOpSize_8_or_128, false, MemOp_STORE, rm, extend, true, rn, rt));
1791     }
1792
1793     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, unsigned pimm)
1794     {
1795         insn(loadStoreRegisterUnsignedImmediate(MemOpSize_8_or_128, false, MemOp_STORE, encodePositiveImmediate<8>(pimm), rn, rt));
1796     }
1797
1798     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, PostIndex simm)
1799     {
1800         insn(loadStoreRegisterPostIndex(MemOpSize_8_or_128, false, MemOp_STORE, simm, rn, rt));
1801     }
1802
1803     ALWAYS_INLINE void strb(RegisterID rt, RegisterID rn, PreIndex simm)
1804     {
1805         insn(loadStoreRegisterPreIndex(MemOpSize_8_or_128, false, MemOp_STORE, simm, rn, rt));
1806     }
1807
1808     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, RegisterID rm)
1809     {
1810         strh(rt, rn, rm, UXTX, 0);
1811     }
1812
1813     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1814     {
1815         ASSERT(!amount || amount == 1);
1816         insn(loadStoreRegisterRegisterOffset(MemOpSize_16, false, MemOp_STORE, rm, extend, amount == 1, rn, rt));
1817     }
1818
1819     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, unsigned pimm)
1820     {
1821         insn(loadStoreRegisterUnsignedImmediate(MemOpSize_16, false, MemOp_STORE, encodePositiveImmediate<16>(pimm), rn, rt));
1822     }
1823
1824     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, PostIndex simm)
1825     {
1826         insn(loadStoreRegisterPostIndex(MemOpSize_16, false, MemOp_STORE, simm, rn, rt));
1827     }
1828
1829     ALWAYS_INLINE void strh(RegisterID rt, RegisterID rn, PreIndex simm)
1830     {
1831         insn(loadStoreRegisterPreIndex(MemOpSize_16, false, MemOp_STORE, simm, rn, rt));
1832     }
1833
1834     template<int datasize>
1835     ALWAYS_INLINE void stur(RegisterID rt, RegisterID rn, int simm)
1836     {
1837         CHECK_DATASIZE();
1838         insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, false, MemOp_STORE, simm, rn, rt));
1839     }
1840
1841     ALWAYS_INLINE void sturb(RegisterID rt, RegisterID rn, int simm)
1842     {
1843         insn(loadStoreRegisterUnscaledImmediate(MemOpSize_8_or_128, false, MemOp_STORE, simm, rn, rt));
1844     }
1845
1846     ALWAYS_INLINE void sturh(RegisterID rt, RegisterID rn, int simm)
1847     {
1848         insn(loadStoreRegisterUnscaledImmediate(MemOpSize_16, false, MemOp_STORE, simm, rn, rt));
1849     }
1850
1851     template<int datasize, SetFlags setFlags = DontSetFlags>
1852     ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, UInt12 imm12, int shift = 0)
1853     {
1854         CHECK_DATASIZE();
1855         ASSERT(!shift || shift == 12);
1856         insn(addSubtractImmediate(DATASIZE, AddOp_SUB, setFlags, shift == 12, imm12, rn, rd));
1857     }
1858
1859     template<int datasize, SetFlags setFlags = DontSetFlags>
1860     ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm)
1861     {
1862         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.");
1863         ASSERT_WITH_MESSAGE(!isSp(rm), "No encoding of SUBS supports SP for the third operand.");
1864
1865         if (isSp(rd) || isSp(rn))
1866             sub<datasize, setFlags>(rd, rn, rm, UXTX, 0);
1867         else
1868             sub<datasize, setFlags>(rd, rn, rm, LSL, 0);
1869     }
1870
1871     template<int datasize, SetFlags setFlags = DontSetFlags>
1872     ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
1873     {
1874         CHECK_DATASIZE();
1875         insn(addSubtractExtendedRegister(DATASIZE, AddOp_SUB, setFlags, rm, extend, amount, rn, rd));
1876     }
1877
1878     template<int datasize, SetFlags setFlags = DontSetFlags>
1879     ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1880     {
1881         CHECK_DATASIZE();
1882         ASSERT(!isSp(rd) && !isSp(rn) && !isSp(rm));
1883         insn(addSubtractShiftedRegister(DATASIZE, AddOp_SUB, setFlags, shift, rm, amount, rn, rd));
1884     }
1885
1886     template<int datasize>
1887     ALWAYS_INLINE void sxtb(RegisterID rd, RegisterID rn)
1888     {
1889         sbfm<datasize>(rd, rn, 0, 7);
1890     }
1891
1892     template<int datasize>
1893     ALWAYS_INLINE void sxth(RegisterID rd, RegisterID rn)
1894     {
1895         sbfm<datasize>(rd, rn, 0, 15);
1896     }
1897
1898     ALWAYS_INLINE void sxtw(RegisterID rd, RegisterID rn)
1899     {
1900         sbfm<64>(rd, rn, 0, 31);
1901     }
1902
1903     ALWAYS_INLINE void tbz(RegisterID rt, int imm, int offset = 0)
1904     {
1905         ASSERT(!(offset & 3));
1906         offset >>= 2;
1907         insn(testAndBranchImmediate(false, imm, offset, rt));
1908     }
1909
1910     ALWAYS_INLINE void tbnz(RegisterID rt, int imm, int offset = 0)
1911     {
1912         ASSERT(!(offset & 3));
1913         offset >>= 2;
1914         insn(testAndBranchImmediate(true, imm, offset, rt));
1915     }
1916
1917     template<int datasize>
1918     ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm)
1919     {
1920         and_<datasize, S>(ARM64Registers::zr, rn, rm);
1921     }
1922
1923     template<int datasize>
1924     ALWAYS_INLINE void tst(RegisterID rn, RegisterID rm, ShiftType shift, int amount)
1925     {
1926         and_<datasize, S>(ARM64Registers::zr, rn, rm, shift, amount);
1927     }
1928
1929     template<int datasize>
1930     ALWAYS_INLINE void tst(RegisterID rn, LogicalImmediate imm)
1931     {
1932         and_<datasize, S>(ARM64Registers::zr, rn, imm);
1933     }
1934
1935     template<int datasize>
1936     ALWAYS_INLINE void ubfiz(RegisterID rd, RegisterID rn, int lsb, int width)
1937     {
1938         ubfm<datasize>(rd, rn, (datasize - lsb) & (datasize - 1), width - 1);
1939     }
1940
1941     template<int datasize>
1942     ALWAYS_INLINE void ubfm(RegisterID rd, RegisterID rn, int immr, int imms)
1943     {
1944         CHECK_DATASIZE();
1945         insn(bitfield(DATASIZE, BitfieldOp_UBFM, immr, imms, rn, rd));
1946     }
1947
1948     template<int datasize>
1949     ALWAYS_INLINE void ubfx(RegisterID rd, RegisterID rn, int lsb, int width)
1950     {
1951         ubfm<datasize>(rd, rn, lsb, lsb + width - 1);
1952     }
1953
1954     template<int datasize>
1955     ALWAYS_INLINE void udiv(RegisterID rd, RegisterID rn, RegisterID rm)
1956     {
1957         CHECK_DATASIZE();
1958         insn(dataProcessing2Source(DATASIZE, rm, DataOp_UDIV, rn, rd));
1959     }
1960
1961     ALWAYS_INLINE void umaddl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1962     {
1963         nopCortexA53Fix835769<64>();
1964         insn(dataProcessing3Source(Datasize_64, DataOp_UMADDL, rm, ra, rn, rd));
1965     }
1966
1967     ALWAYS_INLINE void umnegl(RegisterID rd, RegisterID rn, RegisterID rm)
1968     {
1969         umsubl(rd, rn, rm, ARM64Registers::zr);
1970     }
1971
1972     ALWAYS_INLINE void umsubl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra)
1973     {
1974         nopCortexA53Fix835769<64>();
1975         insn(dataProcessing3Source(Datasize_64, DataOp_UMSUBL, rm, ra, rn, rd));
1976     }
1977
1978     ALWAYS_INLINE void umulh(RegisterID rd, RegisterID rn, RegisterID rm)
1979     {
1980         insn(dataProcessing3Source(Datasize_64, DataOp_UMULH, rm, ARM64Registers::zr, rn, rd));
1981     }
1982
1983     ALWAYS_INLINE void umull(RegisterID rd, RegisterID rn, RegisterID rm)
1984     {
1985         umaddl(rd, rn, rm, ARM64Registers::zr);
1986     }
1987
1988     template<int datasize>
1989     ALWAYS_INLINE void uxtb(RegisterID rd, RegisterID rn)
1990     {
1991         ubfm<datasize>(rd, rn, 0, 7);
1992     }
1993
1994     template<int datasize>
1995     ALWAYS_INLINE void uxth(RegisterID rd, RegisterID rn)
1996     {
1997         ubfm<datasize>(rd, rn, 0, 15);
1998     }
1999
2000     ALWAYS_INLINE void uxtw(RegisterID rd, RegisterID rn)
2001     {
2002         ubfm<64>(rd, rn, 0, 31);
2003     }
2004
2005     // Floating Point Instructions:
2006
2007     template<int datasize>
2008     ALWAYS_INLINE void fabs(FPRegisterID vd, FPRegisterID vn)
2009     {
2010         CHECK_DATASIZE();
2011         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FABS, vn, vd));
2012     }
2013
2014     template<int datasize>
2015     ALWAYS_INLINE void fadd(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2016     {
2017         CHECK_DATASIZE();
2018         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FADD, vn, vd));
2019     }
2020
2021     template<int datasize>
2022     ALWAYS_INLINE void fccmp(FPRegisterID vn, FPRegisterID vm, int nzcv, Condition cond)
2023     {
2024         CHECK_DATASIZE();
2025         insn(floatingPointConditionalCompare(DATASIZE, vm, cond, vn, FPCondCmpOp_FCMP, nzcv));
2026     }
2027
2028     template<int datasize>
2029     ALWAYS_INLINE void fccmpe(FPRegisterID vn, FPRegisterID vm, int nzcv, Condition cond)
2030     {
2031         CHECK_DATASIZE();
2032         insn(floatingPointConditionalCompare(DATASIZE, vm, cond, vn, FPCondCmpOp_FCMPE, nzcv));
2033     }
2034
2035     template<int datasize>
2036     ALWAYS_INLINE void fcmp(FPRegisterID vn, FPRegisterID vm)
2037     {
2038         CHECK_DATASIZE();
2039         insn(floatingPointCompare(DATASIZE, vm, vn, FPCmpOp_FCMP));
2040     }
2041
2042     template<int datasize>
2043     ALWAYS_INLINE void fcmp_0(FPRegisterID vn)
2044     {
2045         CHECK_DATASIZE();
2046         insn(floatingPointCompare(DATASIZE, static_cast<FPRegisterID>(0), vn, FPCmpOp_FCMP0));
2047     }
2048
2049     template<int datasize>
2050     ALWAYS_INLINE void fcmpe(FPRegisterID vn, FPRegisterID vm)
2051     {
2052         CHECK_DATASIZE();
2053         insn(floatingPointCompare(DATASIZE, vm, vn, FPCmpOp_FCMPE));
2054     }
2055
2056     template<int datasize>
2057     ALWAYS_INLINE void fcmpe_0(FPRegisterID vn)
2058     {
2059         CHECK_DATASIZE();
2060         insn(floatingPointCompare(DATASIZE, static_cast<FPRegisterID>(0), vn, FPCmpOp_FCMPE0));
2061     }
2062
2063     template<int datasize>
2064     ALWAYS_INLINE void fcsel(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, Condition cond)
2065     {
2066         CHECK_DATASIZE();
2067         insn(floatingPointConditionalSelect(DATASIZE, vm, cond, vn, vd));
2068     }
2069
2070     template<int dstsize, int srcsize>
2071     ALWAYS_INLINE void fcvt(FPRegisterID vd, FPRegisterID vn)
2072     {
2073         ASSERT(dstsize == 16 || dstsize == 32 || dstsize == 64);
2074         ASSERT(srcsize == 16 || srcsize == 32 || srcsize == 64);
2075         ASSERT(dstsize != srcsize);
2076         Datasize type = (srcsize == 64) ? Datasize_64 : (srcsize == 32) ? Datasize_32 : Datasize_16;
2077         FPDataOp1Source opcode = (dstsize == 64) ? FPDataOp_FCVT_toDouble : (dstsize == 32) ? FPDataOp_FCVT_toSingle : FPDataOp_FCVT_toHalf;
2078         insn(floatingPointDataProcessing1Source(type, opcode, vn, vd));
2079     }
2080
2081     template<int dstsize, int srcsize>
2082     ALWAYS_INLINE void fcvtas(RegisterID rd, FPRegisterID vn)
2083     {
2084         CHECK_DATASIZE_OF(dstsize);
2085         CHECK_DATASIZE_OF(srcsize);
2086         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTAS, vn, rd));
2087     }
2088
2089     template<int dstsize, int srcsize>
2090     ALWAYS_INLINE void fcvtau(RegisterID rd, FPRegisterID vn)
2091     {
2092         CHECK_DATASIZE_OF(dstsize);
2093         CHECK_DATASIZE_OF(srcsize);
2094         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTAU, vn, rd));
2095     }
2096
2097     template<int dstsize, int srcsize>
2098     ALWAYS_INLINE void fcvtms(RegisterID rd, FPRegisterID vn)
2099     {
2100         CHECK_DATASIZE_OF(dstsize);
2101         CHECK_DATASIZE_OF(srcsize);
2102         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTMS, vn, rd));
2103     }
2104
2105     template<int dstsize, int srcsize>
2106     ALWAYS_INLINE void fcvtmu(RegisterID rd, FPRegisterID vn)
2107     {
2108         CHECK_DATASIZE_OF(dstsize);
2109         CHECK_DATASIZE_OF(srcsize);
2110         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTMU, vn, rd));
2111     }
2112
2113     template<int dstsize, int srcsize>
2114     ALWAYS_INLINE void fcvtns(RegisterID rd, FPRegisterID vn)
2115     {
2116         CHECK_DATASIZE_OF(dstsize);
2117         CHECK_DATASIZE_OF(srcsize);
2118         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTNS, vn, rd));
2119     }
2120
2121     template<int dstsize, int srcsize>
2122     ALWAYS_INLINE void fcvtnu(RegisterID rd, FPRegisterID vn)
2123     {
2124         CHECK_DATASIZE_OF(dstsize);
2125         CHECK_DATASIZE_OF(srcsize);
2126         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTNU, vn, rd));
2127     }
2128
2129     template<int dstsize, int srcsize>
2130     ALWAYS_INLINE void fcvtps(RegisterID rd, FPRegisterID vn)
2131     {
2132         CHECK_DATASIZE_OF(dstsize);
2133         CHECK_DATASIZE_OF(srcsize);
2134         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTPS, vn, rd));
2135     }
2136
2137     template<int dstsize, int srcsize>
2138     ALWAYS_INLINE void fcvtpu(RegisterID rd, FPRegisterID vn)
2139     {
2140         CHECK_DATASIZE_OF(dstsize);
2141         CHECK_DATASIZE_OF(srcsize);
2142         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTPU, vn, rd));
2143     }
2144
2145     template<int dstsize, int srcsize>
2146     ALWAYS_INLINE void fcvtzs(RegisterID rd, FPRegisterID vn)
2147     {
2148         CHECK_DATASIZE_OF(dstsize);
2149         CHECK_DATASIZE_OF(srcsize);
2150         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTZS, vn, rd));
2151     }
2152
2153     template<int dstsize, int srcsize>
2154     ALWAYS_INLINE void fcvtzu(RegisterID rd, FPRegisterID vn)
2155     {
2156         CHECK_DATASIZE_OF(dstsize);
2157         CHECK_DATASIZE_OF(srcsize);
2158         insn(floatingPointIntegerConversions(DATASIZE_OF(dstsize), DATASIZE_OF(srcsize), FPIntConvOp_FCVTZU, vn, rd));
2159     }
2160
2161     template<int datasize>
2162     ALWAYS_INLINE void fdiv(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2163     {
2164         CHECK_DATASIZE();
2165         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FDIV, vn, vd));
2166     }
2167
2168     template<int datasize>
2169     ALWAYS_INLINE void fmadd(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
2170     {
2171         CHECK_DATASIZE();
2172         insn(floatingPointDataProcessing3Source(DATASIZE, false, vm, AddOp_ADD, va, vn, vd));
2173     }
2174
2175     template<int datasize>
2176     ALWAYS_INLINE void fmax(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2177     {
2178         CHECK_DATASIZE();
2179         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMAX, vn, vd));
2180     }
2181
2182     template<int datasize>
2183     ALWAYS_INLINE void fmaxnm(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2184     {
2185         CHECK_DATASIZE();
2186         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMAXNM, vn, vd));
2187     }
2188
2189     template<int datasize>
2190     ALWAYS_INLINE void fmin(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2191     {
2192         CHECK_DATASIZE();
2193         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMIN, vn, vd));
2194     }
2195
2196     template<int datasize>
2197     ALWAYS_INLINE void fminnm(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2198     {
2199         CHECK_DATASIZE();
2200         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMINNM, vn, vd));
2201     }
2202
2203     template<int datasize>
2204     ALWAYS_INLINE void fmov(FPRegisterID vd, FPRegisterID vn)
2205     {
2206         CHECK_DATASIZE();
2207         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FMOV, vn, vd));
2208     }
2209
2210     template<int datasize>
2211     ALWAYS_INLINE void fmov(FPRegisterID vd, RegisterID rn)
2212     {
2213         CHECK_DATASIZE();
2214         insn(floatingPointIntegerConversions(DATASIZE, DATASIZE, FPIntConvOp_FMOV_XtoQ, rn, vd));
2215     }
2216
2217     template<int datasize>
2218     ALWAYS_INLINE void fmov(RegisterID rd, FPRegisterID vn)
2219     {
2220         CHECK_DATASIZE();
2221         insn(floatingPointIntegerConversions(DATASIZE, DATASIZE, FPIntConvOp_FMOV_QtoX, vn, rd));
2222     }
2223
2224     template<int datasize>
2225     ALWAYS_INLINE void fmov(FPRegisterID vd, double imm)
2226     {
2227         CHECK_DATASIZE();
2228         insn(floatingPointImmediate(DATASIZE, encodeFPImm(imm), vd));
2229     }
2230
2231     ALWAYS_INLINE void fmov_top(FPRegisterID vd, RegisterID rn)
2232     {
2233         insn(floatingPointIntegerConversions(Datasize_64, Datasize_64, FPIntConvOp_FMOV_XtoQ_top, rn, vd));
2234     }
2235
2236     ALWAYS_INLINE void fmov_top(RegisterID rd, FPRegisterID vn)
2237     {
2238         insn(floatingPointIntegerConversions(Datasize_64, Datasize_64, FPIntConvOp_FMOV_QtoX_top, vn, rd));
2239     }
2240
2241     template<int datasize>
2242     ALWAYS_INLINE void fmsub(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
2243     {
2244         CHECK_DATASIZE();
2245         insn(floatingPointDataProcessing3Source(DATASIZE, false, vm, AddOp_SUB, va, vn, vd));
2246     }
2247
2248     template<int datasize>
2249     ALWAYS_INLINE void fmul(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2250     {
2251         CHECK_DATASIZE();
2252         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FMUL, vn, vd));
2253     }
2254
2255     template<int datasize>
2256     ALWAYS_INLINE void fneg(FPRegisterID vd, FPRegisterID vn)
2257     {
2258         CHECK_DATASIZE();
2259         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FNEG, vn, vd));
2260     }
2261
2262     template<int datasize>
2263     ALWAYS_INLINE void fnmadd(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
2264     {
2265         CHECK_DATASIZE();
2266         insn(floatingPointDataProcessing3Source(DATASIZE, true, vm, AddOp_ADD, va, vn, vd));
2267     }
2268
2269     template<int datasize>
2270     ALWAYS_INLINE void fnmsub(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm, FPRegisterID va)
2271     {
2272         CHECK_DATASIZE();
2273         insn(floatingPointDataProcessing3Source(DATASIZE, true, vm, AddOp_SUB, va, vn, vd));
2274     }
2275
2276     template<int datasize>
2277     ALWAYS_INLINE void fnmul(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2278     {
2279         CHECK_DATASIZE();
2280         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FNMUL, vn, vd));
2281     }
2282
2283     template<int datasize>
2284     ALWAYS_INLINE void vand(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2285     {
2286         CHECK_VECTOR_DATASIZE();
2287         insn(vectorDataProcessingLogical(SIMD_LogicalOp_AND, vm, vn, vd));
2288     }
2289
2290     template<int datasize>
2291     ALWAYS_INLINE void vorr(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2292     {
2293         CHECK_VECTOR_DATASIZE();
2294         insn(vectorDataProcessingLogical(SIMD_LogicalOp_ORR, vm, vn, vd));
2295     }
2296
2297     template<int datasize>
2298     ALWAYS_INLINE void frinta(FPRegisterID vd, FPRegisterID vn)
2299     {
2300         CHECK_DATASIZE();
2301         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTA, vn, vd));
2302     }
2303
2304     template<int datasize>
2305     ALWAYS_INLINE void frinti(FPRegisterID vd, FPRegisterID vn)
2306     {
2307         CHECK_DATASIZE();
2308         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTI, vn, vd));
2309     }
2310
2311     template<int datasize>
2312     ALWAYS_INLINE void frintm(FPRegisterID vd, FPRegisterID vn)
2313     {
2314         CHECK_DATASIZE();
2315         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTM, vn, vd));
2316     }
2317
2318     template<int datasize>
2319     ALWAYS_INLINE void frintn(FPRegisterID vd, FPRegisterID vn)
2320     {
2321         CHECK_DATASIZE();
2322         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTN, vn, vd));
2323     }
2324
2325     template<int datasize>
2326     ALWAYS_INLINE void frintp(FPRegisterID vd, FPRegisterID vn)
2327     {
2328         CHECK_DATASIZE();
2329         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTP, vn, vd));
2330     }
2331
2332     template<int datasize>
2333     ALWAYS_INLINE void frintx(FPRegisterID vd, FPRegisterID vn)
2334     {
2335         CHECK_DATASIZE();
2336         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTX, vn, vd));
2337     }
2338
2339     template<int datasize>
2340     ALWAYS_INLINE void frintz(FPRegisterID vd, FPRegisterID vn)
2341     {
2342         CHECK_DATASIZE();
2343         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FRINTZ, vn, vd));
2344     }
2345
2346     template<int datasize>
2347     ALWAYS_INLINE void fsqrt(FPRegisterID vd, FPRegisterID vn)
2348     {
2349         CHECK_DATASIZE();
2350         insn(floatingPointDataProcessing1Source(DATASIZE, FPDataOp_FSQRT, vn, vd));
2351     }
2352
2353     template<int datasize>
2354     ALWAYS_INLINE void fsub(FPRegisterID vd, FPRegisterID vn, FPRegisterID vm)
2355     {
2356         CHECK_DATASIZE();
2357         insn(floatingPointDataProcessing2Source(DATASIZE, vm, FPDataOp_FSUB, vn, vd));
2358     }
2359
2360     template<int datasize>
2361     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, RegisterID rm)
2362     {
2363         ldr<datasize>(rt, rn, rm, UXTX, 0);
2364     }
2365
2366     template<int datasize>
2367     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
2368     {
2369         CHECK_FP_MEMOP_DATASIZE();
2370         insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
2371     }
2372
2373     template<int datasize>
2374     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, unsigned pimm)
2375     {
2376         CHECK_FP_MEMOP_DATASIZE();
2377         insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, encodePositiveImmediate<datasize>(pimm), rn, rt));
2378     }
2379
2380     template<int datasize>
2381     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, PostIndex simm)
2382     {
2383         CHECK_FP_MEMOP_DATASIZE();
2384         insn(loadStoreRegisterPostIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, simm, rn, rt));
2385     }
2386
2387     template<int datasize>
2388     ALWAYS_INLINE void ldr(FPRegisterID rt, RegisterID rn, PreIndex simm)
2389     {
2390         CHECK_FP_MEMOP_DATASIZE();
2391         insn(loadStoreRegisterPreIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, simm, rn, rt));
2392     }
2393
2394     template<int datasize>
2395     ALWAYS_INLINE void ldr_literal(FPRegisterID rt, int offset = 0)
2396     {
2397         CHECK_FP_MEMOP_DATASIZE();
2398         ASSERT(datasize >= 32);
2399         ASSERT(!(offset & 3));
2400         insn(loadRegisterLiteral(datasize == 128 ? LdrLiteralOp_128BIT : datasize == 64 ? LdrLiteralOp_64BIT : LdrLiteralOp_32BIT, true, offset >> 2, rt));
2401     }
2402
2403     template<int datasize>
2404     ALWAYS_INLINE void ldur(FPRegisterID rt, RegisterID rn, int simm)
2405     {
2406         CHECK_FP_MEMOP_DATASIZE();
2407         insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_LOAD_V128 : MemOp_LOAD, simm, rn, rt));
2408     }
2409
2410     template<int dstsize, int srcsize>
2411     ALWAYS_INLINE void scvtf(FPRegisterID vd, RegisterID rn)
2412     {
2413         CHECK_DATASIZE_OF(dstsize);
2414         CHECK_DATASIZE_OF(srcsize);
2415         insn(floatingPointIntegerConversions(DATASIZE_OF(srcsize), DATASIZE_OF(dstsize), FPIntConvOp_SCVTF, rn, vd));
2416     }
2417
2418     template<int datasize>
2419     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, RegisterID rm)
2420     {
2421         str<datasize>(rt, rn, rm, UXTX, 0);
2422     }
2423
2424     template<int datasize>
2425     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, RegisterID rm, ExtendType extend, int amount)
2426     {
2427         CHECK_FP_MEMOP_DATASIZE();
2428         insn(loadStoreRegisterRegisterOffset(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, rm, extend, encodeShiftAmount<datasize>(amount), rn, rt));
2429     }
2430
2431     template<int datasize>
2432     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, unsigned pimm)
2433     {
2434         CHECK_FP_MEMOP_DATASIZE();
2435         insn(loadStoreRegisterUnsignedImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, encodePositiveImmediate<datasize>(pimm), rn, rt));
2436     }
2437
2438     template<int datasize>
2439     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, PostIndex simm)
2440     {
2441         CHECK_FP_MEMOP_DATASIZE();
2442         insn(loadStoreRegisterPostIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, simm, rn, rt));
2443     }
2444
2445     template<int datasize>
2446     ALWAYS_INLINE void str(FPRegisterID rt, RegisterID rn, PreIndex simm)
2447     {
2448         CHECK_FP_MEMOP_DATASIZE();
2449         insn(loadStoreRegisterPreIndex(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, simm, rn, rt));
2450     }
2451
2452     template<int datasize>
2453     ALWAYS_INLINE void stur(FPRegisterID rt, RegisterID rn, int simm)
2454     {
2455         CHECK_DATASIZE();
2456         insn(loadStoreRegisterUnscaledImmediate(MEMOPSIZE, true, datasize == 128 ? MemOp_STORE_V128 : MemOp_STORE, simm, rn, rt));
2457     }
2458
2459     template<int dstsize, int srcsize>
2460     ALWAYS_INLINE void ucvtf(FPRegisterID vd, RegisterID rn)
2461     {
2462         CHECK_DATASIZE_OF(dstsize);
2463         CHECK_DATASIZE_OF(srcsize);
2464         insn(floatingPointIntegerConversions(DATASIZE_OF(srcsize), DATASIZE_OF(dstsize), FPIntConvOp_UCVTF, rn, vd));
2465     }
2466
2467     ALWAYS_INLINE void fjcvtzs(RegisterID rd, FPRegisterID dn)
2468     {
2469         insn(fjcvtzsInsn(dn, rd));
2470     }
2471
2472     // Admin methods:
2473
2474     AssemblerLabel labelIgnoringWatchpoints()
2475     {
2476         return m_buffer.label();
2477     }
2478
2479     AssemblerLabel labelForWatchpoint()
2480     {
2481         AssemblerLabel result = m_buffer.label();
2482         if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
2483             result = label();
2484         m_indexOfLastWatchpoint = result.m_offset;
2485         m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
2486         return result;
2487     }
2488
2489     AssemblerLabel label()
2490     {
2491         AssemblerLabel result = m_buffer.label();
2492         while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
2493             nop();
2494             result = m_buffer.label();
2495         }
2496         return result;
2497     }
2498
2499     AssemblerLabel align(int alignment)
2500     {
2501         ASSERT(!(alignment & 3));
2502         while (!m_buffer.isAligned(alignment))
2503             brk(0);
2504         return label();
2505     }
2506     
2507     static void* getRelocatedAddress(void* code, AssemblerLabel label)
2508     {
2509         ASSERT(label.isSet());
2510         return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + label.m_offset);
2511     }
2512     
2513     static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
2514     {
2515         return b.m_offset - a.m_offset;
2516     }
2517
2518     size_t codeSize() const { return m_buffer.codeSize(); }
2519
2520     static unsigned getCallReturnOffset(AssemblerLabel call)
2521     {
2522         ASSERT(call.isSet());
2523         return call.m_offset;
2524     }
2525
2526     // Linking & patching:
2527     //
2528     // 'link' and 'patch' methods are for use on unprotected code - such as the code
2529     // within the AssemblerBuffer, and code being patched by the patch buffer. Once
2530     // code has been finalized it is (platform support permitting) within a non-
2531     // writable region of memory; to modify the code in an execute-only execuable
2532     // pool the 'repatch' and 'relink' methods should be used.
2533
2534     void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition)
2535     {
2536         ASSERT(to.isSet());
2537         ASSERT(from.isSet());
2538         m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition));
2539     }
2540
2541     void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition, bool is64Bit, RegisterID compareRegister)
2542     {
2543         ASSERT(to.isSet());
2544         ASSERT(from.isSet());
2545         m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition, is64Bit, compareRegister));
2546     }
2547
2548     void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type, Condition condition, unsigned bitNumber, RegisterID compareRegister)
2549     {
2550         ASSERT(to.isSet());
2551         ASSERT(from.isSet());
2552         m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, type, condition, bitNumber, compareRegister));
2553     }
2554
2555     static void linkJump(void* code, AssemblerLabel from, void* to)
2556     {
2557         ASSERT(from.isSet());
2558         relinkJumpOrCall<BranchType_JMP>(addressOf(code, from), addressOf(code, from), to);
2559     }
2560
2561     static void linkCall(void* code, AssemblerLabel from, void* to)
2562     {
2563         ASSERT(from.isSet());
2564         linkJumpOrCall<BranchType_CALL>(addressOf(code, from) - 1, addressOf(code, from) - 1, to);
2565     }
2566
2567     static void linkPointer(void* code, AssemblerLabel where, void* valuePtr)
2568     {
2569         linkPointer(addressOf(code, where), valuePtr);
2570     }
2571
2572     static void replaceWithVMHalt(void* where)
2573     {
2574         // This should try to write to null which should always Segfault.
2575         int insn = dataCacheZeroVirtualAddress(ARM64Registers::zr);
2576         RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(where) == where);
2577         performJITMemcpy(where, &insn, sizeof(int));
2578         cacheFlush(where, sizeof(int));
2579     }
2580
2581     static void replaceWithJump(void* where, void* to)
2582     {
2583         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(where)) >> 2;
2584         ASSERT(static_cast<int>(offset) == offset);
2585         int insn = unconditionalBranchImmediate(false, static_cast<int>(offset));
2586         RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(where) == where);
2587         performJITMemcpy(where, &insn, sizeof(int));
2588         cacheFlush(where, sizeof(int));
2589     }
2590     
2591     static ptrdiff_t maxJumpReplacementSize()
2592     {
2593         return 4;
2594     }
2595
2596     static constexpr ptrdiff_t patchableJumpSize()
2597     {
2598         return 4;
2599     }
2600     
2601     static void replaceWithLoad(void* where)
2602     {
2603         Datasize sf;
2604         AddOp op;
2605         SetFlags S;
2606         int shift;
2607         int imm12;
2608         RegisterID rn;
2609         RegisterID rd;
2610         if (disassembleAddSubtractImmediate(where, sf, op, S, shift, imm12, rn, rd)) {
2611             ASSERT(sf == Datasize_64);
2612             ASSERT(op == AddOp_ADD);
2613             ASSERT(!S);
2614             ASSERT(!shift);
2615             ASSERT(!(imm12 & ~0xff8));
2616             int insn = loadStoreRegisterUnsignedImmediate(MemOpSize_64, false, MemOp_LOAD, encodePositiveImmediate<64>(imm12), rn, rd);
2617             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(where) == where);
2618             performJITMemcpy(where, &insn, sizeof(int));
2619             cacheFlush(where, sizeof(int));
2620         }
2621 #if !ASSERT_DISABLED
2622         else {
2623             MemOpSize size;
2624             bool V;
2625             MemOp opc;
2626             int imm12;
2627             RegisterID rn;
2628             RegisterID rt;
2629             ASSERT(disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt));
2630             ASSERT(size == MemOpSize_64);
2631             ASSERT(!V);
2632             ASSERT(opc == MemOp_LOAD);
2633             ASSERT(!(imm12 & ~0x1ff));
2634         }
2635 #endif
2636     }
2637
2638     static void replaceWithAddressComputation(void* where)
2639     {
2640         MemOpSize size;
2641         bool V;
2642         MemOp opc;
2643         int imm12;
2644         RegisterID rn;
2645         RegisterID rt;
2646         if (disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt)) {
2647             ASSERT(size == MemOpSize_64);
2648             ASSERT(!V);
2649             ASSERT(opc == MemOp_LOAD);
2650             ASSERT(!(imm12 & ~0x1ff));
2651             int insn = addSubtractImmediate(Datasize_64, AddOp_ADD, DontSetFlags, 0, imm12 * sizeof(void*), rn, rt);
2652             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(where) == where);
2653             performJITMemcpy(where, &insn, sizeof(int));
2654             cacheFlush(where, sizeof(int));
2655         }
2656 #if !ASSERT_DISABLED
2657         else {
2658             Datasize sf;
2659             AddOp op;
2660             SetFlags S;
2661             int shift;
2662             int imm12;
2663             RegisterID rn;
2664             RegisterID rd;
2665             ASSERT(disassembleAddSubtractImmediate(where, sf, op, S, shift, imm12, rn, rd));
2666             ASSERT(sf == Datasize_64);
2667             ASSERT(op == AddOp_ADD);
2668             ASSERT(!S);
2669             ASSERT(!shift);
2670             ASSERT(!(imm12 & ~0xff8));
2671         }
2672 #endif
2673     }
2674
2675     static void repatchPointer(void* where, void* valuePtr)
2676     {
2677         linkPointer(static_cast<int*>(where), valuePtr, true);
2678     }
2679
2680     static void setPointer(int* address, void* valuePtr, RegisterID rd, bool flush)
2681     {
2682         uintptr_t value = reinterpret_cast<uintptr_t>(valuePtr);
2683         int buffer[3];
2684         buffer[0] = moveWideImediate(Datasize_64, MoveWideOp_Z, 0, getHalfword(value, 0), rd);
2685         buffer[1] = moveWideImediate(Datasize_64, MoveWideOp_K, 1, getHalfword(value, 1), rd);
2686         buffer[2] = moveWideImediate(Datasize_64, MoveWideOp_K, 2, getHalfword(value, 2), rd);
2687         RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(address) == address);
2688         performJITMemcpy(address, buffer, sizeof(int) * 3);
2689
2690         if (flush)
2691             cacheFlush(address, sizeof(int) * 3);
2692     }
2693
2694     static void repatchInt32(void* where, int32_t value)
2695     {
2696         int* address = static_cast<int*>(where);
2697
2698         Datasize sf;
2699         MoveWideOp opc;
2700         int hw;
2701         uint16_t imm16;
2702         RegisterID rd;
2703         bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rd);
2704         ASSERT_UNUSED(expected, expected && !sf && (opc == MoveWideOp_Z || opc == MoveWideOp_N) && !hw);
2705         ASSERT(checkMovk<Datasize_32>(address[1], 1, rd));
2706
2707         int buffer[2];
2708         if (value >= 0) {
2709             buffer[0] = moveWideImediate(Datasize_32, MoveWideOp_Z, 0, getHalfword(value, 0), rd);
2710             buffer[1] = moveWideImediate(Datasize_32, MoveWideOp_K, 1, getHalfword(value, 1), rd);
2711         } else {
2712             buffer[0] = moveWideImediate(Datasize_32, MoveWideOp_N, 0, ~getHalfword(value, 0), rd);
2713             buffer[1] = moveWideImediate(Datasize_32, MoveWideOp_K, 1, getHalfword(value, 1), rd);
2714         }
2715         RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(where) == where);
2716         performJITMemcpy(where, &buffer, sizeof(int) * 2);
2717
2718         cacheFlush(where, sizeof(int) * 2);
2719     }
2720
2721     static void* readPointer(void* where)
2722     {
2723         int* address = static_cast<int*>(where);
2724
2725         Datasize sf;
2726         MoveWideOp opc;
2727         int hw;
2728         uint16_t imm16;
2729         RegisterID rdFirst, rd;
2730
2731         bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rdFirst);
2732         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_Z && !hw);
2733         uintptr_t result = imm16;
2734
2735         expected = disassembleMoveWideImediate(address + 1, sf, opc, hw, imm16, rd);
2736         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 1 && rd == rdFirst);
2737         result |= static_cast<uintptr_t>(imm16) << 16;
2738
2739 #if CPU(ADDRESS64)
2740         expected = disassembleMoveWideImediate(address + 2, sf, opc, hw, imm16, rd);
2741         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 2 && rd == rdFirst);
2742         result |= static_cast<uintptr_t>(imm16) << 32;
2743 #endif
2744
2745         return reinterpret_cast<void*>(result);
2746     }
2747
2748     static void* readCallTarget(void* from)
2749     {
2750         return readPointer(reinterpret_cast<int*>(from) - (isAddress64Bit() ? 4 : 3));
2751     }
2752
2753     // The static relink, repatch, and replace methods can use can
2754     // use |from| for both the write and executable address for call
2755     // and jump patching as they're modifying existing (linked) code,
2756     // so the address being provided is correct for relative address
2757     // computation.
2758     static void relinkJump(void* from, void* to)
2759     {
2760         relinkJumpOrCall<BranchType_JMP>(reinterpret_cast<int*>(from), reinterpret_cast<const int*>(from), to);
2761         cacheFlush(from, sizeof(int));
2762     }
2763     
2764     static void relinkJumpToNop(void* from)
2765     {
2766         relinkJump(from, static_cast<char*>(from) + 4);
2767     }
2768     
2769     static void relinkCall(void* from, void* to)
2770     {
2771         relinkJumpOrCall<BranchType_CALL>(reinterpret_cast<int*>(from) - 1, reinterpret_cast<const int*>(from) - 1, to);
2772         cacheFlush(reinterpret_cast<int*>(from) - 1, sizeof(int));
2773     }
2774     
2775     static void repatchCompact(void* where, int32_t value)
2776     {
2777         ASSERT(!(value & ~0x3ff8));
2778
2779         MemOpSize size;
2780         bool V;
2781         MemOp opc;
2782         int imm12;
2783         RegisterID rn;
2784         RegisterID rt;
2785         bool expected = disassembleLoadStoreRegisterUnsignedImmediate(where, size, V, opc, imm12, rn, rt);
2786         ASSERT_UNUSED(expected, expected && size >= MemOpSize_32 && !V && opc == MemOp_LOAD); // expect 32/64 bit load to GPR.
2787
2788         if (size == MemOpSize_32)
2789             imm12 = encodePositiveImmediate<32>(value);
2790         else
2791             imm12 = encodePositiveImmediate<64>(value);
2792         int insn = loadStoreRegisterUnsignedImmediate(size, V, opc, imm12, rn, rt);
2793         RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(where) == where);
2794         performJITMemcpy(where, &insn, sizeof(int));
2795
2796         cacheFlush(where, sizeof(int));
2797     }
2798
2799     unsigned debugOffset() { return m_buffer.debugOffset(); }
2800
2801 #if OS(LINUX) && COMPILER(GCC_COMPATIBLE)
2802     static inline void linuxPageFlush(uintptr_t begin, uintptr_t end)
2803     {
2804         __builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
2805     }
2806 #endif
2807
2808     static void cacheFlush(void* code, size_t size)
2809     {
2810 #if OS(IOS_FAMILY)
2811         sys_cache_control(kCacheFunctionPrepareForExecution, code, size);
2812 #elif OS(FUCHSIA)
2813         zx_cache_flush(code, size, ZX_CACHE_FLUSH_INSN);
2814 #elif OS(LINUX)
2815         size_t page = pageSize();
2816         uintptr_t current = reinterpret_cast<uintptr_t>(code);
2817         uintptr_t end = current + size;
2818         uintptr_t firstPageEnd = (current & ~(page - 1)) + page;
2819
2820         if (end <= firstPageEnd) {
2821             linuxPageFlush(current, end);
2822             return;
2823         }
2824
2825         linuxPageFlush(current, firstPageEnd);
2826
2827         for (current = firstPageEnd; current + page < end; current += page)
2828             linuxPageFlush(current, current + page);
2829
2830         linuxPageFlush(current, end);
2831 #else
2832 #error "The cacheFlush support is missing on this platform."
2833 #endif
2834     }
2835
2836     // Assembler admin methods:
2837
2838     static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JUMP_ENUM_SIZE(jumpType) - JUMP_ENUM_SIZE(jumpLinkType); }
2839
2840     static ALWAYS_INLINE bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b)
2841     {
2842         return a.from() < b.from();
2843     }
2844
2845     static bool canCompact(JumpType jumpType)
2846     {
2847         // Fixed jumps cannot be compacted
2848         return (jumpType == JumpNoCondition) || (jumpType == JumpCondition) || (jumpType == JumpCompareAndBranch) || (jumpType == JumpTestBit);
2849     }
2850
2851     static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to)
2852     {
2853         switch (jumpType) {
2854         case JumpFixed:
2855             return LinkInvalid;
2856         case JumpNoConditionFixedSize:
2857             return LinkJumpNoCondition;
2858         case JumpConditionFixedSize:
2859             return LinkJumpCondition;
2860         case JumpCompareAndBranchFixedSize:
2861             return LinkJumpCompareAndBranch;
2862         case JumpTestBitFixedSize:
2863             return LinkJumpTestBit;
2864         case JumpNoCondition:
2865             return LinkJumpNoCondition;
2866         case JumpCondition: {
2867             ASSERT(is4ByteAligned(from));
2868             ASSERT(is4ByteAligned(to));
2869             intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
2870
2871             if (isInt<21>(relative))
2872                 return LinkJumpConditionDirect;
2873
2874             return LinkJumpCondition;
2875             }
2876         case JumpCompareAndBranch:  {
2877             ASSERT(is4ByteAligned(from));
2878             ASSERT(is4ByteAligned(to));
2879             intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
2880
2881             if (isInt<21>(relative))
2882                 return LinkJumpCompareAndBranchDirect;
2883
2884             return LinkJumpCompareAndBranch;
2885         }
2886         case JumpTestBit:   {
2887             ASSERT(is4ByteAligned(from));
2888             ASSERT(is4ByteAligned(to));
2889             intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
2890
2891             if (isInt<14>(relative))
2892                 return LinkJumpTestBitDirect;
2893
2894             return LinkJumpTestBit;
2895         }
2896         default:
2897             ASSERT_NOT_REACHED();
2898         }
2899
2900         return LinkJumpNoCondition;
2901     }
2902
2903     static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to)
2904     {
2905         JumpLinkType linkType = computeJumpType(record.type(), from, to);
2906         record.setLinkType(linkType);
2907         return linkType;
2908     }
2909
2910     Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink()
2911     {
2912         std::sort(m_jumpsToLink.begin(), m_jumpsToLink.end(), linkRecordSourceComparator);
2913         return m_jumpsToLink;
2914     }
2915
2916     template<CopyFunction copy>
2917     static void ALWAYS_INLINE link(LinkRecord& record, uint8_t* from, const uint8_t* fromInstruction8, uint8_t* to)
2918     {
2919         const int* fromInstruction = reinterpret_cast<const int*>(fromInstruction8);
2920         switch (record.linkType()) {
2921         case LinkJumpNoCondition:
2922             linkJumpOrCall<BranchType_JMP, copy>(reinterpret_cast<int*>(from), fromInstruction, to);
2923             break;
2924         case LinkJumpConditionDirect:
2925             linkConditionalBranch<DirectBranch, copy>(record.condition(), reinterpret_cast<int*>(from), fromInstruction, to);
2926             break;
2927         case LinkJumpCondition:
2928             linkConditionalBranch<IndirectBranch, copy>(record.condition(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to);
2929             break;
2930         case LinkJumpCompareAndBranchDirect:
2931             linkCompareAndBranch<DirectBranch, copy>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from), fromInstruction, to);
2932             break;
2933         case LinkJumpCompareAndBranch:
2934             linkCompareAndBranch<IndirectBranch, copy>(record.condition(), record.is64Bit(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to);
2935             break;
2936         case LinkJumpTestBitDirect:
2937             linkTestAndBranch<DirectBranch, copy>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from), fromInstruction, to);
2938             break;
2939         case LinkJumpTestBit:
2940             linkTestAndBranch<IndirectBranch, copy>(record.condition(), record.bitNumber(), record.compareRegister(), reinterpret_cast<int*>(from) - 1, fromInstruction - 1, to);
2941             break;
2942         default:
2943             ASSERT_NOT_REACHED();
2944             break;
2945         }
2946     }
2947
2948 protected:
2949     template<Datasize size>
2950     static bool checkMovk(int insn, int _hw, RegisterID _rd)
2951     {
2952         Datasize sf;
2953         MoveWideOp opc;
2954         int hw;
2955         uint16_t imm16;
2956         RegisterID rd;
2957         bool expected = disassembleMoveWideImediate(&insn, sf, opc, hw, imm16, rd);
2958
2959         return expected
2960             && sf == size
2961             && opc == MoveWideOp_K
2962             && hw == _hw
2963             && rd == _rd;
2964     }
2965
2966     static void linkPointer(int* address, void* valuePtr, bool flush = false)
2967     {
2968         Datasize sf;
2969         MoveWideOp opc;
2970         int hw;
2971         uint16_t imm16;
2972         RegisterID rd;
2973         bool expected = disassembleMoveWideImediate(address, sf, opc, hw, imm16, rd);
2974         ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_Z && !hw);
2975         ASSERT(checkMovk<Datasize_64>(address[1], 1, rd));
2976         ASSERT(checkMovk<Datasize_64>(address[2], 2, rd));
2977
2978         setPointer(address, valuePtr, rd, flush);
2979     }
2980
2981     template<BranchType type, CopyFunction copy = performJITMemcpy>
2982     static void linkJumpOrCall(int* from, const int* fromInstruction, void* to)
2983     {
2984         static_assert(type == BranchType_JMP || type == BranchType_CALL, "");
2985
2986         bool link;
2987         int imm26;
2988         bool isUnconditionalBranchImmediateOrNop = disassembleUnconditionalBranchImmediate(from, link, imm26) || disassembleNop(from);
2989
2990         ASSERT_UNUSED(isUnconditionalBranchImmediateOrNop, isUnconditionalBranchImmediateOrNop);
2991         constexpr bool isCall = (type == BranchType_CALL);
2992         ASSERT_UNUSED(isCall, (link == isCall) || disassembleNop(from));
2993         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
2994         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
2995         assertIsNotTagged(to);
2996         assertIsNotTagged(fromInstruction);
2997         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(fromInstruction)) >> 2;
2998         ASSERT(static_cast<int>(offset) == offset);
2999
3000         int insn = unconditionalBranchImmediate(isCall, static_cast<int>(offset));
3001         RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
3002         copy(from, &insn, sizeof(int));
3003     }
3004
3005     template<BranchTargetType type, CopyFunction copy = performJITMemcpy>
3006     static void linkCompareAndBranch(Condition condition, bool is64Bit, RegisterID rt, int* from, const int* fromInstruction, void* to)
3007     {
3008         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
3009         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
3010         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(fromInstruction)) >> 2;
3011         ASSERT(isInt<26>(offset));
3012
3013         bool useDirect = isInt<19>(offset);
3014         ASSERT(type == IndirectBranch || useDirect);
3015
3016         if (useDirect || type == DirectBranch) {
3017             int insn = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, condition == ConditionNE, static_cast<int>(offset), rt);
3018             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
3019             copy(from, &insn, sizeof(int));
3020             if (type == IndirectBranch) {
3021                 insn = nopPseudo();
3022                 RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from + 1) == (from + 1));
3023                 copy(from + 1, &insn, sizeof(int));
3024             }
3025         } else {
3026             int insn = compareAndBranchImmediate(is64Bit ? Datasize_64 : Datasize_32, invert(condition) == ConditionNE, 2, rt);
3027             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
3028             copy(from, &insn, sizeof(int));
3029             linkJumpOrCall<BranchType_JMP, copy>(from + 1, fromInstruction + 1, to);
3030         }
3031     }
3032
3033     template<BranchTargetType type, CopyFunction copy = performJITMemcpy>
3034     static void linkConditionalBranch(Condition condition, int* from, const int* fromInstruction, void* to)
3035     {
3036         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
3037         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
3038         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(fromInstruction)) >> 2;
3039         ASSERT(isInt<26>(offset));
3040
3041         bool useDirect = isInt<19>(offset);
3042         ASSERT(type == IndirectBranch || useDirect);
3043
3044         if (useDirect || type == DirectBranch) {
3045             int insn = conditionalBranchImmediate(static_cast<int>(offset), condition);
3046             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
3047             copy(from, &insn, sizeof(int));
3048             if (type == IndirectBranch) {
3049                 insn = nopPseudo();
3050                 RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from + 1) == (from + 1));
3051                 copy(from + 1, &insn, sizeof(int));
3052             }
3053         } else {
3054             int insn = conditionalBranchImmediate(2, invert(condition));
3055             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
3056             copy(from, &insn, sizeof(int));
3057             linkJumpOrCall<BranchType_JMP, copy>(from + 1, fromInstruction + 1, to);
3058         }
3059     }
3060
3061     template<BranchTargetType type, CopyFunction copy = performJITMemcpy>
3062     static void linkTestAndBranch(Condition condition, unsigned bitNumber, RegisterID rt, int* from, const int* fromInstruction, void* to)
3063     {
3064         ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
3065         ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
3066         intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(fromInstruction)) >> 2;
3067         ASSERT(static_cast<int>(offset) == offset);
3068         ASSERT(isInt<26>(offset));
3069
3070         bool useDirect = isInt<14>(offset);
3071         ASSERT(type == IndirectBranch || useDirect);
3072
3073         if (useDirect || type == DirectBranch) {
3074             int insn = testAndBranchImmediate(condition == ConditionNE, static_cast<int>(bitNumber), static_cast<int>(offset), rt);
3075             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
3076             copy(from, &insn, sizeof(int));
3077             if (type == IndirectBranch) {
3078                 insn = nopPseudo();
3079                 RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from + 1) == (from + 1));
3080                 copy(from + 1, &insn, sizeof(int));
3081             }
3082         } else {
3083             int insn = testAndBranchImmediate(invert(condition) == ConditionNE, static_cast<int>(bitNumber), 2, rt);
3084             RELEASE_ASSERT(roundUpToMultipleOf<instructionSize>(from) == from);
3085             copy(from, &insn, sizeof(int));
3086             linkJumpOrCall<BranchType_JMP, copy>(from + 1, fromInstruction + 1, to);
3087         }
3088     }
3089
3090     template<BranchType type>
3091     static void relinkJumpOrCall(int* from, const int* fromInstruction, void* to)
3092     {
3093         static_assert(type == BranchType_JMP || type == BranchType_CALL, "");
3094         if ((type == BranchType_JMP) && disassembleNop(from)) {
3095             unsigned op01;
3096             int imm19;
3097             Condition condition;
3098             bool isConditionalBranchImmediate = disassembleConditionalBranchImmediate(from - 1, op01, imm19, condition);
3099
3100             if (isConditionalBranchImmediate) {
3101                 ASSERT_UNUSED(op01, !op01);
3102                 ASSERT(type == BranchType_JMP);
3103
3104                 if (imm19 == 8)
3105                     condition = invert(condition);
3106
3107                 linkConditionalBranch<IndirectBranch>(condition, from - 1, fromInstruction - 1, to);
3108                 return;
3109             }
3110
3111             Datasize opSize;
3112             bool op;
3113             RegisterID rt;
3114             bool isCompareAndBranchImmediate = disassembleCompareAndBranchImmediate(from - 1, opSize, op, imm19, rt);
3115
3116             if (isCompareAndBranchImmediate) {
3117                 if (imm19 == 8)
3118                     op = !op;
3119
3120                 linkCompareAndBranch<IndirectBranch>(op ? ConditionNE : ConditionEQ, opSize == Datasize_64, rt, from - 1, fromInstruction - 1, to);
3121                 return;
3122             }
3123
3124             int imm14;
3125             unsigned bitNumber;
3126             bool isTestAndBranchImmediate = disassembleTestAndBranchImmediate(from - 1, op, bitNumber, imm14, rt);
3127
3128             if (isTestAndBranchImmediate) {
3129                 if (imm14 == 8)
3130                     op = !op;
3131
3132                 linkTestAndBranch<IndirectBranch>(op ? ConditionNE : ConditionEQ, bitNumber, rt, from - 1, fromInstruction - 1, to);
3133                 return;
3134             }
3135         }
3136
3137         linkJumpOrCall<type>(from, fromInstruction, to);
3138     }
3139
3140     static int* addressOf(void* code, AssemblerLabel label)
3141     {
3142         return reinterpret_cast<int*>(static_cast<char*>(code) + label.m_offset);
3143     }
3144
3145     static RegisterID disassembleXOrSp(int reg) { return reg == 31 ? ARM64Registers::sp : static_cast<RegisterID>(reg); }
3146     static RegisterID disassembleXOrZr(int reg) { return reg == 31 ? ARM64Registers::zr : static_cast<RegisterID>(reg); }
3147     static RegisterID disassembleXOrZrOrSp(bool useZr, int reg) { return reg == 31 ? (useZr ? ARM64Registers::zr : ARM64Registers::sp) : static_cast<RegisterID>(reg); }
3148
3149     static bool disassembleAddSubtractImmediate(void* address, Datasize& sf, AddOp& op, SetFlags& S, int& shift, int& imm12, RegisterID& rn, RegisterID& rd)
3150     {
3151         int insn = *static_cast<int*>(address);
3152         sf = static_cast<Datasize>((insn >> 31) & 1);
3153         op = static_cast<AddOp>((insn >> 30) & 1);
3154         S = static_cast<SetFlags>((insn >> 29) & 1);
3155         shift = (insn >> 22) & 3;
3156         imm12 = (insn >> 10) & 0x3ff;
3157         rn = disassembleXOrSp((insn >> 5) & 0x1f);
3158         rd = disassembleXOrZrOrSp(S, insn & 0x1f);
3159         return (insn & 0x1f000000) == 0x11000000;
3160     }
3161
3162     static bool disassembleLoadStoreRegisterUnsignedImmediate(void* address, MemOpSize& size, bool& V, MemOp& opc, int& imm12, RegisterID& rn, RegisterID& rt)
3163     {
3164         int insn = *static_cast<int*>(address);
3165         size = static_cast<MemOpSize>((insn >> 30) & 3);
3166         V = (insn >> 26) & 1;
3167         opc = static_cast<MemOp>((insn >> 22) & 3);
3168         imm12 = (insn >> 10) & 0xfff;
3169         rn = disassembleXOrSp((insn >> 5) & 0x1f);
3170         rt = disassembleXOrZr(insn & 0x1f);
3171         return (insn & 0x3b000000) == 0x39000000;
3172     }
3173
3174     static bool disassembleMoveWideImediate(void* address, Datasize& sf, MoveWideOp& opc, int& hw, uint16_t& imm16, RegisterID& rd)
3175     {
3176         int insn = *static_cast<int*>(address);
3177         sf = static_cast<Datasize>((insn >> 31) & 1);
3178         opc = static_cast<MoveWideOp>((insn >> 29) & 3);
3179         hw = (insn >> 21) & 3;
3180         imm16 = insn >> 5;
3181         rd = disassembleXOrZr(insn & 0x1f);
3182         return (insn & 0x1f800000) == 0x12800000;
3183     }
3184
3185     static bool disassembleNop(void* address)
3186     {
3187         unsigned insn = *static_cast<unsigned*>(address);
3188         return insn == 0xd503201f;
3189     }
3190
3191     static bool disassembleCompareAndBranchImmediate(void* address, Datasize& sf, bool& op, int& imm19, RegisterID& rt)
3192     {
3193         int insn = *static_cast<int*>(address);
3194         sf = static_cast<Datasize>((insn >> 31) & 1);
3195         op = (insn >> 24) & 0x1;
3196         imm19 = (insn << 8) >> 13;
3197         rt = static_cast<RegisterID>(insn & 0x1f);
3198         return (insn & 0x7e000000) == 0x34000000;
3199         
3200     }
3201
3202     static bool disassembleConditionalBranchImmediate(void* address, unsigned& op01, int& imm19, Condition &condition)
3203     {
3204         int insn = *static_cast<int*>(address);
3205         op01 = ((insn >> 23) & 0x2) | ((insn >> 4) & 0x1);
3206         imm19 = (insn << 8) >> 13;
3207         condition = static_cast<Condition>(insn & 0xf);
3208         return (insn & 0xfe000000) == 0x54000000;
3209     }
3210
3211     static bool disassembleTestAndBranchImmediate(void* address, bool& op, unsigned& bitNumber, int& imm14, RegisterID& rt)
3212     {
3213         int insn = *static_cast<int*>(address);
3214         op = (insn >> 24) & 0x1;
3215         imm14 = (insn << 13) >> 18;
3216         bitNumber = static_cast<unsigned>((((insn >> 26) & 0x20)) | ((insn >> 19) & 0x1f));
3217         rt = static_cast<RegisterID>(insn & 0x1f);
3218         return (insn & 0x7e000000) == 0x36000000;
3219         
3220     }
3221
3222     static bool disassembleUnconditionalBranchImmediate(void* address, bool& op, int& imm26)
3223     {
3224         int insn = *static_cast<int*>(address);
3225         op = (insn >> 31) & 1;
3226         imm26 = (insn << 6) >> 6;
3227         return (insn & 0x7c000000) == 0x14000000;
3228     }
3229
3230     static int xOrSp(RegisterID reg)
3231     {
3232         ASSERT(!isZr(reg));
3233         ASSERT(!isIOS() || reg != ARM64Registers::x18);
3234         return reg;
3235     }
3236     static int xOrZr(RegisterID reg)
3237     {
3238         ASSERT(!isSp(reg));
3239         ASSERT(!isIOS() || reg != ARM64Registers::x18);
3240         return reg & 31;
3241     }
3242     static FPRegisterID xOrZrAsFPR(RegisterID reg) { return static_cast<FPRegisterID>(xOrZr(reg)); }
3243     static int xOrZrOrSp(bool useZr, RegisterID reg) { return useZr ? xOrZr(reg) : xOrSp(reg); }
3244
3245     ALWAYS_INLINE void insn(int instruction)
3246     {
3247         m_buffer.putInt(instruction);
3248     }
3249
3250     ALWAYS_INLINE static int addSubtractExtendedRegister(Datasize sf, AddOp op, SetFlags S, RegisterID rm, ExtendType option, int imm3, RegisterID rn, RegisterID rd)
3251     {
3252         ASSERT(imm3 < 5);
3253         // The only allocated values for opt is 0.
3254         const int opt = 0;
3255         return (0x0b200000 | sf << 31 | op << 30 | S << 29 | opt << 22 | xOrZr(rm) << 16 | option << 13 | (imm3 & 0x7) << 10 | xOrSp(rn) << 5 | xOrZrOrSp(S, rd));
3256     }
3257
3258     ALWAYS_INLINE static int addSubtractImmediate(Datasize sf, AddOp op, SetFlags S, int shift, int imm12, RegisterID rn, RegisterID rd)
3259     {
3260         ASSERT(shift < 2);
3261         ASSERT(isUInt12(imm12));
3262         return (0x11000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | (imm12 & 0xfff) << 10 | xOrSp(rn) << 5 | xOrZrOrSp(S, rd));
3263     }
3264
3265     ALWAYS_INLINE static int addSubtractShiftedRegister(Datasize sf, AddOp op, SetFlags S, ShiftType shift, RegisterID rm, int imm6, RegisterID rn, RegisterID rd)
3266     {
3267         ASSERT(shift < 3);
3268         ASSERT(!(imm6 & (sf ? ~63 : ~31)));
3269         return (0x0b000000 | sf << 31 | op << 30 | S << 29 | shift << 22 | xOrZr(rm) << 16 | (imm6 & 0x3f) << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3270     }
3271
3272     ALWAYS_INLINE static int addSubtractWithCarry(Datasize sf, AddOp op, SetFlags S, RegisterID rm, RegisterID rn, RegisterID rd)
3273     {
3274         const int opcode2 = 0;
3275         return (0x1a000000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | opcode2 << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3276     }
3277
3278     ALWAYS_INLINE static int bitfield(Datasize sf, BitfieldOp opc, int immr, int imms, RegisterID rn, RegisterID rd)
3279     {
3280         ASSERT(immr < (sf ? 64 : 32));
3281         ASSERT(imms < (sf ? 64 : 32));
3282         const int N = sf;
3283         return (0x13000000 | sf << 31 | opc << 29 | N << 22 | immr << 16 | imms << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3284     }
3285
3286     // 'op' means negate
3287     ALWAYS_INLINE static int compareAndBranchImmediate(Datasize sf, bool op, int32_t imm19, RegisterID rt)
3288     {
3289         ASSERT(imm19 == (imm19 << 13) >> 13);
3290         return (0x34000000 | sf << 31 | op << 24 | (imm19 & 0x7ffff) << 5 | xOrZr(rt));
3291     }
3292
3293     ALWAYS_INLINE static int conditionalBranchImmediate(int32_t imm19, Condition cond)
3294     {
3295         ASSERT(imm19 == (imm19 << 13) >> 13);
3296         ASSERT(!(cond & ~15));
3297         // The only allocated values for o1 & o0 are 0.
3298         const int o1 = 0;
3299         const int o0 = 0;
3300         return (0x54000000 | o1 << 24 | (imm19 & 0x7ffff) << 5 | o0 << 4 | cond);
3301     }
3302
3303     ALWAYS_INLINE static int conditionalCompareImmediate(Datasize sf, AddOp op, int imm5, Condition cond, RegisterID rn, int nzcv)
3304     {
3305         ASSERT(!(imm5 & ~0x1f));
3306         ASSERT(nzcv < 16);
3307         const int S = 1;
3308         const int o2 = 0;
3309         const int o3 = 0;
3310         return (0x1a400800 | sf << 31 | op << 30 | S << 29 | (imm5 & 0x1f) << 16 | cond << 12 | o2 << 10 | xOrZr(rn) << 5 | o3 << 4 | nzcv);
3311     }
3312
3313     ALWAYS_INLINE static int conditionalCompareRegister(Datasize sf, AddOp op, RegisterID rm, Condition cond, RegisterID rn, int nzcv)
3314     {
3315         ASSERT(nzcv < 16);
3316         const int S = 1;
3317         const int o2 = 0;
3318         const int o3 = 0;
3319         return (0x1a400000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | cond << 12 | o2 << 10 | xOrZr(rn) << 5 | o3 << 4 | nzcv);
3320     }
3321
3322     // 'op' means negate
3323     // 'op2' means increment
3324     ALWAYS_INLINE static int conditionalSelect(Datasize sf, bool op, RegisterID rm, Condition cond, bool op2, RegisterID rn, RegisterID rd)
3325     {
3326         const int S = 0;
3327         return (0x1a800000 | sf << 31 | op << 30 | S << 29 | xOrZr(rm) << 16 | cond << 12 | op2 << 10 | xOrZr(rn) << 5 | xOrZr(rd));
3328     }
3329
3330     ALWAYS_INLINE static int dataProcessing1Source(Datasize sf, DataOp1Source opcode, RegisterID rn, RegisterID rd)