0851d56a90318c688bfa59d69500ce5c34ad816b
[WebKit-https.git] / Source / JavaScriptCore / disassembler / ARM64 / A64DOpcode.h
1 /*
2  * Copyright (C) 2012, 2016 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 #include <wtf/Assertions.h>
29 #include <stdint.h>
30
31 namespace JSC { namespace ARM64Disassembler {
32
33 class A64DOpcode {
34 private:
35     class OpcodeGroup {
36         WTF_MAKE_FAST_ALLOCATED;
37     public:
38         OpcodeGroup(uint32_t opcodeMask, uint32_t opcodePattern, const char* (*format)(A64DOpcode*))
39             : m_opcodeMask(opcodeMask)
40             , m_opcodePattern(opcodePattern)
41             , m_format(format)
42             , m_next(0)
43         {
44         }
45
46         void setNext(OpcodeGroup* next)
47         {
48             m_next = next;
49         }
50
51         OpcodeGroup* next()
52         {
53             return m_next;
54         }
55
56         bool matches(uint32_t opcode)
57         {
58             return (opcode & m_opcodeMask) == m_opcodePattern;
59         }
60
61         const char* format(A64DOpcode* thisObj)
62         {
63             return m_format(thisObj);
64         }
65
66     private:
67         uint32_t m_opcodeMask;
68         uint32_t m_opcodePattern;
69         const char* (*m_format)(A64DOpcode*);
70         OpcodeGroup* m_next;
71     };
72
73 public:
74     static void init();
75
76     A64DOpcode()
77         : m_opcode(0)
78         , m_bufferOffset(0)
79     {
80         init();
81         m_formatBuffer[0] = '\0';
82     }
83
84     const char* disassemble(uint32_t* currentPC);
85
86 protected:
87     void setPCAndOpcode(uint32_t*, uint32_t);
88     const char* format();
89
90     static const char* const s_conditionNames[16];
91     static const char* const s_shiftNames[4];
92     static const char* const s_optionName[8];
93     static const char s_FPRegisterPrefix[5];
94
95     static const char* conditionName(unsigned condition) { return s_conditionNames[condition & 0xf]; }
96     static const char* shiftName(unsigned shiftValue) { return s_shiftNames[shiftValue & 0x3]; }
97     const char* optionName() { return s_optionName[option()]; }
98     static char FPRegisterPrefix(unsigned FPRegisterSize)
99     {
100         if (FPRegisterSize > 4)
101             FPRegisterSize = 4;
102         return s_FPRegisterPrefix[FPRegisterSize];
103     }
104
105     unsigned opcodeGroupNumber(uint32_t opcode) { return (opcode >> 24) & 0x1f; }
106
107     bool is64Bit() { return m_opcode & 0x80000000; }
108     unsigned size() { return m_opcode >> 30; }
109     unsigned option() { return (m_opcode >> 13) & 0x7; }
110     unsigned rd() { return m_opcode & 0x1f; }
111     unsigned rt() { return m_opcode & 0x1f; }
112     unsigned rn() { return (m_opcode >> 5) & 0x1f; }
113     unsigned rm() { return (m_opcode >> 16) & 0x1f; }
114
115     void bufferPrintf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
116
117     void appendInstructionName(const char* instructionName)
118     {
119         bufferPrintf("   %-8.8s", instructionName);
120     }
121
122     void appendRegisterName(unsigned registerNumber, bool is64Bit = true);
123     void appendSPOrRegisterName(unsigned registerNumber, bool is64Bit = true)
124     {
125         if (registerNumber == 31) {
126             bufferPrintf(is64Bit ? "sp" : "wsp");
127             return;
128         }
129         appendRegisterName(registerNumber, is64Bit);
130     }
131
132     void appendZROrRegisterName(unsigned registerNumber, bool is64Bit = true)
133     {
134         if (registerNumber == 31) {
135             bufferPrintf(is64Bit ? "xzr" : "wzr");
136             return;
137         }
138         appendRegisterName(registerNumber, is64Bit);
139     }
140
141     void appendFPRegisterName(unsigned registerNumber, unsigned registerSize);
142
143     void appendSeparator()
144     {
145         bufferPrintf(", ");
146     }
147
148     void appendCharacter(const char c)
149     {
150         bufferPrintf("%c", c);
151     }
152
153     void appendString(const char* string)
154     {
155         bufferPrintf("%s", string);
156     }
157
158     void appendShiftType(unsigned shiftValue)
159     {
160         bufferPrintf("%s ", shiftName(shiftValue));
161     }
162
163     void appendSignedImmediate(int immediate)
164     {
165         bufferPrintf("#%d", immediate);
166     }
167
168     void appendSignedImmediate64(int64_t immediate)
169     {
170         bufferPrintf("#%" PRIi64, immediate);
171     }
172     
173     void appendUnsignedImmediate(unsigned immediate)
174     {
175         bufferPrintf("#%u", immediate);
176     }
177
178     void appendUnsignedHexImmediate(unsigned immediate)
179     {
180         bufferPrintf("#0x%x", immediate);
181     }
182     
183     void appendUnsignedImmediate64(uint64_t immediate)
184     {
185         bufferPrintf("#0x%" PRIx64, immediate);
186     }
187
188     void appendPCRelativeOffset(uint32_t* pc, int32_t immediate)
189     {
190         bufferPrintf("0x%" PRIx64, reinterpret_cast<uint64_t>(pc + immediate));
191     }
192
193     void appendShiftAmount(unsigned amount)
194     {
195         bufferPrintf("lsl #%u", 16 * amount);
196     }
197
198     static const int bufferSize = 81;
199
200     char m_formatBuffer[bufferSize];
201     uint32_t* m_currentPC;
202     uint32_t m_opcode;
203     int m_bufferOffset;
204
205 private:
206     static OpcodeGroup* opcodeTable[32];
207
208     static bool s_initialized;
209 };
210
211 #define DEFINE_STATIC_FORMAT(klass, thisObj) \
212    static const char* format(A64DOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); }
213
214 class A64DOpcodeAddSubtract : public A64DOpcode {
215 private:
216     static const char* const s_opNames[4];
217
218 public:
219     const char* opName() { return s_opNames[opAndS()]; }
220     const char* cmpName() { return op() ? "cmp" : "cmn"; }
221
222     bool isCMP() { return (sBit() && rd() == 31); }
223     unsigned op() { return (m_opcode >> 30) & 0x1; }
224     unsigned sBit() { return (m_opcode >> 29) & 0x1; }
225     unsigned opAndS() { return (m_opcode >> 29) & 0x3; }
226 };
227
228 class A64DOpcodeAddSubtractImmediate : public A64DOpcodeAddSubtract {
229 public:
230     static const uint32_t mask = 0x1f000000;
231     static const uint32_t pattern = 0x11000000;
232
233     DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractImmediate, thisObj);
234
235     const char* format();
236
237     bool isMovSP() { return (!opAndS() && !immed12() && ((rd() == 31) || rn() == 31)); }
238     unsigned shift() { return (m_opcode >> 22) & 0x3; }
239     unsigned immed12() { return (m_opcode >> 10) & 0xfff; }
240 };
241
242 class A64DOpcodeAddSubtractExtendedRegister : public A64DOpcodeAddSubtract {
243 public:
244     static const uint32_t mask = 0x1fe00000;
245     static const uint32_t pattern = 0x0b200000;
246
247     DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractExtendedRegister, thisObj);
248
249     const char* format();
250
251     unsigned immediate3() { return (m_opcode >> 10) & 0x7; }
252 };
253
254 class A64DOpcodeAddSubtractShiftedRegister : public A64DOpcodeAddSubtract {
255 public:
256     static const uint32_t mask = 0x1f200000;
257     static const uint32_t pattern = 0x0b000000;
258
259     DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractShiftedRegister, thisObj);
260
261     const char* format();
262
263     bool isNeg() { return (op() && rn() == 31); }
264     const char* negName() { return sBit() ? "negs" : "neg"; }
265     unsigned shift() { return (m_opcode >> 22) & 0x3; }
266     int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
267 };
268
269 class A64DOpcodeBitfield : public A64DOpcode {
270 private:
271     static const char* const s_opNames[3];
272     static const char* const s_extendPseudoOpNames[3][3];
273     static const char* const s_insertOpNames[3];
274     static const char* const s_extractOpNames[3];
275
276 public:
277     static const uint32_t mask = 0x1f800000;
278     static const uint32_t pattern = 0x13000000;
279
280     DEFINE_STATIC_FORMAT(A64DOpcodeBitfield, thisObj);
281
282     const char* format();
283
284     const char* opName() { return s_opNames[opc()]; }
285     const char* extendPseudoOpNames(unsigned opSize) { return s_extendPseudoOpNames[opc()][opSize]; }
286     const char* insertOpNames() { return s_insertOpNames[opc()]; }
287     const char* extractOpNames() { return s_extractOpNames[opc()]; }
288
289     unsigned opc() { return (m_opcode >> 29) & 0x3; }
290     unsigned nBit() { return (m_opcode >> 22) & 0x1; }
291     unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
292     unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
293 };
294
295 class A64DOpcodeCompareAndBranchImmediate : public A64DOpcode {
296 public:
297     static const uint32_t mask = 0x7e000000;
298     static const uint32_t pattern = 0x34000000;
299
300     DEFINE_STATIC_FORMAT(A64DOpcodeCompareAndBranchImmediate, thisObj);
301
302     const char* format();
303
304     unsigned opBit() { return (m_opcode >> 24) & 0x1; }
305     int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
306 };
307
308 class A64DOpcodeConditionalBranchImmediate : public A64DOpcode {
309 public:
310     static const uint32_t mask = 0xff000010;
311     static const uint32_t pattern = 0x54000000;
312
313     DEFINE_STATIC_FORMAT(A64DOpcodeConditionalBranchImmediate, thisObj);
314
315     const char* format();
316
317     unsigned condition() { return m_opcode & 0xf; }
318     int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
319 };
320
321 class A64DOpcodeConditionalSelect : public A64DOpcode {
322 private:
323     static const char* const s_opNames[4];
324
325 public:
326     static const uint32_t mask = 0x1fe00000;
327     static const uint32_t pattern = 0x1a800000;
328
329     DEFINE_STATIC_FORMAT(A64DOpcodeConditionalSelect, thisObj);
330
331     const char* format();
332
333     const char* opName() { return s_opNames[opNum()]; }
334     unsigned opNum() { return (op() << 1 | (op2() & 0x1)); }
335     unsigned op() { return (m_opcode >> 30) & 0x1; }
336     unsigned sBit() { return (m_opcode >> 29) & 0x1; }
337     unsigned condition() { return (m_opcode >> 12) & 0xf; }
338     unsigned op2() { return (m_opcode >> 10) & 0x3; }
339 };
340
341 class A64DOpcodeDataProcessing1Source : public A64DOpcode {
342 private:
343     static const char* const s_opNames[8];
344     static const char* const s_pacAutOpNames[18];
345     
346 public:
347     static const uint32_t mask = 0x5fe00000;
348     static const uint32_t pattern = 0x5ac00000;
349     
350     DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing1Source, thisObj);
351     
352     const char* format();
353     
354     const char* opName() { return s_opNames[opNameIndex()]; }
355     unsigned sBit() { return (m_opcode >> 29) & 0x1; }
356     unsigned opCode() { return (m_opcode >> 10) & 0x3f; }
357     unsigned opCode2() { return (m_opcode >> 16) & 0x1f; }
358     unsigned opNameIndex() { return (opCode() & 0x7); }
359 };
360
361 class A64DOpcodeDataProcessing2Source : public A64DOpcode {
362 private:
363     static const char* const s_opNames[16];
364
365 public:
366     static const uint32_t mask = 0x5fe00000;
367     static const uint32_t pattern = 0x1ac00000;
368
369     DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing2Source, thisObj);
370
371     const char* format();
372
373     const char* opName() { return s_opNames[opNameIndex()]; }
374     unsigned sBit() { return (m_opcode >> 29) & 0x1; }
375     unsigned opCode() { return (m_opcode >> 10) & 0x3f; }
376     unsigned opNameIndex() { return (m_opcode >> 10) & 0xf; }
377 };
378
379 class A64DOpcodeDataProcessing3Source : public A64DOpcode {
380 private:
381     static const char* const s_opNames[16];
382     static const char* const s_pseudoOpNames[16];
383
384 public:
385     static const uint32_t mask = 0x1f000000;
386     static const uint32_t pattern = 0x1b000000;
387
388     DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing3Source, thisObj);
389
390     const char* format();
391
392     const char* opName() { return ra() == 31 ? s_pseudoOpNames[opNum() & 0xf] : s_opNames[opNum() & 0xf]; }
393     unsigned ra() { return (m_opcode >> 10) & 0x1f; }
394     unsigned op54() { return (m_opcode >> 29) & 0x3; }
395     unsigned op31() { return (m_opcode >> 21) & 0x7; }
396     unsigned op0() { return (m_opcode >> 15) & 0x1; }
397     unsigned opNum() { return ((m_opcode >> 25) & 0x30) | ((m_opcode >> 20) & 0xe) | ((m_opcode >> 15) & 0x1); }
398 };
399
400 class A64OpcodeExceptionGeneration : public A64DOpcode {
401 public:
402     static const uint32_t mask = 0xff000000;
403     static const uint32_t pattern = 0xd4000000;
404
405     DEFINE_STATIC_FORMAT(A64OpcodeExceptionGeneration, thisObj);
406
407     const char* format();
408
409     unsigned opc() { return (m_opcode>>21) & 0x7; }
410     unsigned op2() { return (m_opcode>>2) & 0x7; }
411     unsigned ll() { return m_opcode & 0x3; }
412     int immediate16() { return (static_cast<int>((m_opcode >> 5) & 0xffff) << 16) >> 16; }
413 };
414
415 class A64DOpcodeExtract : public A64DOpcode {
416 public:
417     static const uint32_t mask = 0x1f800000;
418     static const uint32_t pattern = 0x13800000;
419
420     DEFINE_STATIC_FORMAT(A64DOpcodeExtract, thisObj);
421
422     const char* format();
423
424     unsigned op21() { return (m_opcode >> 29) & 0x3; }
425     unsigned nBit() { return (m_opcode >> 22) & 0x1; }
426     unsigned o0Bit() { return (m_opcode >> 21) & 0x1; }
427     unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
428 };
429
430 class A64DOpcodeFloatingPointOps : public A64DOpcode {
431 public:
432     unsigned mBit() { return (m_opcode >> 31) & 0x1; }
433     unsigned sBit() { return (m_opcode >> 29) & 0x1; }
434     unsigned type() { return (m_opcode >> 22) & 0x3; }
435 };
436
437 class A64DOpcodeFloatingPointCompare : public A64DOpcodeFloatingPointOps {
438 private:
439     static const char* const s_opNames[16];
440     
441 public:
442     static const uint32_t mask = 0x5f203c00;
443     static const uint32_t pattern = 0x1e202000;
444     
445     DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointCompare, thisObj);
446     
447     const char* format();
448
449     const char* opName() { return (opNum() & 0x2) ? "fcmpe" : "fcmp"; }
450
451     unsigned op() { return (m_opcode >> 14) & 0x3; }
452     unsigned opCode2() { return m_opcode & 0x1f; }
453     unsigned opNum() { return (m_opcode >> 3) & 0x3; }
454 };
455
456 class A64DOpcodeFloatingPointConditionalSelect : public A64DOpcodeFloatingPointOps {
457 public:
458     static const uint32_t mask = 0x5f200c00;
459     static const uint32_t pattern = 0x1e200c00;
460     
461     DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointConditionalSelect, thisObj);
462     
463     const char* format();
464     
465     const char* opName() { return "fcsel"; }
466     
467     unsigned condition() { return (m_opcode >> 12) & 0xf; }
468 };
469
470 class A64DOpcodeFloatingPointDataProcessing1Source : public A64DOpcodeFloatingPointOps {
471 private:
472     static const char* const s_opNames[16];
473
474 public:
475     static const uint32_t mask = 0x5f207c00;
476     static const uint32_t pattern = 0x1e204000;
477
478     DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing1Source, thisObj);
479
480     const char* format();
481
482     const char* opName() { return s_opNames[opNum()]; }
483
484     unsigned opNum() { return (m_opcode >> 15) & 0x3f; }
485 };
486
487 class A64DOpcodeFloatingPointDataProcessing2Source : public A64DOpcodeFloatingPointOps {
488 private:
489     static const char* const s_opNames[16];
490
491 public:
492     static const uint32_t mask = 0x5f200800;
493     static const uint32_t pattern = 0x1e200800;
494
495     DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing2Source, thisObj);
496
497     const char* format();
498
499     const char* opName() { return s_opNames[opNum()]; }
500
501     unsigned opNum() { return (m_opcode >> 12) & 0xf; }
502 };
503
504 class A64DOpcodeFloatingFixedPointConversions : public A64DOpcodeFloatingPointOps {
505 private:
506     static const char* const s_opNames[4];
507     
508 public:
509     static const uint32_t mask = 0x5f200000;
510     static const uint32_t pattern = 0x1e000000;
511     
512     DEFINE_STATIC_FORMAT(A64DOpcodeFloatingFixedPointConversions, thisObj);
513     
514     const char* format();
515     
516     const char* opName() { return s_opNames[opNum()]; }
517     unsigned rmode() { return (m_opcode >> 19) & 0x3; }
518     unsigned opcode() { return (m_opcode >> 16) & 0x7; }
519     unsigned scale() { return (m_opcode >> 10) & 0x3f; }
520     unsigned opNum() { return (m_opcode >> 16) & 0x3; }
521 };
522
523 class A64DOpcodeFloatingPointIntegerConversions : public A64DOpcodeFloatingPointOps {
524 private:
525     static const char* const s_opNames[32];
526     
527 public:
528     static const uint32_t mask = 0x5f20fc00;
529     static const uint32_t pattern = 0x1e200000;
530
531     DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointIntegerConversions, thisObj);
532
533     const char* format();
534
535     const char* opName() { return s_opNames[opNum()]; }
536     unsigned rmode() { return (m_opcode >> 19) & 0x3; }
537     unsigned opcode() { return (m_opcode >> 16) & 0x7; }
538     unsigned opNum() { return (m_opcode >> 16) & 0x1f; }
539 };
540
541 class A64DOpcodeSystem : public A64DOpcode {
542 public:
543     unsigned lBit() { return (m_opcode >> 21) & 0x1; }
544     unsigned op0() { return (m_opcode >> 19) & 0x3; }
545     unsigned op1() { return (m_opcode >> 16) & 0x7; }
546     unsigned crN() { return (m_opcode >> 12) & 0xf; }
547     unsigned crM() { return (m_opcode >> 8) & 0xf; }
548     unsigned op2() { return (m_opcode >> 5) & 0x7; }
549 };
550
551 class A64DOpcodeMSRImmediate : public A64DOpcodeSystem {
552 public:
553     static const uint32_t mask = 0xfff8f01f;
554     static const uint32_t pattern = 0xd500401f;
555
556     DEFINE_STATIC_FORMAT(A64DOpcodeMSRImmediate, thisObj);
557
558     const char* format();
559 };
560
561 class A64DOpcodeMSROrMRSRegister : public A64DOpcodeSystem {
562 public:
563     static const uint32_t mask = 0xffd00000;
564     static const uint32_t pattern = 0xd5100000;
565
566     DEFINE_STATIC_FORMAT(A64DOpcodeMSROrMRSRegister, thisObj);
567
568     const char* format();
569
570     const char* opName() { return lBit() ? "mrs" : "msr"; }
571     unsigned systemRegister() { return ((op0() << 14) | (op1() << 11) | (crN() << 7) | (crM() << 3) | op2()); }
572 };
573
574 class A64DOpcodeHint : public A64DOpcodeSystem {
575 private:
576     static const char* const s_opNames[32];
577
578 public:
579     static const uint32_t mask = 0xfffff01f;
580     static const uint32_t pattern = 0xd503201f;
581
582     DEFINE_STATIC_FORMAT(A64DOpcodeHint, thisObj);
583
584     const char* format();
585
586     const char* opName();
587     unsigned immediate7() { return (m_opcode >> 5) & 0x7f; }
588 };
589
590 class A64DOpcodeSystemSync : public A64DOpcodeSystem {
591     static const char* const s_opNames[8];
592     static const char* const s_optionNames[16];
593
594 public:
595     static const uint32_t mask = 0xfffff01f;
596     static const uint32_t pattern = 0xd503301f;
597
598     DEFINE_STATIC_FORMAT(A64DOpcodeSystemSync, thisObj);
599
600     const char* format();
601
602     const char* opName() { return s_opNames[op2()]; }
603     const char* option() { return s_optionNames[crM()]; }
604 };
605
606 class A64DOpcodeLoadStore : public A64DOpcode {
607 private:
608     static const char* const s_opNames[32];
609
610 protected:
611     const char* opName()
612     {
613         return s_opNames[opNumber()];
614     }
615
616     unsigned size() { return (m_opcode >> 30) & 0x3; }
617     unsigned vBit() { return (m_opcode >> 26) & 0x1; }
618     unsigned opc() { return (m_opcode >> 22) & 0x3; }
619     unsigned opNumber() { return (size() <<3 ) | (vBit() << 2) | opc(); }
620     bool is64BitRT() { return ((opNumber() & 0x17) == 0x02) || ((opNumber() & 0x1e) == 0x18); }
621 };
622
623 class A64DOpcodeLoadStoreExclusive : public A64DOpcodeLoadStore {
624 private:
625     static const char* const s_opNames[64];
626
627 public:
628     static const uint32_t mask = 0x3f000000;
629     static const uint32_t pattern = 0x08000000;
630
631     DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreExclusive, thisObj);
632
633     const char* format();
634
635     const char* opName()
636     {
637         return s_opNames[opNumber()];
638     }
639
640     unsigned rs() { return rm(); }
641     unsigned rt2() { return (m_opcode >> 10) & 0x1f; }
642     unsigned o0() { return (m_opcode >> 15) & 0x1; }
643     unsigned o1() { return (m_opcode >> 21) & 0x1; }
644     unsigned o2() { return (m_opcode >> 23) & 0x1; }
645     unsigned loadBit() { return (m_opcode >> 22) & 0x1; }
646     unsigned opNumber() { return (size() << 4 ) | (o2() << 3) | (loadBit() << 2) | (o1() << 1) | o0(); }
647     bool isPairOp() { return (size() & 0x10) && o1(); }
648 };
649
650 class A64DOpcodeLoadStoreImmediate : public A64DOpcodeLoadStore {
651 private:
652     static const char* const s_unprivilegedOpNames[32];
653     static const char* const s_unscaledOpNames[32];
654
655 public:
656     static const uint32_t mask = 0x3b200000;
657     static const uint32_t pattern = 0x38000000;
658
659     DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreImmediate, thisObj);
660
661     const char* format();
662
663     const char* unprivilegedOpName()
664     {
665         return s_unprivilegedOpNames[opNumber()];
666     }
667     const char* unscaledOpName()
668     {
669         return s_unscaledOpNames[opNumber()];
670     }
671     unsigned type() { return (m_opcode >> 10) & 0x3; }
672     int immediate9() { return (static_cast<int>((m_opcode >> 12) & 0x1ff) << 23) >> 23; }
673 };
674
675 class A64DOpcodeLoadStoreRegisterOffset : public A64DOpcodeLoadStore {
676 public:
677     static const uint32_t mask = 0x3b200c00;
678     static const uint32_t pattern = 0x38200800;
679
680     DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterOffset, thisObj);
681
682     const char* format();
683
684     unsigned option() { return (m_opcode >> 13) & 0x7; }
685     int sBit() { return (m_opcode >> 12) & 0x1; }
686 };
687
688 class A64DOpcodeLoadStoreAuthenticated : public A64DOpcodeLoadStore {
689 private:
690     static const char* const s_opNames[2];
691     
692 protected:
693     const char* opName()
694     {
695         return s_opNames[opNumber()];
696     }
697
698 public:
699     static const uint32_t mask = 0xff200400;
700     static const uint32_t pattern = 0xf8200400;
701     
702     DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreAuthenticated, thisObj);
703     
704     const char* format();
705
706     unsigned opNum() { return mBit(); }
707     unsigned mBit() { return (m_opcode >> 23) & 0x1; }
708     unsigned sBit() { return (m_opcode >> 22) & 0x1; }
709     unsigned wBit() { return (m_opcode >> 11) & 0x1; }
710     int immediate10() { return (sBit() << 9) | ((m_opcode >> 12) & 0x1ff); }
711     
712 };
713
714 class A64DOpcodeLoadStoreRegisterPair : public A64DOpcodeLoadStore {
715 public:
716     static const uint32_t mask = 0x3a000000;
717     static const uint32_t pattern = 0x28000000;
718
719     DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterPair, thisObj);
720
721     const char* format();
722     const char* opName();
723
724     unsigned rt2() { return (m_opcode >> 10) & 0x1f; }
725     int immediate7() { return (static_cast<int>((m_opcode >> 15) & 0x7f) << 25) >> 25; }
726     unsigned offsetMode() { return (m_opcode >> 23) & 0x7; }
727     int lBit() { return (m_opcode >> 22) & 0x1; }
728 };
729
730 class A64DOpcodeLoadStoreUnsignedImmediate : public A64DOpcodeLoadStore {
731 public:
732     static const uint32_t mask = 0x3b000000;
733     static const uint32_t pattern = 0x39000000;
734
735     DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreUnsignedImmediate, thisObj);
736
737     const char* format();
738
739     unsigned immediate12() { return (m_opcode >> 10) & 0xfff; }
740 };
741
742 class A64DOpcodeLogical : public A64DOpcode {
743 private:
744     static const char* const s_opNames[8];
745
746 public:
747     const char* opName(unsigned opNumber)
748     {
749         return s_opNames[opNumber & 0x7];
750     }
751
752     unsigned opc() { return (m_opcode >> 29) & 0x3; }
753     unsigned nBit() { return (m_opcode >> 21) & 0x1; }
754 };
755
756 class A64DOpcodeLogicalImmediate : public A64DOpcodeLogical {
757 public:
758     static const uint32_t mask = 0x1f800000;
759     static const uint32_t pattern = 0x12000000;
760
761     DEFINE_STATIC_FORMAT(A64DOpcodeLogicalImmediate, thisObj);
762
763     const char* format();
764
765     bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
766     bool isMov() { return ((opNumber() == 2) && (rn() == 31)); }
767     unsigned opNumber() { return opc() << 1; }
768     unsigned nBit() { return (m_opcode >> 22) & 0x1; }
769     unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
770     unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
771 };
772
773 class A64DOpcodeLogicalShiftedRegister : public A64DOpcodeLogical {
774 public:
775     static const uint32_t mask = 0x1f000000;
776     static const uint32_t pattern = 0x0a000000;
777
778     DEFINE_STATIC_FORMAT(A64DOpcodeLogicalShiftedRegister, thisObj);
779
780     const char* format();
781
782     bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
783     bool isMov() { return ((opc() == 1) && (rn() == 31)); }
784     unsigned opNumber() { return (opc() << 1) | nBit(); }
785     unsigned shift() { return (m_opcode >> 22) & 0x3; }
786     int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
787 };
788
789 class A64DOpcodeMoveWide : public A64DOpcode {
790 private:
791     static const char* const s_opNames[4];
792
793 public:
794     static const uint32_t mask = 0x1f800000;
795     static const uint32_t pattern = 0x12800000;
796
797     DEFINE_STATIC_FORMAT(A64DOpcodeMoveWide, thisObj);
798
799     const char* format();
800
801     const char* opName() { return s_opNames[opc()]; }
802     unsigned opc() { return (m_opcode >> 29) & 0x3; }
803     unsigned hw() { return (m_opcode >> 21) & 0x3; }
804     unsigned immediate16() { return (m_opcode >> 5) & 0xffff; }
805 };
806
807 class A64DOpcodeTestAndBranchImmediate : public A64DOpcode {
808 public:
809     static const uint32_t mask = 0x7e000000;
810     static const uint32_t pattern = 0x36000000;
811
812     DEFINE_STATIC_FORMAT(A64DOpcodeTestAndBranchImmediate, thisObj);
813
814     const char* format();
815
816     unsigned bitNumber() { return ((m_opcode >> 26) & 0x20) | ((m_opcode >> 19) & 0x1f); }
817     unsigned opBit() { return (m_opcode >> 24) & 0x1; }
818     int immediate14() { return (static_cast<int>((m_opcode >> 5) & 0x3fff) << 18) >> 18; }
819 };
820
821 class A64DOpcodeUnconditionalBranchImmediate : public A64DOpcode {
822 public:
823     static const uint32_t mask = 0x7c000000;
824     static const uint32_t pattern = 0x14000000;
825
826     DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchImmediate, thisObj);
827
828     const char* format();
829
830     unsigned op() { return (m_opcode >> 31) & 0x1; }
831     int immediate26() { return (static_cast<int>(m_opcode & 0x3ffffff) << 6) >> 6; }
832 };
833
834 class A64DOpcodeUnconditionalBranchRegister : public A64DOpcode {
835 private:
836     static const char* const s_opNames[8];
837     static const char* const s_AuthOpNames[20];
838
839 public:
840     static const uint32_t mask = 0xfe1f0000;
841     static const uint32_t pattern = 0xd61f0000;
842
843     DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchRegister, thisObj);
844
845     const char* format();
846
847     const char* opName() { return s_opNames[opc()]; }
848     const char* authOpName();
849     unsigned opc() { return (m_opcode >> 21) & 0xf; }
850     unsigned authOpCode() {return (opc() << 1) | mBit(); }
851     unsigned op2() { return (m_opcode >> 16) & 0x1f; }
852     unsigned op3() { return (m_opcode >> 10) & 0x3f; }
853     unsigned op4() { return m_opcode & 0xf; }
854     unsigned mBit() { return (m_opcode >> 10) & 1; }
855     unsigned rm() { return rd(); }
856 };
857
858 } } // namespace JSC::ARM64Disassembler
859
860 using JSC::ARM64Disassembler::A64DOpcode;