summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp')
-rw-r--r--Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp330
1 files changed, 260 insertions, 70 deletions
diff --git a/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp
index 0ea817a46..9584f4953 100644
--- a/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp
+++ b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,6 +24,9 @@
*/
#include "config.h"
+
+#if USE(ARM64_DISASSEMBLER)
+
#include "A64DOpcode.h"
#include <stdarg.h>
@@ -62,6 +65,8 @@ struct OpcodeGroupInitializer {
{ groupIndex, groupClass::mask, groupClass::pattern, groupClass::format }
static OpcodeGroupInitializer opcodeGroupList[] = {
+ OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair),
+ OPCODE_GROUP_ENTRY(0x09, A64DOpcodeLoadStoreRegisterPair),
OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister),
OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister),
OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister),
@@ -78,6 +83,7 @@ static OpcodeGroupInitializer opcodeGroupList[] = {
OPCODE_GROUP_ENTRY(0x15, A64DOpcodeConditionalBranchImmediate),
OPCODE_GROUP_ENTRY(0x15, A64DOpcodeCompareAndBranchImmediate),
OPCODE_GROUP_ENTRY(0x15, A64DOpcodeHint),
+ OPCODE_GROUP_ENTRY(0x15, A64DOpcodeDmb),
OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchImmediate),
OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister),
OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate),
@@ -88,12 +94,14 @@ static OpcodeGroupInitializer opcodeGroupList[] = {
OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset),
OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate),
OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect),
+ OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing1Source),
OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source),
OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source),
OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate),
OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset),
OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate),
OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointConditionalSelect),
OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source),
OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source),
OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions),
@@ -172,6 +180,11 @@ const char* A64DOpcode::format()
void A64DOpcode::appendRegisterName(unsigned registerNumber, bool is64Bit)
{
+ if (registerNumber == 29) {
+ bufferPrintf(is64Bit ? "fp" : "wfp");
+ return;
+ }
+
if (registerNumber == 30) {
bufferPrintf(is64Bit ? "lr" : "wlr");
return;
@@ -276,7 +289,7 @@ const char* const A64DOpcodeBitfield::s_opNames[3] = { "sbfm", "bfm", "ubfm" };
const char* const A64DOpcodeBitfield::s_extendPseudoOpNames[3][3] = {
{ "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } };
const char* const A64DOpcodeBitfield::s_insertOpNames[3] = { "sbfiz", "bfi", "ubfiz" };
-const char* const A64DOpcodeBitfield::s_extractOpNames[3] = { "sbfx", "bf", "ubfx" };
+const char* const A64DOpcodeBitfield::s_extractOpNames[3] = { "sbfx", "bfxil", "ubfx" };
const char* A64DOpcodeBitfield::format()
{
@@ -298,7 +311,7 @@ const char* A64DOpcodeBitfield::format()
} else if (immediateS() == 15) {
appendInstructionName(extendPseudoOpNames(1));
isSTXType = true;
- } else if (immediateS() == 31 && is64Bit()) {
+ } else if (immediateS() == 31 && is64Bit() && !opc()) {
appendInstructionName(extendPseudoOpNames(2));
isSTXType = true;
}
@@ -312,19 +325,9 @@ const char* A64DOpcodeBitfield::format()
}
}
- if (opc() == 0x2 && immediateS() == (immediateR() + 1)) {
- // lsl
- appendInstructionName("lsl");
- appendRegisterName(rd(), is64Bit());
- appendSeparator();
- appendRegisterName(rn(), is64Bit());
- appendSeparator();
- appendUnsignedImmediate((is64Bit() ? 63u : 31u) - immediateR());
-
- return m_formatBuffer;
- } else if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) {
+ if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) {
// asr/lsr
- appendInstructionName(!opc() ? "ars" : "lsr");
+ appendInstructionName(!opc() ? "asr" : "lsr");
appendRegisterName(rd(), is64Bit());
appendSeparator();
@@ -333,42 +336,58 @@ const char* A64DOpcodeBitfield::format()
appendUnsignedImmediate(immediateR());
return m_formatBuffer;
- } else if (immediateS() < immediateR()) {
- // bit field insert
- appendInstructionName(insertOpNames());
+ }
+ if (opc() == 0x2 && (immediateS() + 1) == immediateR()) {
+ // lsl
+ appendInstructionName("lsl");
appendRegisterName(rd(), is64Bit());
appendSeparator();
appendRegisterName(rn(), is64Bit());
appendSeparator();
appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
- appendSeparator();
- appendUnsignedImmediate(immediateS() + 1);
-
+
return m_formatBuffer;
- } else {
- // bit field extract
- appendInstructionName(extractOpNames());
+ }
+
+ if (immediateS() < immediateR()) {
+ if (opc() != 1 || rn() != 0x1f) {
+ // bit field insert
+ appendInstructionName(insertOpNames());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
+ appendSeparator();
+ appendUnsignedImmediate(immediateS() + 1);
+
+ return m_formatBuffer;
+ }
+
+ appendInstructionName(opName());
appendRegisterName(rd(), is64Bit());
appendSeparator();
appendRegisterName(rn(), is64Bit());
appendSeparator();
appendUnsignedImmediate(immediateR());
appendSeparator();
- appendUnsignedImmediate(immediateS() - immediateR() + 1);
-
+ appendUnsignedImmediate(immediateS());
+
return m_formatBuffer;
}
+
+ // bit field extract
+ appendInstructionName(extractOpNames());
- appendInstructionName(opName());
appendRegisterName(rd(), is64Bit());
appendSeparator();
appendRegisterName(rn(), is64Bit());
appendSeparator();
appendUnsignedImmediate(immediateR());
appendSeparator();
- appendUnsignedImmediate(immediateS());
+ appendUnsignedImmediate(immediateS() - immediateR() + 1);
return m_formatBuffer;
}
@@ -430,6 +449,38 @@ const char* A64DOpcodeConditionalSelect::format()
}
+const char* const A64DOpcodeDataProcessing1Source::s_opNames[8] = {
+ "rbit", "rev16", "rev32", "rev", "clz", "cls", 0, 0
+};
+
+const char* A64DOpcodeDataProcessing1Source::format()
+{
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (opCode2())
+ return A64DOpcode::format();
+
+ if (opCode() & 0x38)
+ return A64DOpcode::format();
+
+ if ((opCode() & 0x3e) == 0x6)
+ return A64DOpcode::format();
+
+ if (is64Bit() && opCode() == 0x3)
+ return A64DOpcode::format();
+
+ if (!is64Bit() && opCode() == 0x2)
+ appendInstructionName("rev");
+ else
+ appendInstructionName(opName());
+ appendZROrRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendZROrRegisterName(rn(), is64Bit());
+
+ return m_formatBuffer;
+}
+
const char* const A64DOpcodeDataProcessing2Source::s_opNames[8] = {
0, 0, "udiv", "sdiv", "lsl", "lsr", "asr", "ror" // We use the pseudo-op names for the shift/rotate instructions
};
@@ -449,11 +500,11 @@ const char* A64DOpcodeDataProcessing2Source::format()
return A64DOpcode::format();
appendInstructionName(opName());
- appendRegisterName(rd(), is64Bit());
+ appendZROrRegisterName(rd(), is64Bit());
appendSeparator();
- appendRegisterName(rn(), is64Bit());
+ appendZROrRegisterName(rn(), is64Bit());
appendSeparator();
- appendRegisterName(rm(), is64Bit());
+ appendZROrRegisterName(rm(), is64Bit());
return m_formatBuffer;
}
@@ -482,15 +533,18 @@ const char* A64DOpcodeDataProcessing3Source::format()
if (!opName())
return A64DOpcode::format();
+ if ((opNum() & 0x4) && (ra() != 31))
+ return A64DOpcode::format();
+
appendInstructionName(opName());
- appendRegisterName(rd(), is64Bit());
+ appendZROrRegisterName(rd(), is64Bit());
appendSeparator();
bool srcOneAndTwoAre64Bit = is64Bit() & !(opNum() & 0x2);
- appendRegisterName(rn(), srcOneAndTwoAre64Bit);
+ appendZROrRegisterName(rn(), srcOneAndTwoAre64Bit);
appendSeparator();
- appendRegisterName(rm(), srcOneAndTwoAre64Bit);
+ appendZROrRegisterName(rm(), srcOneAndTwoAre64Bit);
- if ((ra() != 31) || !(opNum() & 0x4)) {
+ if (ra() != 31) {
appendSeparator();
appendRegisterName(ra(), is64Bit());
}
@@ -550,23 +604,26 @@ const char* A64OpcodeExceptionGeneration::format()
const char* A64DOpcodeExtract::format()
{
- if (!op21() || !o0Bit())
+ if (op21() || o0Bit())
return A64DOpcode::format();
if (is64Bit() != nBit())
return A64DOpcode::format();
- if (is64Bit() && (immediateS() & 0x20))
+ if (!is64Bit() && (immediateS() & 0x20))
return A64DOpcode::format();
- const char* opName = (rn() == rm()) ? "ror" : "extr";
+ bool isROR = rn() == rm();
+ const char* opName = (isROR) ? "ror" : "extr";
appendInstructionName(opName);
- appendRegisterName(rd(), is64Bit());
+ appendZROrRegisterName(rd(), is64Bit());
appendSeparator();
- appendRegisterName(rn(), is64Bit());
- appendSeparator();
- appendRegisterName(rm(), is64Bit());
+ appendZROrRegisterName(rn(), is64Bit());
+ if (!isROR) {
+ appendSeparator();
+ appendZROrRegisterName(rm(), is64Bit());
+ }
appendSeparator();
appendUnsignedImmediate(immediateS());
@@ -602,6 +659,30 @@ const char* A64DOpcodeFloatingPointCompare::format()
return m_formatBuffer;
}
+const char* A64DOpcodeFloatingPointConditionalSelect::format()
+{
+ if (mBit())
+ return A64DOpcode::format();
+
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (type() & 0x2)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ unsigned registerSize = type() + 2;
+ appendFPRegisterName(rd(), registerSize);
+ appendSeparator();
+ appendFPRegisterName(rn(), registerSize);
+ appendSeparator();
+ appendFPRegisterName(rm(), registerSize);
+ appendSeparator();
+ appendString(conditionName(condition()));
+
+ return m_formatBuffer;
+}
+
const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames[16] = {
"fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt",
"frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti"
@@ -770,10 +851,10 @@ const char* A64DOpcodeFloatingPointIntegerConversions::format()
// fmov Vd.D[1], Xn
bufferPrintf("V%u.D[1]", rd());
appendSeparator();
- appendRegisterName(rn());
+ appendZROrRegisterName(rn());
} else {
// fmov Xd, Vn.D[1]
- appendRegisterName(rd());
+ appendZROrRegisterName(rd());
appendSeparator();
bufferPrintf("V%u.D[1]", rn());
}
@@ -788,9 +869,9 @@ const char* A64DOpcodeFloatingPointIntegerConversions::format()
if (destIsFP) {
appendFPRegisterName(rd(), FPRegisterSize);
appendSeparator();
- appendRegisterName(rn(), is64Bit());
+ appendZROrRegisterName(rn(), is64Bit());
} else {
- appendRegisterName(rd(), is64Bit());
+ appendZROrRegisterName(rd(), is64Bit());
appendSeparator();
appendFPRegisterName(rn(), FPRegisterSize);
}
@@ -812,6 +893,23 @@ const char* A64DOpcodeHint::format()
return m_formatBuffer;
}
+const char* const A64DOpcodeDmb::s_optionNames[16] = {
+ 0, "oshld", "oshst", "osh", 0, "nshld", "nshst", "nsh",
+ 0, "ishld", "ishst", "ish", 0, "ld", "st", "sy"
+};
+
+const char* A64DOpcodeDmb::format()
+{
+ appendInstructionName(opName());
+ const char* thisOption = option();
+ if (thisOption)
+ appendString(thisOption);
+ else
+ appendUnsignedImmediate(crM());
+
+ return m_formatBuffer;
+}
+
// A zero in an entry of the table means the instruction is Unallocated
const char* const A64DOpcodeLoadStore::s_opNames[32] = {
"strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr",
@@ -853,6 +951,8 @@ const char* A64DOpcodeLoadStoreImmediate::format()
appendInstructionName(thisOpName);
if (vBit())
appendFPRegisterName(rt(), size());
+ else if (!opc())
+ appendZROrRegisterName(rt(), is64BitRT());
else
appendRegisterName(rt(), is64BitRT());
appendSeparator();
@@ -910,31 +1010,99 @@ const char* A64DOpcodeLoadStoreRegisterOffset::format()
appendFPRegisterName(rt(), size());
scale = ((opc() & 2)<<1) | size();
} else {
- appendRegisterName(rt(), is64BitRT());
+ if (!opc())
+ appendZROrRegisterName(rt(), is64BitRT());
+ else
+ appendRegisterName(rt(), is64BitRT());
scale = size();
}
appendSeparator();
appendCharacter('[');
appendSPOrRegisterName(rn());
- appendSeparator();
- appendZROrRegisterName(rm(), (option() & 0x3) == 0x3);
+ if (rm() != 31) {
+ appendSeparator();
+ appendRegisterName(rm(), (option() & 0x3) == 0x3);
- unsigned shift = sBit() ? scale : 0;
+ unsigned shift = sBit() ? scale : 0;
- if (option() == 0x3) {
- if (shift) {
+ if (option() == 0x3) {
+ if (shift) {
+ appendSeparator();
+ appendString("lsl ");
+ appendUnsignedImmediate(shift);
+ }
+ } else {
appendSeparator();
- appendString("lsl ");
- appendUnsignedImmediate(shift);
+ appendString(optionName());
+ if (shift)
+ appendUnsignedImmediate(shift);
}
+ }
+
+ appendCharacter(']');
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeLoadStoreRegisterPair::opName()
+{
+ if (!vBit() && lBit() && size() == 0x1)
+ return "ldpsw";
+ if (lBit())
+ return "ldp";
+ return "stp";
+}
+
+const char* A64DOpcodeLoadStoreRegisterPair::format()
+{
+ const char* thisOpName = opName();
+
+ if (size() == 0x3)
+ return A64DOpcode::format();
+
+ if ((offsetMode() < 0x1) || (offsetMode() > 0x3))
+ return A64DOpcode::format();
+
+ if ((offsetMode() == 0x1) && !vBit() && !lBit())
+ return A64DOpcode::format();
+
+ appendInstructionName(thisOpName);
+ unsigned offsetShift;
+ if (vBit()) {
+ appendFPRegisterName(rt(), size());
+ appendSeparator();
+ appendFPRegisterName(rt2(), size());
+ offsetShift = size() + 2;
} else {
+ if (!lBit())
+ appendZROrRegisterName(rt(), is64Bit());
+ else
+ appendRegisterName(rt(), is64Bit());
appendSeparator();
- appendString(optionName());
- if (shift)
- appendUnsignedImmediate(shift);
+ if (!lBit())
+ appendZROrRegisterName(rt2(), is64Bit());
+ else
+ appendRegisterName(rt2(), is64Bit());
+ offsetShift = (size() >> 1) + 2;
}
- appendCharacter(']');
+ appendSeparator();
+ appendCharacter('[');
+ appendSPOrRegisterName(rn());
+
+ int offset = immediate7() << offsetShift;
+
+ if (offsetMode() == 1) {
+ appendCharacter(']');
+ appendSeparator();
+ appendSignedImmediate(offset);
+ } else {
+ appendSeparator();
+ appendSignedImmediate(offset);
+ appendCharacter(']');
+ if (offsetMode() == 0x3)
+ appendCharacter('!');
+ }
return m_formatBuffer;
}
@@ -952,7 +1120,10 @@ const char* A64DOpcodeLoadStoreUnsignedImmediate::format()
appendFPRegisterName(rt(), size());
scale = ((opc() & 2)<<1) | size();
} else {
- appendRegisterName(rt(), is64BitRT());
+ if (!opc())
+ appendZROrRegisterName(rt(), is64BitRT());
+ else
+ appendRegisterName(rt(), is64BitRT());
scale = size();
}
appendSeparator();
@@ -983,15 +1154,15 @@ const char* A64DOpcodeLogicalShiftedRegister::format()
appendInstructionName("tst");
else {
if (isMov())
- appendInstructionName("mov");
+ appendInstructionName(nBit() ? "mvn" : "mov");
else
appendInstructionName(opName(opNumber()));
- appendSPOrRegisterName(rd(), is64Bit());
+ appendZROrRegisterName(rd(), is64Bit());
appendSeparator();
}
if (!isMov()) {
- appendRegisterName(rn(), is64Bit());
+ appendZROrRegisterName(rn(), is64Bit());
appendSeparator();
}
@@ -1075,22 +1246,39 @@ const char* A64DOpcodeLogicalImmediate::format()
return m_formatBuffer;
}
-const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", "", "movz", "movk" };
+const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", 0, "movz", "movk" };
const char* A64DOpcodeMoveWide::format()
{
if (opc() == 1)
return A64DOpcode::format();
- if (!size() && hw() >= 2)
+ if (!is64Bit() && hw() >= 2)
return A64DOpcode::format();
- appendInstructionName(opName());
- appendRegisterName(rd(), is64Bit());
- appendSeparator();
- appendUnsignedImmediate(immediate16());
- if (hw()) {
+ if (!opc() && (!immediate16() || !hw()) && (is64Bit() || immediate16() != 0xffff)) {
+ // MOV pseudo op for MOVN
+ appendInstructionName("mov");
+ appendRegisterName(rd(), is64Bit());
appendSeparator();
- appendShiftAmount(hw());
+
+ if (is64Bit()) {
+ int64_t amount = immediate16() << (hw() * 16);
+ amount = ~amount;
+ appendSignedImmediate64(amount);
+ } else {
+ int32_t amount = immediate16() << (hw() * 16);
+ amount = ~amount;
+ appendSignedImmediate(amount);
+ }
+ } else {
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendUnsignedHexImmediate(immediate16());
+ if (hw()) {
+ appendSeparator();
+ appendShiftAmount(hw());
+ }
}
return m_formatBuffer;
@@ -1130,3 +1318,5 @@ const char* A64DOpcodeUnconditionalBranchRegister::format()
}
} } // namespace JSC::ARM64Disassembler
+
+#endif // USE(ARM64_DISASSEMBLER)