Index: runtime/vm/disassembler_arm.cc |
=================================================================== |
--- runtime/vm/disassembler_arm.cc (revision 24980) |
+++ runtime/vm/disassembler_arm.cc (working copy) |
@@ -33,6 +33,7 @@ |
void PrintRegister(int reg); |
void PrintSRegister(int reg); |
void PrintDRegister(int reg); |
+ void PrintQRegister(int reg); |
void PrintCondition(Instr* instr); |
void PrintShiftRm(Instr* instr); |
void PrintShiftImm(Instr* instr); |
@@ -42,6 +43,7 @@ |
int FormatRegister(Instr* instr, const char* option); |
int FormatSRegister(Instr* instr, const char* option); |
int FormatDRegister(Instr* instr, const char* option); |
+ int FormatQRegister(Instr* instr, const char* option); |
int FormatOption(Instr* instr, const char* option); |
void Format(Instr* instr, const char* format); |
void Unknown(Instr* instr); |
@@ -57,6 +59,7 @@ |
void DecodeType5(Instr* instr); |
void DecodeType6(Instr* instr); |
void DecodeType7(Instr* instr); |
+ void DecodeSIMDDataProcessing(Instr* instr); |
// Convenience functions. |
char* get_buffer() const { return buffer_; } |
@@ -137,6 +140,15 @@ |
} |
+void ARMDecoder::PrintQRegister(int reg) { |
+ ASSERT(0 <= reg); |
+ ASSERT(reg < kNumberOfQRegisters); |
+ buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
+ remaining_size_in_buffer(), |
+ "q%d", reg); |
+} |
+ |
+ |
// These shift names are defined in a way to match the native disassembler |
// formatting. See for example the command "objdump -d <binary file>". |
static const char* shift_names[kMaxShift] = { |
@@ -351,6 +363,26 @@ |
} |
+int ARMDecoder::FormatQRegister(Instr* instr, const char* format) { |
+ ASSERT(format[0] == 'q'); |
+ if (format[1] == 'n') { // 'qn: Qn register |
+ int reg = instr->QnField(); |
+ PrintQRegister(reg); |
+ return 2; |
+ } else if (format[1] == 'd') { // 'qd: Qd register |
+ int reg = instr->QdField(); |
+ PrintQRegister(reg); |
+ return 2; |
+ } else if (format[1] == 'm') { // 'qm: Qm register |
+ int reg = instr->QmField(); |
+ PrintQRegister(reg); |
+ return 2; |
+ } |
+ UNREACHABLE(); |
+ return -1; |
+} |
+ |
+ |
// FormatOption takes a formatting string and interprets it based on |
// the current instructions. The format string points to the first |
// character of the option string (the option escape has already been |
@@ -391,6 +423,9 @@ |
return FormatDRegister(instr, format); |
} |
} |
+ case 'q': { |
+ return FormatQRegister(instr, format); |
+ } |
case 'i': { // 'imm12_4, imm4_12, immf, or immd |
uint16_t immed16; |
if (format[3] == 'f') { |
@@ -446,7 +481,7 @@ |
"%d", |
instr->Bits(0, 8) << 2); |
} else { |
- // 'off12: 12-bit offset for load and store instructions |
+ // 'off12: 12-bit offset for load and store instructions. |
ASSERT(STRING_STARTS_WITH(format, "off12")); |
buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
remaining_size_in_buffer(), |
@@ -455,7 +490,7 @@ |
} |
return 5; |
} |
- // 'off8: 8-bit offset for extra load and store instructions |
+ // 'off8: 8-bit offset for extra load and store instructions. |
ASSERT(STRING_STARTS_WITH(format, "off8")); |
int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField(); |
buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
@@ -464,7 +499,7 @@ |
offs8); |
return 4; |
} |
- case 'p': { // 'pu: P and U bits for load and store instructions |
+ case 'p': { // 'pu: P and U bits for load and store instructions. |
ASSERT(STRING_STARTS_WITH(format, "pu")); |
PrintPU(instr); |
return 2; |
@@ -495,8 +530,16 @@ |
"0x%x", |
instr->SvcField()); |
return 3; |
+ } else if (format[1] == 'z') { |
+ // 'sz: Size field of SIMD instruction. |
+ int sz = 8 << (instr->Bits(20, 2)); |
+ buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
+ remaining_size_in_buffer(), |
+ "I%d", |
+ sz); |
+ return 2; |
} else if (format[1] == ' ') { |
- // 's: S field of data processing instructions |
+ // 's: S field of data processing instructions. |
if (instr->HasS()) { |
Print("s"); |
} |
@@ -505,7 +548,7 @@ |
return FormatSRegister(instr, format); |
} |
} |
- case 't': { // 'target: target of branch instructions |
+ case 't': { // 'target: target of branch instructions. |
ASSERT(STRING_STARTS_WITH(format, "target")); |
int off = (instr->SImmed24Field() << 2) + 8; |
buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
@@ -514,7 +557,7 @@ |
off); |
return 6; |
} |
- case 'u': { // 'u: signed or unsigned multiplies |
+ case 'u': { // 'u: signed or unsigned multiplies. |
if (instr->Bit(22) == 0) { |
Print("u"); |
} else { |
@@ -522,13 +565,13 @@ |
} |
return 1; |
} |
- case 'w': { // 'w: W field of load and store instructions |
+ case 'w': { // 'w: W field of load and store instructions. |
if (instr->HasW()) { |
Print("!"); |
} |
return 1; |
} |
- case 'x': { // 'x: type of extra load/store instructions |
+ case 'x': { // 'x: type of extra load/store instructions. |
if (!instr->HasSign()) { |
Print("h"); |
} else if (instr->HasL()) { |
@@ -1223,6 +1266,24 @@ |
} |
+void ARMDecoder::DecodeSIMDDataProcessing(Instr* instr) { |
+ ASSERT(instr->ConditionField() == kSpecialCondition); |
+ if (instr->Bit(6) == 1) { |
+ if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) && |
+ (instr->Bit(24) == 0)) { |
+ Format(instr, "vadd.'sz 'qd, 'qn, 'qm"); |
+ } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) && |
+ (instr->Bit(24) == 0)) { |
+ Format(instr, "vadd.F32 'qd, 'qn, 'qm"); |
+ } else { |
+ Unknown(instr); |
+ } |
+ } else { |
+ Unknown(instr); |
+ } |
+} |
+ |
+ |
void ARMDecoder::InstructionDecode(uword pc) { |
Instr* instr = Instr::At(pc); |
@@ -1230,7 +1291,11 @@ |
if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) { |
Format(instr, "clrex"); |
} else { |
- Unknown(instr); |
+ if (instr->IsSIMDDataProcessing()) { |
+ DecodeSIMDDataProcessing(instr); |
+ } else { |
+ Unknown(instr); |
+ } |
} |
} else { |
switch (instr->TypeField()) { |