aboutsummaryrefslogtreecommitdiffstats
path: root/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h')
-rw-r--r--src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h708
1 files changed, 708 insertions, 0 deletions
diff --git a/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h b/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h
new file mode 100644
index 0000000000..5bb7db9f12
--- /dev/null
+++ b/src/3rdparty/masm/disassembler/ARM64/A64DOpcode.h
@@ -0,0 +1,708 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef A64DOpcode_h
+#define A64DOpcode_h
+
+#include <wtf/Assertions.h>
+#include <stdint.h>
+
+namespace JSC { namespace ARM64Disassembler {
+
+class A64DOpcode {
+private:
+ class OpcodeGroup {
+ public:
+ OpcodeGroup(uint32_t opcodeMask, uint32_t opcodePattern, const char* (*format)(A64DOpcode*))
+ : m_opcodeMask(opcodeMask)
+ , m_opcodePattern(opcodePattern)
+ , m_format(format)
+ , m_next(0)
+ {
+ }
+
+ void setNext(OpcodeGroup* next)
+ {
+ m_next = next;
+ }
+
+ OpcodeGroup* next()
+ {
+ return m_next;
+ }
+
+ bool matches(uint32_t opcode)
+ {
+ return (opcode & m_opcodeMask) == m_opcodePattern;
+ }
+
+ const char* format(A64DOpcode* thisObj)
+ {
+ return m_format(thisObj);
+ }
+
+ private:
+ uint32_t m_opcodeMask;
+ uint32_t m_opcodePattern;
+ const char* (*m_format)(A64DOpcode*);
+ OpcodeGroup* m_next;
+ };
+
+public:
+ static void init();
+
+ A64DOpcode()
+ : m_opcode(0)
+ , m_bufferOffset(0)
+ {
+ init();
+ m_formatBuffer[0] = '\0';
+ }
+
+ const char* disassemble(uint32_t* currentPC);
+
+protected:
+ void setPCAndOpcode(uint32_t*, uint32_t);
+ const char* format();
+
+ static const char* const s_conditionNames[16];
+ static const char* const s_shiftNames[4];
+ static const char* const s_optionName[8];
+ static const char s_FPRegisterPrefix[5];
+
+ static const char* conditionName(unsigned condition) { return s_conditionNames[condition & 0xf]; }
+ static const char* shiftName(unsigned shiftValue) { return s_shiftNames[shiftValue & 0x3]; }
+ const char* optionName() { return s_optionName[option()]; }
+ static char FPRegisterPrefix(unsigned FPRegisterSize)
+ {
+ if (FPRegisterSize > 4)
+ FPRegisterSize = 4;
+ return s_FPRegisterPrefix[FPRegisterSize];
+ }
+
+ unsigned opcodeGroupNumber(uint32_t opcode) { return (opcode >> 24) & 0x1f; }
+
+ bool is64Bit() { return m_opcode & 0x80000000; }
+ unsigned size() { return m_opcode >> 30; }
+ unsigned option() { return (m_opcode >> 13) & 0x7; }
+ unsigned rd() { return m_opcode & 0x1f; }
+ unsigned rt() { return m_opcode & 0x1f; }
+ unsigned rn() { return (m_opcode >> 5) & 0x1f; }
+ unsigned rm() { return (m_opcode >> 16) & 0x1f; }
+
+ void bufferPrintf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+
+ void appendInstructionName(const char* instructionName)
+ {
+ bufferPrintf(" %-7.7s", instructionName);
+ }
+
+ void appendRegisterName(unsigned registerNumber, bool is64Bit = true);
+ void appendSPOrRegisterName(unsigned registerNumber, bool is64Bit = true)
+ {
+ if (registerNumber == 31) {
+ bufferPrintf(is64Bit ? "sp" : "wsp");
+ return;
+ }
+ appendRegisterName(registerNumber, is64Bit);
+ }
+
+ void appendZROrRegisterName(unsigned registerNumber, bool is64Bit = true)
+ {
+ if (registerNumber == 31) {
+ bufferPrintf(is64Bit ? "xzr" : "wzr");
+ return;
+ }
+ appendRegisterName(registerNumber, is64Bit);
+ }
+
+ void appendFPRegisterName(unsigned registerNumber, unsigned registerSize);
+
+ void appendSeparator()
+ {
+ bufferPrintf(", ");
+ }
+
+ void appendCharacter(const char c)
+ {
+ bufferPrintf("%c", c);
+ }
+
+ void appendString(const char* string)
+ {
+ bufferPrintf("%s", string);
+ }
+
+ void appendShiftType(unsigned shiftValue)
+ {
+ bufferPrintf("%s ", shiftName(shiftValue));
+ }
+
+ void appendSignedImmediate(int immediate)
+ {
+ bufferPrintf("#%d", immediate);
+ }
+
+ void appendUnsignedImmediate(unsigned immediate)
+ {
+ bufferPrintf("#%u", immediate);
+ }
+
+ void appendUnsignedImmediate64(uint64_t immediate)
+ {
+ bufferPrintf("#0x%" PRIx64, immediate);
+ }
+
+ void appendPCRelativeOffset(uint32_t* pc, int32_t immediate)
+ {
+ bufferPrintf("0x%" PRIx64, reinterpret_cast<uint64_t>(pc + immediate));
+ }
+
+ void appendShiftAmount(unsigned amount)
+ {
+ bufferPrintf("lsl #%u", 16 * amount);
+ }
+
+ static const int bufferSize = 81;
+
+ char m_formatBuffer[bufferSize];
+ uint32_t* m_currentPC;
+ uint32_t m_opcode;
+ int m_bufferOffset;
+
+private:
+ static OpcodeGroup* opcodeTable[32];
+
+ static bool s_initialized;
+};
+
+#define DEFINE_STATIC_FORMAT(klass, thisObj) \
+ static const char* format(A64DOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); }
+
+class A64DOpcodeAddSubtract : public A64DOpcode {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ const char* opName() { return s_opNames[opAndS()]; }
+ const char* cmpName() { return op() ? "cmp" : "cmn"; }
+
+ bool isCMP() { return (sBit() && rd() == 31); }
+ unsigned op() { return (m_opcode >> 30) & 0x1; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned opAndS() { return (m_opcode >> 29) & 0x3; }
+};
+
+class A64DOpcodeAddSubtractImmediate : public A64DOpcodeAddSubtract {
+public:
+ static const uint32_t mask = 0x1f000000;
+ static const uint32_t pattern = 0x11000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractImmediate, thisObj);
+
+ const char* format();
+
+ bool isMovSP() { return (!opAndS() && !immed12() && ((rd() == 31) || rn() == 31)); }
+ unsigned shift() { return (m_opcode >> 22) & 0x3; }
+ unsigned immed12() { return (m_opcode >> 10) & 0xfff; }
+};
+
+class A64DOpcodeAddSubtractExtendedRegister : public A64DOpcodeAddSubtract {
+public:
+ static const uint32_t mask = 0x1fe00000;
+ static const uint32_t pattern = 0x0b200000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractExtendedRegister, thisObj);
+
+ const char* format();
+
+ unsigned immediate3() { return (m_opcode >> 10) & 0x7; }
+};
+
+class A64DOpcodeAddSubtractShiftedRegister : public A64DOpcodeAddSubtract {
+public:
+ static const uint32_t mask = 0x1f200000;
+ static const uint32_t pattern = 0x0b000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractShiftedRegister, thisObj);
+
+ const char* format();
+
+ bool isNeg() { return (op() && rn() == 31); }
+ const char* negName() { return sBit() ? "negs" : "neg"; }
+ unsigned shift() { return (m_opcode >> 22) & 0x3; }
+ int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
+};
+
+class A64DOpcodeBitfield : public A64DOpcode {
+private:
+ static const char* const s_opNames[3];
+ static const char* const s_extendPseudoOpNames[3][3];
+ static const char* const s_insertOpNames[3];
+ static const char* const s_extractOpNames[3];
+
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x13000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeBitfield, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opc()]; }
+ const char* extendPseudoOpNames(unsigned opSize) { return s_extendPseudoOpNames[opc()][opSize]; }
+ const char* insertOpNames() { return s_insertOpNames[opc()]; }
+ const char* extractOpNames() { return s_extractOpNames[opc()]; }
+
+ unsigned opc() { return (m_opcode >> 29) & 0x3; }
+ unsigned nBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
+ unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
+};
+
+class A64DOpcodeCompareAndBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x7e000000;
+ static const uint32_t pattern = 0x34000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeCompareAndBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned opBit() { return (m_opcode >> 24) & 0x1; }
+ int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
+};
+
+class A64DOpcodeConditionalBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0xff000010;
+ static const uint32_t pattern = 0x54000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeConditionalBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned condition() { return m_opcode & 0xf; }
+ int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
+};
+
+class A64DOpcodeConditionalSelect : public A64DOpcode {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ static const uint32_t mask = 0x1fe00010;
+ static const uint32_t pattern = 0x1a800000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeConditionalSelect, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+ unsigned opNum() { return (op() << 1 | (op2() & 0x1)); }
+ unsigned op() { return (m_opcode >> 30) & 0x1; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned condition() { return (m_opcode >> 12) & 0xf; }
+ unsigned op2() { return (m_opcode >> 10) & 0x3; }
+};
+
+class A64DOpcodeDataProcessing2Source : public A64DOpcode {
+private:
+ static const char* const s_opNames[8];
+
+public:
+ static const uint32_t mask = 0x5fe00000;
+ static const uint32_t pattern = 0x1ac00000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing2Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNameIndex()]; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned opCode() { return (m_opcode >> 10) & 0x3f; }
+ unsigned opNameIndex() { return ((m_opcode >> 11) & 0x4) | ((m_opcode >> 10) & 0x3); }
+};
+
+class A64DOpcodeDataProcessing3Source : public A64DOpcode {
+private:
+ static const char* const s_opNames[16];
+ static const char* const s_pseudoOpNames[16];
+
+public:
+ static const uint32_t mask = 0x1f000000;
+ static const uint32_t pattern = 0x1b000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing3Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return ra() == 31 ? s_opNames[opNum() & 0xf] : s_pseudoOpNames[opNum() & 0xf]; }
+ unsigned ra() { return (m_opcode >> 10) & 0x1f; }
+ unsigned op54() { return (m_opcode >> 29) & 0x3; }
+ unsigned op31() { return (m_opcode >> 21) & 0x7; }
+ unsigned op0() { return (m_opcode >> 15) & 0x1; }
+ unsigned opNum() { return ((m_opcode >> 25) & 0x30) | ((m_opcode >> 20) & 0xe) | ((m_opcode >> 15) & 0x1); }
+};
+
+class A64OpcodeExceptionGeneration : public A64DOpcode {
+public:
+ static const uint32_t mask = 0xff000010;
+ static const uint32_t pattern = 0xd4000000;
+
+ DEFINE_STATIC_FORMAT(A64OpcodeExceptionGeneration, thisObj);
+
+ const char* format();
+
+ unsigned opc() { return (m_opcode>>21) & 0x7; }
+ unsigned op2() { return (m_opcode>>2) & 0x7; }
+ unsigned ll() { return m_opcode & 0x3; }
+ int immediate16() { return (static_cast<int>((m_opcode >> 5) & 0xffff) << 16) >> 16; }
+};
+
+class A64DOpcodeExtract : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x13800000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeExtract, thisObj);
+
+ const char* format();
+
+ unsigned op21() { return (m_opcode >> 29) & 0x3; }
+ unsigned nBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned o0Bit() { return (m_opcode >> 21) & 0x1; }
+ unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
+};
+
+class A64DOpcodeFloatingPointOps : public A64DOpcode {
+public:
+ unsigned mBit() { return (m_opcode >> 31) & 0x1; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned type() { return (m_opcode >> 22) & 0x3; }
+};
+
+class A64DOpcodeFloatingPointCompare : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[16];
+
+public:
+ static const uint32_t mask = 0x5f203c00;
+ static const uint32_t pattern = 0x1e202000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointCompare, thisObj);
+
+ const char* format();
+
+ const char* opName() { return (opNum() & 0x2) ? "fcmpe" : "fcmp"; }
+
+ unsigned op() { return (m_opcode >> 14) & 0x3; }
+ unsigned opCode2() { return m_opcode & 0x1f; }
+ unsigned opNum() { return (m_opcode >> 3) & 0x3; }
+};
+
+class A64DOpcodeFloatingPointDataProcessing1Source : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[16];
+
+public:
+ static const uint32_t mask = 0x5f207c00;
+ static const uint32_t pattern = 0x1e204000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing1Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+
+ unsigned opNum() { return (m_opcode >> 15) & 0x3f; }
+};
+
+class A64DOpcodeFloatingPointDataProcessing2Source : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[16];
+
+public:
+ static const uint32_t mask = 0x5f200800;
+ static const uint32_t pattern = 0x1e200800;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing2Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+
+ unsigned opNum() { return (m_opcode >> 12) & 0xf; }
+};
+
+class A64DOpcodeFloatingFixedPointConversions : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ static const uint32_t mask = 0x5f200000;
+ static const uint32_t pattern = 0x1e000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingFixedPointConversions, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+ unsigned rmode() { return (m_opcode >> 19) & 0x3; }
+ unsigned opcode() { return (m_opcode >> 16) & 0x7; }
+ unsigned scale() { return (m_opcode >> 10) & 0x3f; }
+ unsigned opNum() { return (m_opcode >> 16) & 0x3; }
+};
+
+class A64DOpcodeFloatingPointIntegerConversions : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[32];
+
+public:
+ static const uint32_t mask = 0x5f20fc00;
+ static const uint32_t pattern = 0x1e200000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointIntegerConversions, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+ unsigned rmode() { return (m_opcode >> 19) & 0x3; }
+ unsigned opcode() { return (m_opcode >> 16) & 0x7; }
+ unsigned opNum() { return (m_opcode >> 16) & 0x1f; }
+};
+
+class A64DOpcodeHint : public A64DOpcode {
+private:
+ static const char* const s_opNames[6];
+
+public:
+ static const uint32_t mask = 0xfffff01f;
+ static const uint32_t pattern = 0xd503201f;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeHint, thisObj);
+
+ const char* format();
+
+ const char* opName() { return immediate7() <= 5 ? s_opNames[immediate7()] : "hint"; }
+ unsigned immediate7() { return (m_opcode >> 5) & 0x7f; }
+};
+
+class A64DOpcodeLoadStore : public A64DOpcode {
+private:
+ static const char* const s_opNames[32];
+
+protected:
+ const char* opName()
+ {
+ return s_opNames[opNumber()];
+ }
+
+ unsigned size() { return (m_opcode >> 30) & 0x3; }
+ unsigned vBit() { return (m_opcode >> 26) & 0x1; }
+ unsigned opc() { return (m_opcode >> 22) & 0x3; }
+ unsigned opNumber() { return (size() <<3 ) | (vBit() << 2) | opc(); }
+ bool is64BitRT() { return ((opNumber() & 0x17) == 0x02) || ((opNumber() & 0x1e) == 0x18); }
+};
+
+class A64DOpcodeLoadStoreImmediate : public A64DOpcodeLoadStore {
+private:
+ static const char* const s_unprivilegedOpNames[32];
+ static const char* const s_unscaledOpNames[32];
+
+public:
+ static const uint32_t mask = 0x3b200000;
+ static const uint32_t pattern = 0x38000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreImmediate, thisObj);
+
+ const char* format();
+
+ const char* unprivilegedOpName()
+ {
+ return s_unprivilegedOpNames[opNumber()];
+ }
+ const char* unscaledOpName()
+ {
+ return s_unscaledOpNames[opNumber()];
+ }
+ unsigned type() { return (m_opcode >> 10) & 0x3; }
+ int immediate9() { return (static_cast<int>((m_opcode >> 12) & 0x1ff) << 23) >> 23; }
+};
+
+class A64DOpcodeLoadStoreRegisterOffset : public A64DOpcodeLoadStore {
+public:
+ static const uint32_t mask = 0x3b200c00;
+ static const uint32_t pattern = 0x38200800;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterOffset, thisObj);
+
+ const char* format();
+
+ unsigned option() { return (m_opcode >> 13) & 0x7; }
+ int sBit() { return (m_opcode >> 12) & 0x1; }
+};
+
+class A64DOpcodeLoadStoreRegisterPair : public A64DOpcodeLoadStore {
+public:
+ static const uint32_t mask = 0x3a000000;
+ static const uint32_t pattern = 0x28000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterPair, thisObj);
+
+ const char* format();
+ const char* opName();
+
+ unsigned rt2() { return (m_opcode >> 10) & 0x1f; }
+ int immediate7() { return (static_cast<int>((m_opcode >> 15) & 0x7f) << 25) >> 25; }
+ unsigned offsetMode() { return (m_opcode >> 23) & 0x7; }
+ int lBit() { return (m_opcode >> 22) & 0x1; }
+};
+
+class A64DOpcodeLoadStoreUnsignedImmediate : public A64DOpcodeLoadStore {
+public:
+ static const uint32_t mask = 0x3b000000;
+ static const uint32_t pattern = 0x39000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreUnsignedImmediate, thisObj);
+
+ const char* format();
+
+ unsigned immediate12() { return (m_opcode >> 10) & 0xfff; }
+};
+
+class A64DOpcodeLogical : public A64DOpcode {
+private:
+ static const char* const s_opNames[8];
+
+public:
+ const char* opName(unsigned opNumber)
+ {
+ return s_opNames[opNumber & 0x7];
+ }
+
+ unsigned opc() { return (m_opcode >> 29) & 0x3; }
+ unsigned nBit() { return (m_opcode >> 21) & 0x1; }
+};
+
+class A64DOpcodeLogicalImmediate : public A64DOpcodeLogical {
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x12000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLogicalImmediate, thisObj);
+
+ const char* format();
+
+ bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
+ bool isMov() { return ((opNumber() == 2) && (rn() == 31)); }
+ unsigned opNumber() { return opc() << 1; }
+ unsigned nBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
+ unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
+};
+
+class A64DOpcodeLogicalShiftedRegister : public A64DOpcodeLogical {
+public:
+ static const uint32_t mask = 0x1f000000;
+ static const uint32_t pattern = 0x0a000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLogicalShiftedRegister, thisObj);
+
+ const char* format();
+
+ bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
+ bool isMov() { return ((opNumber() == 2) && (rn() == 31)); }
+ unsigned opNumber() { return (opc() << 1) | nBit(); }
+ unsigned shift() { return (m_opcode >> 22) & 0x3; }
+ int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
+};
+
+class A64DOpcodeMoveWide : public A64DOpcode {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x12800000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeMoveWide, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opc()]; }
+ unsigned opc() { return (m_opcode >> 29) & 0x3; }
+ unsigned hw() { return (m_opcode >> 21) & 0x3; }
+ unsigned immediate16() { return (m_opcode >> 5) & 0xffff; }
+};
+
+class A64DOpcodeTestAndBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x7e000000;
+ static const uint32_t pattern = 0x36000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeTestAndBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned bitNumber() { return ((m_opcode >> 26) & 0x20) | ((m_opcode >> 19) & 0x1f); }
+ unsigned opBit() { return (m_opcode >> 24) & 0x1; }
+ int immediate14() { return (static_cast<int>((m_opcode >> 5) & 0x3fff) << 18) >> 18; }
+};
+
+class A64DOpcodeUnconditionalBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x7c000000;
+ static const uint32_t pattern = 0x14000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned op() { return (m_opcode >> 31) & 0x1; }
+ int immediate26() { return (static_cast<int>(m_opcode & 0x3ffffff) << 6) >> 6; }
+};
+
+class A64DOpcodeUnconditionalBranchRegister : public A64DOpcode {
+private:
+ static const char* const s_opNames[8];
+
+public:
+ static const uint32_t mask = 0xfe1ffc1f;
+ static const uint32_t pattern = 0xd61f0000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchRegister, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opc()]; }
+ unsigned opc() { return (m_opcode >> 21) & 0xf; }
+};
+
+} } // namespace JSC::ARM64Disassembler
+
+using JSC::ARM64Disassembler::A64DOpcode;
+
+#endif // A64DOpcode_h