1/*
2 * Copyright (C) 2012 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef A64DOpcode_h
27#define A64DOpcode_h
28
29#include <wtf/Assertions.h>
30#include <stdint.h>
31
32namespace JSC { namespace ARM64Disassembler {
33
34class A64DOpcode {
35private:
36    class OpcodeGroup {
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
73public:
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
86protected:
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("   %-7.7s", 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 appendUnsignedImmediate(unsigned immediate)
169    {
170        bufferPrintf("#%u", immediate);
171    }
172
173    void appendUnsignedImmediate64(uint64_t immediate)
174    {
175        bufferPrintf("#0x%llx", immediate);
176    }
177
178    void appendPCRelativeOffset(uint32_t* pc, int32_t immediate)
179    {
180        bufferPrintf("0x%llx", reinterpret_cast<uint64_t>(pc + immediate));
181    }
182
183    void appendShiftAmount(unsigned amount)
184    {
185        bufferPrintf("lsl #%u", 16 * amount);
186    }
187
188    static const int bufferSize = 81;
189
190    char m_formatBuffer[bufferSize];
191    uint32_t* m_currentPC;
192    uint32_t m_opcode;
193    int m_bufferOffset;
194
195private:
196    static OpcodeGroup* opcodeTable[32];
197
198    static bool s_initialized;
199};
200
201#define DEFINE_STATIC_FORMAT(klass, thisObj) \
202   static const char* format(A64DOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); }
203
204class A64DOpcodeAddSubtract : public A64DOpcode {
205private:
206    static const char* const s_opNames[4];
207
208public:
209    const char* opName() { return s_opNames[opAndS()]; }
210    const char* cmpName() { return op() ? "cmp" : "cmn"; }
211
212    bool isCMP() { return (sBit() && rd() == 31); }
213    unsigned op() { return (m_opcode >> 30) & 0x1; }
214    unsigned sBit() { return (m_opcode >> 29) & 0x1; }
215    unsigned opAndS() { return (m_opcode >> 29) & 0x3; }
216};
217
218class A64DOpcodeAddSubtractImmediate : public A64DOpcodeAddSubtract {
219public:
220    static const uint32_t mask = 0x1f000000;
221    static const uint32_t pattern = 0x11000000;
222
223    DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractImmediate, thisObj);
224
225    const char* format();
226
227    bool isMovSP() { return (!opAndS() && !immed12() && ((rd() == 31) || rn() == 31)); }
228    unsigned shift() { return (m_opcode >> 22) & 0x3; }
229    unsigned immed12() { return (m_opcode >> 10) & 0xfff; }
230};
231
232class A64DOpcodeAddSubtractExtendedRegister : public A64DOpcodeAddSubtract {
233public:
234    static const uint32_t mask = 0x1fe00000;
235    static const uint32_t pattern = 0x0b200000;
236
237    DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractExtendedRegister, thisObj);
238
239    const char* format();
240
241    unsigned immediate3() { return (m_opcode >> 10) & 0x7; }
242};
243
244class A64DOpcodeAddSubtractShiftedRegister : public A64DOpcodeAddSubtract {
245public:
246    static const uint32_t mask = 0x1f200000;
247    static const uint32_t pattern = 0x0b000000;
248
249    DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractShiftedRegister, thisObj);
250
251    const char* format();
252
253    bool isNeg() { return (op() && rn() == 31); }
254    const char* negName() { return sBit() ? "negs" : "neg"; }
255    unsigned shift() { return (m_opcode >> 22) & 0x3; }
256    int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
257};
258
259class A64DOpcodeBitfield : public A64DOpcode {
260private:
261    static const char* const s_opNames[3];
262    static const char* const s_extendPseudoOpNames[3][3];
263    static const char* const s_insertOpNames[3];
264    static const char* const s_extractOpNames[3];
265
266public:
267    static const uint32_t mask = 0x1f800000;
268    static const uint32_t pattern = 0x13000000;
269
270    DEFINE_STATIC_FORMAT(A64DOpcodeBitfield, thisObj);
271
272    const char* format();
273
274    const char* opName() { return s_opNames[opc()]; }
275    const char* extendPseudoOpNames(unsigned opSize) { return s_extendPseudoOpNames[opc()][opSize]; }
276    const char* insertOpNames() { return s_insertOpNames[opc()]; }
277    const char* extractOpNames() { return s_extractOpNames[opc()]; }
278
279    unsigned opc() { return (m_opcode >> 29) & 0x3; }
280    unsigned nBit() { return (m_opcode >> 22) & 0x1; }
281    unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
282    unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
283};
284
285class A64DOpcodeCompareAndBranchImmediate : public A64DOpcode {
286public:
287    static const uint32_t mask = 0x7e000000;
288    static const uint32_t pattern = 0x34000000;
289
290    DEFINE_STATIC_FORMAT(A64DOpcodeCompareAndBranchImmediate, thisObj);
291
292    const char* format();
293
294    unsigned opBit() { return (m_opcode >> 24) & 0x1; }
295    int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
296};
297
298class A64DOpcodeConditionalBranchImmediate : public A64DOpcode {
299public:
300    static const uint32_t mask = 0xff000010;
301    static const uint32_t pattern = 0x54000000;
302
303    DEFINE_STATIC_FORMAT(A64DOpcodeConditionalBranchImmediate, thisObj);
304
305    const char* format();
306
307    unsigned condition() { return m_opcode & 0xf; }
308    int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
309};
310
311class A64DOpcodeConditionalSelect : public A64DOpcode {
312private:
313    static const char* const s_opNames[4];
314
315public:
316    static const uint32_t mask = 0x1fe00010;
317    static const uint32_t pattern = 0x1a800000;
318
319    DEFINE_STATIC_FORMAT(A64DOpcodeConditionalSelect, thisObj);
320
321    const char* format();
322
323    const char* opName() { return s_opNames[opNum()]; }
324    unsigned opNum() { return (op() << 1 | (op2() & 0x1)); }
325    unsigned op() { return (m_opcode >> 30) & 0x1; }
326    unsigned sBit() { return (m_opcode >> 29) & 0x1; }
327    unsigned condition() { return (m_opcode >> 12) & 0xf; }
328    unsigned op2() { return (m_opcode >> 10) & 0x3; }
329};
330
331class A64DOpcodeDataProcessing2Source : public A64DOpcode {
332private:
333    static const char* const s_opNames[8];
334
335public:
336    static const uint32_t mask = 0x5fe00000;
337    static const uint32_t pattern = 0x1ac00000;
338
339    DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing2Source, thisObj);
340
341    const char* format();
342
343    const char* opName() { return s_opNames[opNameIndex()]; }
344    unsigned sBit() { return (m_opcode >> 29) & 0x1; }
345    unsigned opCode() { return (m_opcode >> 10) & 0x3f; }
346    unsigned opNameIndex() { return ((m_opcode >> 11) & 0x4) | ((m_opcode >> 10) & 0x3); }
347};
348
349class A64DOpcodeDataProcessing3Source : public A64DOpcode {
350private:
351    static const char* const s_opNames[16];
352    static const char* const s_pseudoOpNames[16];
353
354public:
355    static const uint32_t mask = 0x1f000000;
356    static const uint32_t pattern = 0x1b000000;
357
358    DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing3Source, thisObj);
359
360    const char* format();
361
362    const char* opName() { return ra() == 31 ? s_opNames[opNum() & 0xf] : s_pseudoOpNames[opNum() & 0xf]; }
363    unsigned ra() { return (m_opcode >> 10) & 0x1f; }
364    unsigned op54() { return (m_opcode >> 29) & 0x3; }
365    unsigned op31() { return (m_opcode >> 21) & 0x7; }
366    unsigned op0() { return (m_opcode >> 15) & 0x1; }
367    unsigned opNum() { return ((m_opcode >> 25) & 0x30) | ((m_opcode >> 20) & 0xe) | ((m_opcode >> 15) & 0x1); }
368};
369
370class A64OpcodeExceptionGeneration : public A64DOpcode {
371public:
372    static const uint32_t mask = 0xff000010;
373    static const uint32_t pattern = 0xd4000000;
374
375    DEFINE_STATIC_FORMAT(A64OpcodeExceptionGeneration, thisObj);
376
377    const char* format();
378
379    unsigned opc() { return (m_opcode>>21) & 0x7; }
380    unsigned op2() { return (m_opcode>>2) & 0x7; }
381    unsigned ll() { return m_opcode & 0x3; }
382    int immediate16() { return (static_cast<int>((m_opcode >> 5) & 0xffff) << 16) >> 16; }
383};
384
385class A64DOpcodeExtract : public A64DOpcode {
386public:
387    static const uint32_t mask = 0x1f800000;
388    static const uint32_t pattern = 0x13800000;
389
390    DEFINE_STATIC_FORMAT(A64DOpcodeExtract, thisObj);
391
392    const char* format();
393
394    unsigned op21() { return (m_opcode >> 29) & 0x3; }
395    unsigned nBit() { return (m_opcode >> 22) & 0x1; }
396    unsigned o0Bit() { return (m_opcode >> 21) & 0x1; }
397    unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
398};
399
400class A64DOpcodeFloatingPointOps : public A64DOpcode {
401public:
402    unsigned mBit() { return (m_opcode >> 31) & 0x1; }
403    unsigned sBit() { return (m_opcode >> 29) & 0x1; }
404    unsigned type() { return (m_opcode >> 22) & 0x3; }
405};
406
407class A64DOpcodeFloatingPointCompare : public A64DOpcodeFloatingPointOps {
408private:
409    static const char* const s_opNames[16];
410
411public:
412    static const uint32_t mask = 0x5f203c00;
413    static const uint32_t pattern = 0x1e202000;
414
415    DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointCompare, thisObj);
416
417    const char* format();
418
419    const char* opName() { return (opNum() & 0x2) ? "fcmpe" : "fcmp"; }
420
421    unsigned op() { return (m_opcode >> 14) & 0x3; }
422    unsigned opCode2() { return m_opcode & 0x1f; }
423    unsigned opNum() { return (m_opcode >> 3) & 0x3; }
424};
425
426class A64DOpcodeFloatingPointDataProcessing1Source : public A64DOpcodeFloatingPointOps {
427private:
428    static const char* const s_opNames[16];
429
430public:
431    static const uint32_t mask = 0x5f207c00;
432    static const uint32_t pattern = 0x1e204000;
433
434    DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing1Source, thisObj);
435
436    const char* format();
437
438    const char* opName() { return s_opNames[opNum()]; }
439
440    unsigned opNum() { return (m_opcode >> 15) & 0x3f; }
441};
442
443class A64DOpcodeFloatingPointDataProcessing2Source : public A64DOpcodeFloatingPointOps {
444private:
445    static const char* const s_opNames[16];
446
447public:
448    static const uint32_t mask = 0x5f200800;
449    static const uint32_t pattern = 0x1e200800;
450
451    DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing2Source, thisObj);
452
453    const char* format();
454
455    const char* opName() { return s_opNames[opNum()]; }
456
457    unsigned opNum() { return (m_opcode >> 12) & 0xf; }
458};
459
460class A64DOpcodeFloatingFixedPointConversions : public A64DOpcodeFloatingPointOps {
461private:
462    static const char* const s_opNames[4];
463
464public:
465    static const uint32_t mask = 0x5f200000;
466    static const uint32_t pattern = 0x1e000000;
467
468    DEFINE_STATIC_FORMAT(A64DOpcodeFloatingFixedPointConversions, thisObj);
469
470    const char* format();
471
472    const char* opName() { return s_opNames[opNum()]; }
473    unsigned rmode() { return (m_opcode >> 19) & 0x3; }
474    unsigned opcode() { return (m_opcode >> 16) & 0x7; }
475    unsigned scale() { return (m_opcode >> 10) & 0x3f; }
476    unsigned opNum() { return (m_opcode >> 16) & 0x3; }
477};
478
479class A64DOpcodeFloatingPointIntegerConversions : public A64DOpcodeFloatingPointOps {
480private:
481    static const char* const s_opNames[32];
482
483public:
484    static const uint32_t mask = 0x5f20fc00;
485    static const uint32_t pattern = 0x1e200000;
486
487    DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointIntegerConversions, thisObj);
488
489    const char* format();
490
491    const char* opName() { return s_opNames[opNum()]; }
492    unsigned rmode() { return (m_opcode >> 19) & 0x3; }
493    unsigned opcode() { return (m_opcode >> 16) & 0x7; }
494    unsigned opNum() { return (m_opcode >> 16) & 0x1f; }
495};
496
497class A64DOpcodeHint : public A64DOpcode {
498private:
499    static const char* const s_opNames[6];
500
501public:
502    static const uint32_t mask = 0xfffff01f;
503    static const uint32_t pattern = 0xd503201f;
504
505    DEFINE_STATIC_FORMAT(A64DOpcodeHint, thisObj);
506
507    const char* format();
508
509    const char* opName() { return immediate7() <= 5 ? s_opNames[immediate7()] : "hint"; }
510    unsigned immediate7() { return (m_opcode >> 5) & 0x7f; }
511};
512
513class A64DOpcodeLoadStore : public A64DOpcode {
514private:
515    static const char* const s_opNames[32];
516
517protected:
518    const char* opName()
519    {
520        return s_opNames[opNumber()];
521    }
522
523    unsigned size() { return (m_opcode >> 30) & 0x3; }
524    unsigned vBit() { return (m_opcode >> 26) & 0x1; }
525    unsigned opc() { return (m_opcode >> 22) & 0x3; }
526    unsigned opNumber() { return (size() <<3 ) | (vBit() << 2) | opc(); }
527    bool is64BitRT() { return ((opNumber() & 0x17) == 0x02) || ((opNumber() & 0x1e) == 0x18); }
528};
529
530class A64DOpcodeLoadStoreImmediate : public A64DOpcodeLoadStore {
531private:
532    static const char* const s_unprivilegedOpNames[32];
533    static const char* const s_unscaledOpNames[32];
534
535public:
536    static const uint32_t mask = 0x3b200000;
537    static const uint32_t pattern = 0x38000000;
538
539    DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreImmediate, thisObj);
540
541    const char* format();
542
543    const char* unprivilegedOpName()
544    {
545        return s_unprivilegedOpNames[opNumber()];
546    }
547    const char* unscaledOpName()
548    {
549        return s_unscaledOpNames[opNumber()];
550    }
551    unsigned type() { return (m_opcode >> 10) & 0x3; }
552    int immediate9() { return (static_cast<int>((m_opcode >> 12) & 0x1ff) << 23) >> 23; }
553};
554
555class A64DOpcodeLoadStoreRegisterOffset : public A64DOpcodeLoadStore {
556public:
557    static const uint32_t mask = 0x3b200c00;
558    static const uint32_t pattern = 0x38200800;
559
560    DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterOffset, thisObj);
561
562    const char* format();
563
564    unsigned option() { return (m_opcode >> 13) & 0x7; }
565    int sBit() { return (m_opcode >> 12) & 0x1; }
566};
567
568class A64DOpcodeLoadStoreRegisterPair : public A64DOpcodeLoadStore {
569public:
570    static const uint32_t mask = 0x3a000000;
571    static const uint32_t pattern = 0x28000000;
572
573    DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterPair, thisObj);
574
575    const char* format();
576    const char* opName();
577
578    unsigned rt2() { return (m_opcode >> 10) & 0x1f; }
579    int immediate7() { return (static_cast<int>((m_opcode >> 15) & 0x7f) << 25) >> 25; }
580    unsigned offsetMode() { return (m_opcode >> 23) & 0x7; }
581    int lBit() { return (m_opcode >> 22) & 0x1; }
582};
583
584class A64DOpcodeLoadStoreUnsignedImmediate : public A64DOpcodeLoadStore {
585public:
586    static const uint32_t mask = 0x3b000000;
587    static const uint32_t pattern = 0x39000000;
588
589    DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreUnsignedImmediate, thisObj);
590
591    const char* format();
592
593    unsigned immediate12() { return (m_opcode >> 10) & 0xfff; }
594};
595
596class A64DOpcodeLogical : public A64DOpcode {
597private:
598    static const char* const s_opNames[8];
599
600public:
601    const char* opName(unsigned opNumber)
602    {
603        return s_opNames[opNumber & 0x7];
604    }
605
606    unsigned opc() { return (m_opcode >> 29) & 0x3; }
607    unsigned nBit() { return (m_opcode >> 21) & 0x1; }
608};
609
610class A64DOpcodeLogicalImmediate : public A64DOpcodeLogical {
611public:
612    static const uint32_t mask = 0x1f800000;
613    static const uint32_t pattern = 0x12000000;
614
615    DEFINE_STATIC_FORMAT(A64DOpcodeLogicalImmediate, thisObj);
616
617    const char* format();
618
619    bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
620    bool isMov() { return ((opNumber() == 2) && (rn() == 31)); }
621    unsigned opNumber() { return opc() << 1; }
622    unsigned nBit() { return (m_opcode >> 22) & 0x1; }
623    unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
624    unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
625};
626
627class A64DOpcodeLogicalShiftedRegister : public A64DOpcodeLogical {
628public:
629    static const uint32_t mask = 0x1f000000;
630    static const uint32_t pattern = 0x0a000000;
631
632    DEFINE_STATIC_FORMAT(A64DOpcodeLogicalShiftedRegister, thisObj);
633
634    const char* format();
635
636    bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
637    bool isMov() { return ((opNumber() == 2) && (rn() == 31)); }
638    unsigned opNumber() { return (opc() << 1) | nBit(); }
639    unsigned shift() { return (m_opcode >> 22) & 0x3; }
640    int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
641};
642
643class A64DOpcodeMoveWide : public A64DOpcode {
644private:
645    static const char* const s_opNames[4];
646
647public:
648    static const uint32_t mask = 0x1f800000;
649    static const uint32_t pattern = 0x12800000;
650
651    DEFINE_STATIC_FORMAT(A64DOpcodeMoveWide, thisObj);
652
653    const char* format();
654
655    const char* opName() { return s_opNames[opc()]; }
656    unsigned opc() { return (m_opcode >> 29) & 0x3; }
657    unsigned hw() { return (m_opcode >> 21) & 0x3; }
658    unsigned immediate16() { return (m_opcode >> 5) & 0xffff; }
659};
660
661class A64DOpcodeTestAndBranchImmediate : public A64DOpcode {
662public:
663    static const uint32_t mask = 0x7e000000;
664    static const uint32_t pattern = 0x36000000;
665
666    DEFINE_STATIC_FORMAT(A64DOpcodeTestAndBranchImmediate, thisObj);
667
668    const char* format();
669
670    unsigned bitNumber() { return ((m_opcode >> 26) & 0x20) | ((m_opcode >> 19) & 0x1f); }
671    unsigned opBit() { return (m_opcode >> 24) & 0x1; }
672    int immediate14() { return (static_cast<int>((m_opcode >> 5) & 0x3fff) << 18) >> 18; }
673};
674
675class A64DOpcodeUnconditionalBranchImmediate : public A64DOpcode {
676public:
677    static const uint32_t mask = 0x7c000000;
678    static const uint32_t pattern = 0x14000000;
679
680    DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchImmediate, thisObj);
681
682    const char* format();
683
684    unsigned op() { return (m_opcode >> 31) & 0x1; }
685    int immediate26() { return (static_cast<int>(m_opcode & 0x3ffffff) << 6) >> 6; }
686};
687
688class A64DOpcodeUnconditionalBranchRegister : public A64DOpcode {
689private:
690    static const char* const s_opNames[8];
691
692public:
693    static const uint32_t mask = 0xfe1ffc1f;
694    static const uint32_t pattern = 0xd61f0000;
695
696    DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchRegister, thisObj);
697
698    const char* format();
699
700    const char* opName() { return s_opNames[opc()]; }
701    unsigned opc() { return (m_opcode >> 21) & 0xf; }
702};
703
704} } // namespace JSC::ARM64Disassembler
705
706using JSC::ARM64Disassembler::A64DOpcode;
707
708#endif // A64DOpcode_h
709