1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
6 | #if defined(TARGET_ARCH_ARM64) |
7 | |
8 | #include "vm/compiler/assembler/disassembler.h" |
9 | |
10 | #include "platform/assert.h" |
11 | #include "vm/instructions.h" |
12 | |
13 | namespace dart { |
14 | |
15 | #if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) |
16 | |
17 | class ARM64Decoder : public ValueObject { |
18 | public: |
19 | ARM64Decoder(char* buffer, size_t buffer_size) |
20 | : buffer_(buffer), buffer_size_(buffer_size), buffer_pos_(0) { |
21 | buffer_[buffer_pos_] = '\0'; |
22 | } |
23 | |
24 | ~ARM64Decoder() {} |
25 | |
26 | // Writes one disassembled instruction into 'buffer' (0-terminated). |
27 | // Returns true if the instruction was successfully decoded, false otherwise. |
28 | void InstructionDecode(uword pc); |
29 | |
30 | private: |
31 | // Bottleneck functions to print into the out_buffer. |
32 | void Print(const char* str); |
33 | |
34 | // Printing of common values. |
35 | void PrintRegister(int reg, R31Type r31t); |
36 | void PrintVRegister(int reg); |
37 | void PrintShiftExtendRm(Instr* instr); |
38 | void PrintMemOperand(Instr* instr); |
39 | void PrintPairMemOperand(Instr* instr); |
40 | void PrintS(Instr* instr); |
41 | void PrintCondition(Instr* instr); |
42 | void PrintInvertedCondition(Instr* instr); |
43 | |
44 | // Handle formatting of instructions and their options. |
45 | int FormatRegister(Instr* instr, const char* option); |
46 | int FormatVRegister(Instr* instr, const char* option); |
47 | int FormatOption(Instr* instr, const char* format); |
48 | void Format(Instr* instr, const char* format); |
49 | void Unknown(Instr* instr); |
50 | |
51 | // Decode instructions. |
52 | #define DECODE_OP(op) void Decode##op(Instr* instr); |
53 | APPLY_OP_LIST(DECODE_OP) |
54 | #undef DECODE_OP |
55 | |
56 | // Convenience functions. |
57 | char* get_buffer() const { return buffer_; } |
58 | char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
59 | size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
60 | |
61 | char* buffer_; // Decode instructions into this buffer. |
62 | size_t buffer_size_; // The size of the character buffer. |
63 | size_t buffer_pos_; // Current character position in buffer. |
64 | |
65 | DISALLOW_ALLOCATION(); |
66 | DISALLOW_COPY_AND_ASSIGN(ARM64Decoder); |
67 | }; |
68 | |
69 | // Support for assertions in the ARM64Decoder formatting functions. |
70 | #define STRING_STARTS_WITH(string, compare_string) \ |
71 | (strncmp(string, compare_string, strlen(compare_string)) == 0) |
72 | |
73 | // Append the str to the output buffer. |
74 | void ARM64Decoder::Print(const char* str) { |
75 | char cur = *str++; |
76 | while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { |
77 | buffer_[buffer_pos_++] = cur; |
78 | cur = *str++; |
79 | } |
80 | buffer_[buffer_pos_] = '\0'; |
81 | } |
82 | |
83 | // These register names are defined in a way to match the native disassembler |
84 | // formatting, except for register aliases ctx (r9), pp (r10) and sp (r19). |
85 | // See for example the command "objdump -d <binary file>". |
86 | static const char* reg_names[kNumberOfCpuRegisters] = { |
87 | "r0" , "r1" , "r2" , "r3" , "r4" , "r5" , "r6" , "r7" , "r8" , "r9" , "r10" , |
88 | "r11" , "r12" , "r13" , "r14" , "r15" , "ip0" , "ip1" , "r18" , "sp" , "r20" , "r21" , |
89 | "nr" , "r23" , "r24" , "r25" , "thr" , "pp" , "ctx" , "fp" , "lr" , "r31" , |
90 | }; |
91 | |
92 | // Print the register name according to the active name converter. |
93 | void ARM64Decoder::PrintRegister(int reg, R31Type r31t) { |
94 | ASSERT(0 <= reg); |
95 | ASSERT(reg < kNumberOfCpuRegisters); |
96 | if (reg == 31) { |
97 | const char* rstr = (r31t == R31IsZR) ? "zr" : "csp" ; |
98 | Print(rstr); |
99 | } else { |
100 | Print(reg_names[reg]); |
101 | } |
102 | } |
103 | |
104 | void ARM64Decoder::PrintVRegister(int reg) { |
105 | ASSERT(0 <= reg); |
106 | ASSERT(reg < kNumberOfVRegisters); |
107 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
108 | remaining_size_in_buffer(), "v%d" , reg); |
109 | } |
110 | |
111 | // These shift names are defined in a way to match the native disassembler |
112 | // formatting. See for example the command "objdump -d <binary file>". |
113 | static const char* shift_names[kMaxShift] = {"lsl" , "lsr" , "asr" , "ror" }; |
114 | |
115 | static const char* extend_names[kMaxExtend] = { |
116 | "uxtb" , "uxth" , "uxtw" , "uxtx" , "sxtb" , "sxth" , "sxtw" , "sxtx" , |
117 | }; |
118 | |
119 | // These condition names are defined in a way to match the native disassembler |
120 | // formatting. See for example the command "objdump -d <binary file>". |
121 | static const char* cond_names[kNumberOfConditions] = { |
122 | "eq" , "ne" , "cs" , "cc" , "mi" , "pl" , "vs" , "vc" , |
123 | "hi" , "ls" , "ge" , "lt" , "gt" , "le" , "" , "invalid" , |
124 | }; |
125 | |
126 | // Print the condition guarding the instruction. |
127 | void ARM64Decoder::PrintCondition(Instr* instr) { |
128 | if (instr->IsConditionalSelectOp()) { |
129 | Print(cond_names[instr->SelectConditionField()]); |
130 | } else { |
131 | Print(cond_names[instr->ConditionField()]); |
132 | } |
133 | } |
134 | |
135 | // Print the inverse of the condition guarding the instruction. |
136 | void ARM64Decoder::PrintInvertedCondition(Instr* instr) { |
137 | if (instr->IsConditionalSelectOp()) { |
138 | Print(cond_names[InvertCondition(instr->SelectConditionField())]); |
139 | } else { |
140 | Print(cond_names[InvertCondition(instr->ConditionField())]); |
141 | } |
142 | } |
143 | |
144 | // Print the register shift operands for the instruction. Generally used for |
145 | // data processing instructions. |
146 | void ARM64Decoder::PrintShiftExtendRm(Instr* instr) { |
147 | int rm = instr->RmField(); |
148 | Shift shift = instr->ShiftTypeField(); |
149 | int shift_amount = instr->ShiftAmountField(); |
150 | Extend extend = instr->ExtendTypeField(); |
151 | int extend_shift_amount = instr->ExtShiftAmountField(); |
152 | |
153 | PrintRegister(rm, R31IsZR); |
154 | |
155 | if (instr->IsShift() && (shift == LSL) && (shift_amount == 0)) { |
156 | // Special case for using rm only. |
157 | return; |
158 | } |
159 | if (instr->IsShift()) { |
160 | // by immediate |
161 | if ((shift == ROR) && (shift_amount == 0)) { |
162 | Print(" RRX" ); |
163 | return; |
164 | } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) { |
165 | shift_amount = 32; |
166 | } |
167 | buffer_pos_ += |
168 | Utils::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
169 | " %s #%d" , shift_names[shift], shift_amount); |
170 | } else { |
171 | ASSERT(instr->IsExtend()); |
172 | // by register |
173 | buffer_pos_ += |
174 | Utils::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
175 | " %s" , extend_names[extend]); |
176 | if (((instr->SFField() == 1) && (extend == UXTX)) || |
177 | ((instr->SFField() == 0) && (extend == UXTW))) { |
178 | // Shift amount. |
179 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
180 | remaining_size_in_buffer(), " %d" , |
181 | extend_shift_amount); |
182 | } |
183 | } |
184 | } |
185 | |
186 | void ARM64Decoder::PrintMemOperand(Instr* instr) { |
187 | const Register rn = instr->RnField(); |
188 | if (instr->Bit(24) == 1) { |
189 | // rn + scaled unsigned 12-bit immediate offset. |
190 | const uint32_t scale = instr->SzField(); |
191 | const uint32_t imm12 = instr->Imm12Field(); |
192 | const uint32_t off = imm12 << scale; |
193 | Print("[" ); |
194 | PrintRegister(rn, R31IsSP); |
195 | if (off != 0) { |
196 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
197 | remaining_size_in_buffer(), ", #%d" , off); |
198 | } |
199 | Print("]" ); |
200 | } else { |
201 | switch (instr->Bits(10, 2)) { |
202 | case 0: { |
203 | // rn + signed 9-bit immediate, pre-index, no writeback. |
204 | const int32_t imm9 = instr->SImm9Field(); |
205 | Print("[" ); |
206 | PrintRegister(rn, R31IsSP); |
207 | buffer_pos_ += |
208 | Utils::SNPrint(current_position_in_buffer(), |
209 | remaining_size_in_buffer(), ", #%d" , imm9); |
210 | Print("]" ); |
211 | break; |
212 | } |
213 | case 1: { |
214 | const int32_t imm9 = instr->SImm9Field(); |
215 | // rn + signed 9-bit immediate, post-index, writeback. |
216 | Print("[" ); |
217 | PrintRegister(rn, R31IsSP); |
218 | Print("]" ); |
219 | buffer_pos_ += |
220 | Utils::SNPrint(current_position_in_buffer(), |
221 | remaining_size_in_buffer(), ", #%d !" , imm9); |
222 | break; |
223 | } |
224 | case 2: { |
225 | const Register rm = instr->RmField(); |
226 | const Extend ext = instr->ExtendTypeField(); |
227 | const int s = instr->Bit(12); |
228 | Print("[" ); |
229 | PrintRegister(rn, R31IsSP); |
230 | Print(", " ); |
231 | PrintRegister(rm, R31IsZR); |
232 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
233 | remaining_size_in_buffer(), " %s" , |
234 | extend_names[ext]); |
235 | if (s == 1) { |
236 | Print(" scaled" ); |
237 | } |
238 | Print("]" ); |
239 | break; |
240 | } |
241 | case 3: { |
242 | const int32_t imm9 = instr->SImm9Field(); |
243 | // rn + signed 9-bit immediate, pre-index, writeback. |
244 | Print("[" ); |
245 | PrintRegister(rn, R31IsSP); |
246 | buffer_pos_ += |
247 | Utils::SNPrint(current_position_in_buffer(), |
248 | remaining_size_in_buffer(), ", #%d" , imm9); |
249 | Print("] !" ); |
250 | break; |
251 | } |
252 | default: { Print("???" ); } |
253 | } |
254 | } |
255 | } |
256 | |
257 | void ARM64Decoder::PrintPairMemOperand(Instr* instr) { |
258 | const Register rn = instr->RnField(); |
259 | const uint32_t simm7 = instr->SImm7Field(); |
260 | const int32_t offset = simm7 << (2 + instr->Bit(31)); |
261 | Print("[" ); |
262 | PrintRegister(rn, R31IsSP); |
263 | switch (instr->Bits(23, 3)) { |
264 | case 1: |
265 | // rn + (imm7 << (2 + B31)), post-index, writeback. |
266 | buffer_pos_ += |
267 | Utils::SNPrint(current_position_in_buffer(), |
268 | remaining_size_in_buffer(), "], #%d !" , offset); |
269 | break; |
270 | case 2: |
271 | // rn + (imm7 << (2 + B31)), pre-index, no writeback. |
272 | buffer_pos_ += |
273 | Utils::SNPrint(current_position_in_buffer(), |
274 | remaining_size_in_buffer(), ", #%d ]" , offset); |
275 | break; |
276 | case 3: |
277 | // rn + (imm7 << (2 + B31)), pre-index, writeback. |
278 | buffer_pos_ += |
279 | Utils::SNPrint(current_position_in_buffer(), |
280 | remaining_size_in_buffer(), ", #%d ]!" , offset); |
281 | break; |
282 | default: |
283 | Print(", ???]" ); |
284 | break; |
285 | } |
286 | } |
287 | |
288 | // Handle all register based formatting in these functions to reduce the |
289 | // complexity of FormatOption. |
290 | int ARM64Decoder::FormatRegister(Instr* instr, const char* format) { |
291 | ASSERT(format[0] == 'r'); |
292 | if (format[1] == 'n') { // 'rn: Rn register |
293 | int reg = instr->RnField(); |
294 | PrintRegister(reg, instr->RnMode()); |
295 | return 2; |
296 | } else if (format[1] == 'd') { // 'rd: Rd register |
297 | int reg = instr->RdField(); |
298 | PrintRegister(reg, instr->RdMode()); |
299 | return 2; |
300 | } else if (format[1] == 'm') { // 'rm: Rm register |
301 | int reg = instr->RmField(); |
302 | PrintRegister(reg, R31IsZR); |
303 | return 2; |
304 | } else if (format[1] == 't') { // 'rt: Rt register |
305 | int reg = instr->RtField(); |
306 | PrintRegister(reg, R31IsZR); |
307 | return 2; |
308 | } else if (format[1] == 'a') { // 'ra: Ra register |
309 | int reg = instr->RaField(); |
310 | PrintRegister(reg, R31IsZR); |
311 | return 2; |
312 | } else if (format[1] == 's') { // 'rs: Rs register |
313 | int reg = instr->RsField(); |
314 | PrintRegister(reg, R31IsZR); |
315 | return 2; |
316 | } |
317 | UNREACHABLE(); |
318 | return -1; |
319 | } |
320 | |
321 | int ARM64Decoder::FormatVRegister(Instr* instr, const char* format) { |
322 | ASSERT(format[0] == 'v'); |
323 | if (format[1] == 'd') { |
324 | int reg = instr->VdField(); |
325 | PrintVRegister(reg); |
326 | return 2; |
327 | } else if (format[1] == 'n') { |
328 | int reg = instr->VnField(); |
329 | PrintVRegister(reg); |
330 | return 2; |
331 | } else if (format[1] == 'm') { |
332 | int reg = instr->VmField(); |
333 | PrintVRegister(reg); |
334 | return 2; |
335 | } else if (format[1] == 't') { |
336 | int reg = instr->VtField(); |
337 | PrintVRegister(reg); |
338 | return 2; |
339 | } |
340 | UNREACHABLE(); |
341 | return -1; |
342 | } |
343 | |
344 | // FormatOption takes a formatting string and interprets it based on |
345 | // the current instructions. The format string points to the first |
346 | // character of the option string (the option escape has already been |
347 | // consumed by the caller.) FormatOption returns the number of |
348 | // characters that were consumed from the formatting string. |
349 | int ARM64Decoder::FormatOption(Instr* instr, const char* format) { |
350 | switch (format[0]) { |
351 | case 'b': { |
352 | if (format[3] == 'i') { |
353 | ASSERT(STRING_STARTS_WITH(format, "bitimm" )); |
354 | const uint64_t imm = instr->ImmLogical(); |
355 | buffer_pos_ += |
356 | Utils::SNPrint(current_position_in_buffer(), |
357 | remaining_size_in_buffer(), "0x%" Px64, imm); |
358 | return 6; |
359 | } else { |
360 | ASSERT(STRING_STARTS_WITH(format, "bitpos" )); |
361 | int bitpos = instr->Bits(19, 5) | (instr->Bit(31) << 5); |
362 | buffer_pos_ += |
363 | Utils::SNPrint(current_position_in_buffer(), |
364 | remaining_size_in_buffer(), "#%d" , bitpos); |
365 | return 6; |
366 | } |
367 | } |
368 | case 'c': { |
369 | if (format[1] == 's') { |
370 | ASSERT(STRING_STARTS_WITH(format, "csz" )); |
371 | const int32_t imm5 = instr->Bits(16, 5); |
372 | char const* typ = "??" ; |
373 | if (imm5 & 0x1) { |
374 | typ = "b" ; |
375 | } else if (imm5 & 0x2) { |
376 | typ = "h" ; |
377 | } else if (imm5 & 0x4) { |
378 | typ = "s" ; |
379 | } else if (imm5 & 0x8) { |
380 | typ = "d" ; |
381 | } |
382 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
383 | remaining_size_in_buffer(), "%s" , typ); |
384 | return 3; |
385 | } else { |
386 | ASSERT(STRING_STARTS_WITH(format, "cond" )); |
387 | if (format[4] == 'i') { |
388 | ASSERT(STRING_STARTS_WITH(format, "condinverted" )); |
389 | PrintInvertedCondition(instr); |
390 | return 12; |
391 | } else { |
392 | PrintCondition(instr); |
393 | return 4; |
394 | } |
395 | } |
396 | } |
397 | case 'd': { |
398 | int64_t off; |
399 | if (format[4] == '2') { |
400 | ASSERT(STRING_STARTS_WITH(format, "dest26" )); |
401 | off = static_cast<uint64_t>(instr->SImm26Field()) << 2; |
402 | } else { |
403 | if (format[5] == '4') { |
404 | ASSERT(STRING_STARTS_WITH(format, "dest14" )); |
405 | off = static_cast<uint64_t>(instr->SImm14Field()) << 2; |
406 | } else { |
407 | ASSERT(STRING_STARTS_WITH(format, "dest19" )); |
408 | off = static_cast<uint64_t>(instr->SImm19Field()) << 2; |
409 | } |
410 | } |
411 | if (FLAG_disassemble_relative) { |
412 | buffer_pos_ += |
413 | Utils::SNPrint(current_position_in_buffer(), |
414 | remaining_size_in_buffer(), "%+" Pd64 "" , off); |
415 | } else { |
416 | uword destination = reinterpret_cast<uword>(instr) + off; |
417 | buffer_pos_ += |
418 | Utils::SNPrint(current_position_in_buffer(), |
419 | remaining_size_in_buffer(), "%#" Px "" , destination); |
420 | } |
421 | return 6; |
422 | } |
423 | case 'f': { |
424 | ASSERT(STRING_STARTS_WITH(format, "fsz" )); |
425 | const int sz = instr->SzField(); |
426 | char const* sz_str; |
427 | switch (sz) { |
428 | case 0: |
429 | if (instr->Bit(23) == 1) { |
430 | sz_str = "q" ; |
431 | } else { |
432 | sz_str = "b" ; |
433 | } |
434 | break; |
435 | case 1: |
436 | sz_str = "h" ; |
437 | break; |
438 | case 2: |
439 | sz_str = "s" ; |
440 | break; |
441 | case 3: |
442 | sz_str = "d" ; |
443 | break; |
444 | default: |
445 | sz_str = "?" ; |
446 | break; |
447 | } |
448 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
449 | remaining_size_in_buffer(), "%s" , sz_str); |
450 | return 3; |
451 | } |
452 | case 'h': { |
453 | ASSERT(STRING_STARTS_WITH(format, "hw" )); |
454 | const int shift = instr->HWField() << 4; |
455 | if (shift != 0) { |
456 | buffer_pos_ += |
457 | Utils::SNPrint(current_position_in_buffer(), |
458 | remaining_size_in_buffer(), "lsl %d" , shift); |
459 | } |
460 | return 2; |
461 | } |
462 | case 'i': { // 'imm12, 'imm16, 'immd |
463 | if (format[1] == 'd') { |
464 | // Element index for a SIMD copy instruction. |
465 | ASSERT(STRING_STARTS_WITH(format, "idx" )); |
466 | const int32_t imm4 = instr->Bits(11, 4); |
467 | const int32_t imm5 = instr->Bits(16, 5); |
468 | int32_t shift = 0; |
469 | int32_t imm = -1; |
470 | if (format[3] == '4') { |
471 | imm = imm4; |
472 | } else if (format[3] == '5') { |
473 | imm = imm5; |
474 | shift = 1; |
475 | } |
476 | int32_t idx = -1; |
477 | if (imm5 & 0x1) { |
478 | idx = imm >> shift; |
479 | } else if (imm5 & 0x2) { |
480 | idx = imm >> (shift + 1); |
481 | } else if (imm5 & 0x4) { |
482 | idx = imm >> (shift + 2); |
483 | } else if (imm5 & 0x8) { |
484 | idx = imm >> (shift + 3); |
485 | } |
486 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
487 | remaining_size_in_buffer(), "[%d]" , idx); |
488 | return 4; |
489 | } else if (format[3] == '1') { |
490 | uint64_t imm; |
491 | int ret = 5; |
492 | if (format[4] == '2') { |
493 | ASSERT(STRING_STARTS_WITH(format, "imm12" )); |
494 | imm = instr->Imm12Field(); |
495 | if (format[5] == 's') { |
496 | // shifted immediate. |
497 | if (instr->Imm12ShiftField() == 1) { |
498 | imm = imm << 12; |
499 | } else if ((instr->Imm12ShiftField() & 0x2) != 0) { |
500 | Print("Unknown Shift" ); |
501 | } |
502 | ret = 6; |
503 | } |
504 | } else { |
505 | ASSERT(STRING_STARTS_WITH(format, "imm16" )); |
506 | imm = instr->Imm16Field(); |
507 | } |
508 | buffer_pos_ += |
509 | Utils::SNPrint(current_position_in_buffer(), |
510 | remaining_size_in_buffer(), "0x%" Px64, imm); |
511 | return ret; |
512 | } else { |
513 | ASSERT(STRING_STARTS_WITH(format, "imm" )); |
514 | if (format[3] == 'd') { |
515 | double dimm = bit_cast<double, int64_t>( |
516 | Instr::VFPExpandImm(instr->Imm8Field())); |
517 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
518 | remaining_size_in_buffer(), "%f" , dimm); |
519 | return 4; |
520 | } else if (format[3] == 'r') { |
521 | int immr = instr->ImmRField(); |
522 | buffer_pos_ += |
523 | Utils::SNPrint(current_position_in_buffer(), |
524 | remaining_size_in_buffer(), "#%d" , immr); |
525 | return 4; |
526 | } else { |
527 | ASSERT(format[3] == 's'); |
528 | int imms = instr->ImmSField(); |
529 | buffer_pos_ += |
530 | Utils::SNPrint(current_position_in_buffer(), |
531 | remaining_size_in_buffer(), "#%d" , imms); |
532 | return 4; |
533 | } |
534 | } |
535 | } |
536 | case 'm': { |
537 | ASSERT(STRING_STARTS_WITH(format, "memop" )); |
538 | PrintMemOperand(instr); |
539 | return 5; |
540 | } |
541 | case 'p': { |
542 | if (format[1] == 'c') { |
543 | if (format[2] == 'a') { |
544 | ASSERT(STRING_STARTS_WITH(format, "pcadr" )); |
545 | const uint64_t immhi = instr->SImm19Field(); |
546 | const uint64_t immlo = instr->Bits(29, 2); |
547 | const uint64_t off = (immhi << 2) | immlo; |
548 | const uint64_t pc = reinterpret_cast<int64_t>(instr); |
549 | const uint64_t dest = pc + off; |
550 | buffer_pos_ += |
551 | Utils::SNPrint(current_position_in_buffer(), |
552 | remaining_size_in_buffer(), "0x%" Px64, dest); |
553 | } else { |
554 | ASSERT(STRING_STARTS_WITH(format, "pcldr" )); |
555 | const uint64_t off = instr->SImm19Field() << 2; |
556 | const uint64_t pc = reinterpret_cast<int64_t>(instr); |
557 | const uint64_t dest = pc + off; |
558 | buffer_pos_ += |
559 | Utils::SNPrint(current_position_in_buffer(), |
560 | remaining_size_in_buffer(), "0x%" Px64, dest); |
561 | } |
562 | return 5; |
563 | } else { |
564 | ASSERT(STRING_STARTS_WITH(format, "pmemop" )); |
565 | PrintPairMemOperand(instr); |
566 | return 6; |
567 | } |
568 | } |
569 | case 'r': { |
570 | return FormatRegister(instr, format); |
571 | } |
572 | case 'v': { |
573 | if (format[1] == 's') { |
574 | ASSERT(STRING_STARTS_WITH(format, "vsz" )); |
575 | char const* sz_str = NULL; |
576 | if (instr->Bits(14, 2) == 3) { |
577 | switch (instr->Bit(22)) { |
578 | case 0: |
579 | sz_str = "s" ; |
580 | break; |
581 | case 1: |
582 | sz_str = "d" ; |
583 | break; |
584 | default: |
585 | UNREACHABLE(); |
586 | break; |
587 | } |
588 | } else { |
589 | switch (instr->Bit(22)) { |
590 | case 0: |
591 | sz_str = "w" ; |
592 | break; |
593 | case 1: |
594 | sz_str = "x" ; |
595 | break; |
596 | default: |
597 | UNREACHABLE(); |
598 | break; |
599 | } |
600 | } |
601 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
602 | remaining_size_in_buffer(), "%s" , sz_str); |
603 | return 3; |
604 | } else { |
605 | return FormatVRegister(instr, format); |
606 | } |
607 | } |
608 | case 's': { // 's: S flag. |
609 | if (format[1] == 'h') { |
610 | ASSERT(STRING_STARTS_WITH(format, "shift_op" )); |
611 | PrintShiftExtendRm(instr); |
612 | return 8; |
613 | } else if (format[1] == 'f') { |
614 | ASSERT(STRING_STARTS_WITH(format, "sf" )); |
615 | if (instr->SFField() == 1) { |
616 | // 64-bit width is most commonly used, no need to print "x". |
617 | } else { |
618 | Print("w" ); |
619 | } |
620 | return 2; |
621 | } else if (format[1] == 'z') { |
622 | ASSERT(STRING_STARTS_WITH(format, "sz" )); |
623 | const int sz = instr->SzField(); |
624 | char const* sz_str; |
625 | switch (sz) { |
626 | case 0: |
627 | sz_str = "b" ; |
628 | break; |
629 | case 1: |
630 | sz_str = "h" ; |
631 | break; |
632 | case 2: |
633 | sz_str = "w" ; |
634 | break; |
635 | case 3: |
636 | sz_str = "x" ; |
637 | break; |
638 | default: |
639 | sz_str = "?" ; |
640 | break; |
641 | } |
642 | buffer_pos_ += Utils::SNPrint(current_position_in_buffer(), |
643 | remaining_size_in_buffer(), "%s" , sz_str); |
644 | return 2; |
645 | } else if (format[1] == ' ') { |
646 | if (instr->HasS()) { |
647 | Print("s" ); |
648 | } |
649 | return 1; |
650 | } else { |
651 | UNREACHABLE(); |
652 | } |
653 | } |
654 | default: { |
655 | UNREACHABLE(); |
656 | break; |
657 | } |
658 | } |
659 | UNREACHABLE(); |
660 | return -1; |
661 | } |
662 | |
663 | // Format takes a formatting string for a whole instruction and prints it into |
664 | // the output buffer. All escaped options are handed to FormatOption to be |
665 | // parsed further. |
666 | void ARM64Decoder::Format(Instr* instr, const char* format) { |
667 | char cur = *format++; |
668 | while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { |
669 | if (cur == '\'') { // Single quote is used as the formatting escape. |
670 | format += FormatOption(instr, format); |
671 | } else { |
672 | buffer_[buffer_pos_++] = cur; |
673 | } |
674 | cur = *format++; |
675 | } |
676 | buffer_[buffer_pos_] = '\0'; |
677 | } |
678 | |
679 | // For currently unimplemented decodings the disassembler calls Unknown(instr) |
680 | // which will just print "unknown" of the instruction bits. |
681 | void ARM64Decoder::Unknown(Instr* instr) { |
682 | Format(instr, "unknown" ); |
683 | } |
684 | |
685 | void ARM64Decoder::DecodeMoveWide(Instr* instr) { |
686 | switch (instr->Bits(29, 2)) { |
687 | case 0: |
688 | Format(instr, "movn'sf 'rd, 'imm16 'hw" ); |
689 | break; |
690 | case 2: |
691 | Format(instr, "movz'sf 'rd, 'imm16 'hw" ); |
692 | break; |
693 | case 3: |
694 | Format(instr, "movk'sf 'rd, 'imm16 'hw" ); |
695 | break; |
696 | default: |
697 | Unknown(instr); |
698 | break; |
699 | } |
700 | } |
701 | |
702 | void ARM64Decoder::DecodeLoadStoreReg(Instr* instr) { |
703 | if (instr->Bit(26) == 1) { |
704 | // SIMD or FP src/dst. |
705 | if (instr->Bit(22) == 1) { |
706 | Format(instr, "fldr'fsz 'vt, 'memop" ); |
707 | } else { |
708 | Format(instr, "fstr'fsz 'vt, 'memop" ); |
709 | } |
710 | } else { |
711 | // Integer src/dst. |
712 | if (instr->Bits(22, 2) == 0) { |
713 | Format(instr, "str'sz 'rt, 'memop" ); |
714 | } else if (instr->Bits(23, 1) == 1) { |
715 | Format(instr, "ldrs'sz 'rt, 'memop" ); |
716 | } else { |
717 | Format(instr, "ldr'sz 'rt, 'memop" ); |
718 | } |
719 | } |
720 | } |
721 | |
722 | void ARM64Decoder::DecodeLoadStoreRegPair(Instr* instr) { |
723 | if (instr->Bit(22) == 1) { |
724 | // Load. |
725 | Format(instr, "ldp'sf 'rt, 'ra, 'pmemop" ); |
726 | } else { |
727 | // Store. |
728 | Format(instr, "stp'sf 'rt, 'ra, 'pmemop" ); |
729 | } |
730 | } |
731 | |
732 | void ARM64Decoder::DecodeLoadRegLiteral(Instr* instr) { |
733 | if ((instr->Bit(31) != 0) || (instr->Bit(29) != 0) || |
734 | (instr->Bits(24, 3) != 0)) { |
735 | Unknown(instr); |
736 | } |
737 | if (instr->Bit(30)) { |
738 | Format(instr, "ldrx 'rt, 'pcldr" ); |
739 | } else { |
740 | Format(instr, "ldrw 'rt, 'pcldr" ); |
741 | } |
742 | } |
743 | |
744 | void ARM64Decoder::DecodeLoadStoreExclusive(Instr* instr) { |
745 | if (instr->Bit(21) != 0 || instr->Bit(23) != instr->Bit(15)) { |
746 | Unknown(instr); |
747 | } |
748 | const int32_t size = instr->Bits(30, 2); |
749 | if (size != 3) { |
750 | Unknown(instr); |
751 | } |
752 | |
753 | const bool is_load = instr->Bit(22) == 1; |
754 | const bool is_exclusive = instr->Bit(23) == 0; |
755 | const bool is_ordered = instr->Bit(15) == 1; |
756 | if (is_load) { |
757 | const bool is_load_acquire = !is_exclusive && is_ordered; |
758 | if (is_load_acquire) { |
759 | Format(instr, "ldar 'rt, 'rn" ); |
760 | } else { |
761 | Format(instr, "ldxr 'rt, 'rn" ); |
762 | } |
763 | } else { |
764 | const bool is_store_release = !is_exclusive && is_ordered; |
765 | if (is_store_release) { |
766 | Format(instr, "stlr 'rt, 'rn" ); |
767 | } else { |
768 | Format(instr, "stxr 'rs, 'rt, 'rn" ); |
769 | } |
770 | } |
771 | } |
772 | |
773 | void ARM64Decoder::DecodeAddSubImm(Instr* instr) { |
774 | switch (instr->Bit(30)) { |
775 | case 0: { |
776 | if ((instr->RdField() == R31) && (instr->SField() == 1)) { |
777 | Format(instr, "cmni'sf 'rn, 'imm12s" ); |
778 | } else { |
779 | if (((instr->RdField() == R31) || (instr->RnField() == R31)) && |
780 | (instr->Imm12Field() == 0) && (instr->Bit(29) == 0)) { |
781 | Format(instr, "mov'sf 'rd, 'rn" ); |
782 | } else { |
783 | Format(instr, "addi'sf's 'rd, 'rn, 'imm12s" ); |
784 | } |
785 | } |
786 | break; |
787 | } |
788 | case 1: { |
789 | if ((instr->RdField() == R31) && (instr->SField() == 1)) { |
790 | Format(instr, "cmpi'sf 'rn, 'imm12s" ); |
791 | } else { |
792 | Format(instr, "subi'sf's 'rd, 'rn, 'imm12s" ); |
793 | } |
794 | break; |
795 | } |
796 | default: |
797 | Unknown(instr); |
798 | break; |
799 | } |
800 | } |
801 | |
802 | void ARM64Decoder::DecodeBitfield(Instr* instr) { |
803 | int op = instr->Bits(29, 2); |
804 | int r_imm = instr->ImmRField(); |
805 | int s_imm = instr->ImmSField(); |
806 | switch (op) { |
807 | case 0: |
808 | if (r_imm == 0) { |
809 | if (s_imm == 7) { |
810 | Format(instr, "sxtb 'rd, 'rn" ); |
811 | break; |
812 | } else if (s_imm == 15) { |
813 | Format(instr, "sxth 'rd, 'rn" ); |
814 | break; |
815 | } else if (s_imm == 31) { |
816 | Format(instr, "sxtw 'rd, 'rn" ); |
817 | break; |
818 | } |
819 | } |
820 | Format(instr, "sbfm'sf 'rd, 'rn, 'immr, 'imms" ); |
821 | break; |
822 | case 1: |
823 | Format(instr, "bfm'sf 'rd, 'rn, 'immr, 'imms" ); |
824 | break; |
825 | case 2: |
826 | if (r_imm == 0) { |
827 | if (s_imm == 7) { |
828 | Format(instr, "uxtb 'rd, 'rn" ); |
829 | break; |
830 | } else if (s_imm == 15) { |
831 | Format(instr, "uxth 'rd, 'rn" ); |
832 | break; |
833 | } |
834 | } |
835 | Format(instr, "ubfm'sf 'rd, 'rn, 'immr, 'imms" ); |
836 | break; |
837 | default: |
838 | Unknown(instr); |
839 | break; |
840 | } |
841 | } |
842 | |
843 | void ARM64Decoder::DecodeLogicalImm(Instr* instr) { |
844 | int op = instr->Bits(29, 2); |
845 | switch (op) { |
846 | case 0: |
847 | Format(instr, "andi'sf 'rd, 'rn, 'bitimm" ); |
848 | break; |
849 | case 1: { |
850 | if (instr->RnField() == R31) { |
851 | Format(instr, "mov'sf 'rd, 'bitimm" ); |
852 | } else { |
853 | Format(instr, "orri'sf 'rd, 'rn, 'bitimm" ); |
854 | } |
855 | break; |
856 | } |
857 | case 2: |
858 | Format(instr, "eori'sf 'rd, 'rn, 'bitimm" ); |
859 | break; |
860 | case 3: |
861 | Format(instr, "andi'sfs 'rd, 'rn, 'bitimm" ); |
862 | break; |
863 | default: |
864 | Unknown(instr); |
865 | break; |
866 | } |
867 | } |
868 | |
869 | void ARM64Decoder::DecodePCRel(Instr* instr) { |
870 | const int op = instr->Bit(31); |
871 | if (op == 0) { |
872 | Format(instr, "adr 'rd, 'pcadr" ); |
873 | } else { |
874 | Unknown(instr); |
875 | } |
876 | } |
877 | |
878 | void ARM64Decoder::DecodeDPImmediate(Instr* instr) { |
879 | if (instr->IsMoveWideOp()) { |
880 | DecodeMoveWide(instr); |
881 | } else if (instr->IsAddSubImmOp()) { |
882 | DecodeAddSubImm(instr); |
883 | } else if (instr->IsBitfieldOp()) { |
884 | DecodeBitfield(instr); |
885 | } else if (instr->IsLogicalImmOp()) { |
886 | DecodeLogicalImm(instr); |
887 | } else if (instr->IsPCRelOp()) { |
888 | DecodePCRel(instr); |
889 | } else { |
890 | Unknown(instr); |
891 | } |
892 | } |
893 | |
894 | void ARM64Decoder::DecodeExceptionGen(Instr* instr) { |
895 | if ((instr->Bits(0, 2) == 1) && (instr->Bits(2, 3) == 0) && |
896 | (instr->Bits(21, 3) == 0)) { |
897 | Format(instr, "svc 'imm16" ); |
898 | } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && |
899 | (instr->Bits(21, 3) == 1)) { |
900 | Format(instr, "brk 'imm16" ); |
901 | } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) && |
902 | (instr->Bits(21, 3) == 2)) { |
903 | Format(instr, "hlt 'imm16" ); |
904 | } else { |
905 | Unknown(instr); |
906 | } |
907 | } |
908 | |
909 | void ARM64Decoder::DecodeSystem(Instr* instr) { |
910 | if (instr->InstructionBits() == CLREX) { |
911 | Format(instr, "clrex" ); |
912 | return; |
913 | } |
914 | |
915 | if ((instr->Bits(0, 8) == 0x1f) && (instr->Bits(12, 4) == 2) && |
916 | (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) && |
917 | (instr->Bit(21) == 0)) { |
918 | if (instr->Bits(8, 4) == 0) { |
919 | Format(instr, "nop" ); |
920 | } else { |
921 | Unknown(instr); |
922 | } |
923 | } else { |
924 | Unknown(instr); |
925 | } |
926 | } |
927 | |
928 | void ARM64Decoder::DecodeUnconditionalBranchReg(Instr* instr) { |
929 | if ((instr->Bits(0, 5) == 0) && (instr->Bits(10, 5) == 0) && |
930 | (instr->Bits(16, 5) == 0x1f)) { |
931 | switch (instr->Bits(21, 4)) { |
932 | case 0: |
933 | Format(instr, "br 'rn" ); |
934 | break; |
935 | case 1: |
936 | Format(instr, "blr 'rn" ); |
937 | break; |
938 | case 2: |
939 | Format(instr, "ret 'rn" ); |
940 | break; |
941 | default: |
942 | Unknown(instr); |
943 | break; |
944 | } |
945 | } |
946 | } |
947 | |
948 | void ARM64Decoder::DecodeCompareAndBranch(Instr* instr) { |
949 | const int op = instr->Bit(24); |
950 | if (op == 0) { |
951 | Format(instr, "cbz'sf 'rt, 'dest19" ); |
952 | } else { |
953 | Format(instr, "cbnz'sf 'rt, 'dest19" ); |
954 | } |
955 | } |
956 | |
957 | void ARM64Decoder::DecodeConditionalBranch(Instr* instr) { |
958 | if ((instr->Bit(24) != 0) || (instr->Bit(4) != 0)) { |
959 | Unknown(instr); |
960 | return; |
961 | } |
962 | Format(instr, "b'cond 'dest19" ); |
963 | } |
964 | |
965 | void ARM64Decoder::DecodeTestAndBranch(Instr* instr) { |
966 | const int op = instr->Bit(24); |
967 | if (op == 0) { |
968 | Format(instr, "tbz'sf 'rt, 'bitpos, 'dest14" ); |
969 | } else { |
970 | Format(instr, "tbnz'sf 'rt, 'bitpos, 'dest14" ); |
971 | } |
972 | } |
973 | |
974 | void ARM64Decoder::DecodeUnconditionalBranch(Instr* instr) { |
975 | const int op = instr->Bit(31); |
976 | if (op == 0) { |
977 | Format(instr, "b 'dest26" ); |
978 | } else { |
979 | Format(instr, "bl 'dest26" ); |
980 | } |
981 | } |
982 | |
983 | void ARM64Decoder::DecodeCompareBranch(Instr* instr) { |
984 | if (instr->IsExceptionGenOp()) { |
985 | DecodeExceptionGen(instr); |
986 | } else if (instr->IsSystemOp()) { |
987 | DecodeSystem(instr); |
988 | } else if (instr->IsUnconditionalBranchRegOp()) { |
989 | DecodeUnconditionalBranchReg(instr); |
990 | } else if (instr->IsCompareAndBranchOp()) { |
991 | DecodeCompareAndBranch(instr); |
992 | } else if (instr->IsConditionalBranchOp()) { |
993 | DecodeConditionalBranch(instr); |
994 | } else if (instr->IsTestAndBranchOp()) { |
995 | DecodeTestAndBranch(instr); |
996 | } else if (instr->IsUnconditionalBranchOp()) { |
997 | DecodeUnconditionalBranch(instr); |
998 | } else { |
999 | Unknown(instr); |
1000 | } |
1001 | } |
1002 | |
1003 | void ARM64Decoder::DecodeLoadStore(Instr* instr) { |
1004 | if (instr->IsLoadStoreRegOp()) { |
1005 | DecodeLoadStoreReg(instr); |
1006 | } else if (instr->IsLoadStoreRegPairOp()) { |
1007 | DecodeLoadStoreRegPair(instr); |
1008 | } else if (instr->IsLoadRegLiteralOp()) { |
1009 | DecodeLoadRegLiteral(instr); |
1010 | } else if (instr->IsLoadStoreExclusiveOp()) { |
1011 | DecodeLoadStoreExclusive(instr); |
1012 | } else { |
1013 | Unknown(instr); |
1014 | } |
1015 | } |
1016 | |
1017 | void ARM64Decoder::DecodeAddSubShiftExt(Instr* instr) { |
1018 | switch (instr->Bit(30)) { |
1019 | case 0: { |
1020 | if ((instr->RdField() == R31) && (instr->SFField())) { |
1021 | Format(instr, "cmn'sf 'rn, 'shift_op" ); |
1022 | } else { |
1023 | Format(instr, "add'sf's 'rd, 'rn, 'shift_op" ); |
1024 | } |
1025 | break; |
1026 | } |
1027 | case 1: { |
1028 | if ((instr->RdField() == R31) && (instr->SFField())) { |
1029 | Format(instr, "cmp'sf 'rn, 'shift_op" ); |
1030 | } else { |
1031 | Format(instr, "sub'sf's 'rd, 'rn, 'shift_op" ); |
1032 | } |
1033 | break; |
1034 | } |
1035 | default: |
1036 | UNREACHABLE(); |
1037 | break; |
1038 | } |
1039 | } |
1040 | |
1041 | void ARM64Decoder::DecodeAddSubWithCarry(Instr* instr) { |
1042 | switch (instr->Bit(30)) { |
1043 | case 0: { |
1044 | Format(instr, "adc'sf's 'rd, 'rn, 'rm" ); |
1045 | break; |
1046 | } |
1047 | case 1: { |
1048 | Format(instr, "sbc'sf's 'rd, 'rn, 'rm" ); |
1049 | break; |
1050 | } |
1051 | default: |
1052 | UNREACHABLE(); |
1053 | break; |
1054 | } |
1055 | } |
1056 | |
1057 | void ARM64Decoder::DecodeLogicalShift(Instr* instr) { |
1058 | const int op = (instr->Bits(29, 2) << 1) | instr->Bit(21); |
1059 | switch (op) { |
1060 | case 0: |
1061 | Format(instr, "and'sf 'rd, 'rn, 'shift_op" ); |
1062 | break; |
1063 | case 1: |
1064 | Format(instr, "bic'sf 'rd, 'rn, 'shift_op" ); |
1065 | break; |
1066 | case 2: { |
1067 | if ((instr->RnField() == R31) && (instr->IsShift()) && |
1068 | (instr->ShiftTypeField() == LSL)) { |
1069 | if (instr->ShiftAmountField() == 0) { |
1070 | Format(instr, "mov'sf 'rd, 'rm" ); |
1071 | } else { |
1072 | Format(instr, "lsl'sf 'rd, 'rm, 'imms" ); |
1073 | } |
1074 | } else { |
1075 | Format(instr, "orr'sf 'rd, 'rn, 'shift_op" ); |
1076 | } |
1077 | break; |
1078 | } |
1079 | case 3: |
1080 | Format(instr, "orn'sf 'rd, 'rn, 'shift_op" ); |
1081 | break; |
1082 | case 4: |
1083 | Format(instr, "eor'sf 'rd, 'rn, 'shift_op" ); |
1084 | break; |
1085 | case 5: |
1086 | Format(instr, "eon'sf 'rd, 'rn, 'shift_op" ); |
1087 | break; |
1088 | case 6: |
1089 | Format(instr, "and'sfs 'rd, 'rn, 'shift_op" ); |
1090 | break; |
1091 | case 7: |
1092 | Format(instr, "bic'sfs 'rd, 'rn, 'shift_op" ); |
1093 | break; |
1094 | default: |
1095 | UNREACHABLE(); |
1096 | break; |
1097 | } |
1098 | } |
1099 | |
1100 | void ARM64Decoder::DecodeMiscDP1Source(Instr* instr) { |
1101 | if (instr->Bit(29) != 0) { |
1102 | Unknown(instr); |
1103 | } |
1104 | |
1105 | const int op = instr->Bits(10, 10); |
1106 | switch (op) { |
1107 | case 4: |
1108 | Format(instr, "clz'sf 'rd, 'rn" ); |
1109 | break; |
1110 | default: |
1111 | Unknown(instr); |
1112 | break; |
1113 | } |
1114 | } |
1115 | |
1116 | void ARM64Decoder::DecodeMiscDP2Source(Instr* instr) { |
1117 | if (instr->Bit(29) != 0) { |
1118 | Unknown(instr); |
1119 | } |
1120 | |
1121 | const int op = instr->Bits(10, 5); |
1122 | switch (op) { |
1123 | case 2: |
1124 | Format(instr, "udiv'sf 'rd, 'rn, 'rm" ); |
1125 | break; |
1126 | case 3: |
1127 | Format(instr, "sdiv'sf 'rd, 'rn, 'rm" ); |
1128 | break; |
1129 | case 8: |
1130 | Format(instr, "lsl'sf 'rd, 'rn, 'rm" ); |
1131 | break; |
1132 | case 9: |
1133 | Format(instr, "lsr'sf 'rd, 'rn, 'rm" ); |
1134 | break; |
1135 | case 10: |
1136 | Format(instr, "asr'sf 'rd, 'rn, 'rm" ); |
1137 | break; |
1138 | default: |
1139 | Unknown(instr); |
1140 | break; |
1141 | } |
1142 | } |
1143 | |
1144 | void ARM64Decoder::DecodeMiscDP3Source(Instr* instr) { |
1145 | bool zero_operand = instr->RaField() == R31; |
1146 | int32_t mask = B31 | B30 | B29 | B23 | B22 | B21 | B15 | MiscDP3SourceMask; |
1147 | int32_t bits = instr->InstructionBits() & mask; |
1148 | |
1149 | if (bits == MADD || bits == MADDW) { |
1150 | if (zero_operand) { |
1151 | Format(instr, "mul'sf 'rd, 'rn, 'rm" ); |
1152 | } else { |
1153 | Format(instr, "madd'sf 'rd, 'rn, 'rm, 'ra" ); |
1154 | } |
1155 | } else if (bits == MSUB || bits == MSUBW) { |
1156 | if (zero_operand) { |
1157 | Format(instr, "mneg'sf 'rd, 'rn, 'rm" ); |
1158 | } else { |
1159 | Format(instr, "msub'sf 'rd, 'rn, 'rm, 'ra" ); |
1160 | } |
1161 | } else if (bits == SMULH) { |
1162 | Format(instr, "smulh 'rd, 'rn, 'rm" ); |
1163 | } else if (bits == UMULH) { |
1164 | Format(instr, "umulh 'rd, 'rn, 'rm" ); |
1165 | } else if (bits == UMADDL) { |
1166 | if (zero_operand) { |
1167 | Format(instr, "umull 'rd, 'rn, 'rm" ); |
1168 | } else { |
1169 | Format(instr, "umaddl 'rd, 'rn, 'rm, 'ra" ); |
1170 | } |
1171 | } else if (bits == SMADDL) { |
1172 | if (zero_operand) { |
1173 | Format(instr, "smull 'rd, 'rn, 'rm" ); |
1174 | } else { |
1175 | Format(instr, "smaddl 'rd, 'rn, 'rm, 'ra" ); |
1176 | } |
1177 | } else if (bits == SMSUBL) { |
1178 | if (zero_operand) { |
1179 | Format(instr, "smnegl 'rd, 'rn, 'rm" ); |
1180 | } else { |
1181 | Format(instr, "smsubl 'rd, 'rn, 'rm, 'ra" ); |
1182 | } |
1183 | } else if (bits == UMSUBL) { |
1184 | if (zero_operand) { |
1185 | Format(instr, "umnegl 'rd, 'rn, 'rm" ); |
1186 | } else { |
1187 | Format(instr, "umsubl 'rd, 'rn, 'rm, 'ra" ); |
1188 | } |
1189 | } else { |
1190 | Unknown(instr); |
1191 | } |
1192 | } |
1193 | |
1194 | void ARM64Decoder::DecodeConditionalSelect(Instr* instr) { |
1195 | int cond = instr->SelectConditionField(); |
1196 | bool non_select = |
1197 | (instr->RnField() == instr->RmField()) && ((cond & 0xe) != 0xe); |
1198 | if ((instr->Bits(29, 2) == 0) && (instr->Bits(10, 2) == 0)) { |
1199 | Format(instr, "mov'sf'cond 'rd, 'rn, 'rm" ); |
1200 | } else if ((instr->Bits(29, 2) == 0) && (instr->Bits(10, 2) == 1)) { |
1201 | if (non_select) { |
1202 | Format(instr, "csinc'sf'cond 'rd, 'rn, 'rm" ); |
1203 | } else { |
1204 | Format(instr, "cinc'sf'condinverted 'rd, 'rn" ); |
1205 | } |
1206 | } else if ((instr->Bits(29, 2) == 2) && (instr->Bits(10, 2) == 0)) { |
1207 | if (non_select) { |
1208 | Format(instr, "cinv'sf'condinverted 'rd, 'rn" ); |
1209 | } else { |
1210 | Format(instr, "csinv'sf'cond 'rd, 'rn, 'rm" ); |
1211 | } |
1212 | } else if ((instr->Bits(29, 2) == 2) && (instr->Bits(10, 2) == 1)) { |
1213 | if (non_select) { |
1214 | Format(instr, "cneg'sf'condinverted 'rd, 'rn" ); |
1215 | } else { |
1216 | Format(instr, "csneg'sf'cond 'rd, 'rn, 'rm" ); |
1217 | } |
1218 | } else { |
1219 | Unknown(instr); |
1220 | } |
1221 | } |
1222 | |
1223 | void ARM64Decoder::DecodeDPRegister(Instr* instr) { |
1224 | if (instr->IsAddSubShiftExtOp()) { |
1225 | DecodeAddSubShiftExt(instr); |
1226 | } else if (instr->IsAddSubWithCarryOp()) { |
1227 | DecodeAddSubWithCarry(instr); |
1228 | } else if (instr->IsLogicalShiftOp()) { |
1229 | DecodeLogicalShift(instr); |
1230 | } else if (instr->IsMiscDP1SourceOp()) { |
1231 | DecodeMiscDP1Source(instr); |
1232 | } else if (instr->IsMiscDP2SourceOp()) { |
1233 | DecodeMiscDP2Source(instr); |
1234 | } else if (instr->IsMiscDP3SourceOp()) { |
1235 | DecodeMiscDP3Source(instr); |
1236 | } else if (instr->IsConditionalSelectOp()) { |
1237 | DecodeConditionalSelect(instr); |
1238 | } else { |
1239 | Unknown(instr); |
1240 | } |
1241 | } |
1242 | |
1243 | void ARM64Decoder::DecodeSIMDCopy(Instr* instr) { |
1244 | const int32_t Q = instr->Bit(30); |
1245 | const int32_t op = instr->Bit(29); |
1246 | const int32_t imm4 = instr->Bits(11, 4); |
1247 | |
1248 | if ((op == 0) && (imm4 == 7)) { |
1249 | if (Q == 0) { |
1250 | Format(instr, "vmovrs 'rd, 'vn'idx5" ); |
1251 | } else { |
1252 | Format(instr, "vmovrd 'rd, 'vn'idx5" ); |
1253 | } |
1254 | } else if ((Q == 1) && (op == 0) && (imm4 == 0)) { |
1255 | Format(instr, "vdup'csz 'vd, 'vn'idx5" ); |
1256 | } else if ((Q == 1) && (op == 0) && (imm4 == 3)) { |
1257 | Format(instr, "vins'csz 'vd'idx5, 'rn" ); |
1258 | } else if ((Q == 1) && (op == 0) && (imm4 == 1)) { |
1259 | Format(instr, "vdup'csz 'vd, 'rn" ); |
1260 | } else if ((Q == 1) && (op == 1)) { |
1261 | Format(instr, "vins'csz 'vd'idx5, 'vn'idx4" ); |
1262 | } else { |
1263 | Unknown(instr); |
1264 | } |
1265 | } |
1266 | |
1267 | void ARM64Decoder::DecodeSIMDThreeSame(Instr* instr) { |
1268 | const int32_t Q = instr->Bit(30); |
1269 | const int32_t U = instr->Bit(29); |
1270 | const int32_t opcode = instr->Bits(11, 5); |
1271 | |
1272 | if (Q == 0) { |
1273 | Unknown(instr); |
1274 | return; |
1275 | } |
1276 | |
1277 | if ((U == 0) && (opcode == 0x3)) { |
1278 | if (instr->Bit(23) == 0) { |
1279 | Format(instr, "vand 'vd, 'vn, 'vm" ); |
1280 | } else { |
1281 | Format(instr, "vorr 'vd, 'vn, 'vm" ); |
1282 | } |
1283 | } else if ((U == 1) && (opcode == 0x3)) { |
1284 | Format(instr, "veor 'vd, 'vn, 'vm" ); |
1285 | } else if ((U == 0) && (opcode == 0x10)) { |
1286 | Format(instr, "vadd'vsz 'vd, 'vn, 'vm" ); |
1287 | } else if ((U == 1) && (opcode == 0x10)) { |
1288 | Format(instr, "vsub'vsz 'vd, 'vn, 'vm" ); |
1289 | } else if ((U == 0) && (opcode == 0x1a)) { |
1290 | if (instr->Bit(23) == 0) { |
1291 | Format(instr, "vadd'vsz 'vd, 'vn, 'vm" ); |
1292 | } else { |
1293 | Format(instr, "vsub'vsz 'vd, 'vn, 'vm" ); |
1294 | } |
1295 | } else if ((U == 1) && (opcode == 0x1b)) { |
1296 | Format(instr, "vmul'vsz 'vd, 'vn, 'vm" ); |
1297 | } else if ((U == 1) && (opcode == 0x1f)) { |
1298 | Format(instr, "vdiv'vsz 'vd, 'vn, 'vm" ); |
1299 | } else if ((U == 0) && (opcode == 0x1c)) { |
1300 | Format(instr, "vceq'vsz 'vd, 'vn, 'vm" ); |
1301 | } else if ((U == 1) && (opcode == 0x1c)) { |
1302 | if (instr->Bit(23) == 1) { |
1303 | Format(instr, "vcgt'vsz 'vd, 'vn, 'vm" ); |
1304 | } else { |
1305 | Format(instr, "vcge'vsz 'vd, 'vn, 'vm" ); |
1306 | } |
1307 | } else if ((U == 0) && (opcode == 0x1e)) { |
1308 | if (instr->Bit(23) == 1) { |
1309 | Format(instr, "vmin'vsz 'vd, 'vn, 'vm" ); |
1310 | } else { |
1311 | Format(instr, "vmax'vsz 'vd, 'vn, 'vm" ); |
1312 | } |
1313 | } else if ((U == 0) && (opcode == 0x1f)) { |
1314 | if (instr->Bit(23) == 1) { |
1315 | Format(instr, "vrsqrt'vsz 'vd, 'vn, 'vm" ); |
1316 | } else { |
1317 | Format(instr, "vrecps'vsz 'vd, 'vn, 'vm" ); |
1318 | } |
1319 | } else { |
1320 | Unknown(instr); |
1321 | } |
1322 | } |
1323 | |
1324 | void ARM64Decoder::DecodeSIMDTwoReg(Instr* instr) { |
1325 | const int32_t Q = instr->Bit(30); |
1326 | const int32_t U = instr->Bit(29); |
1327 | const int32_t op = instr->Bits(12, 5); |
1328 | const int32_t sz = instr->Bits(22, 2); |
1329 | |
1330 | if (Q == 0) { |
1331 | Unknown(instr); |
1332 | return; |
1333 | } |
1334 | |
1335 | if ((U == 1) && (op == 0x5)) { |
1336 | Format(instr, "vnot 'vd, 'vn" ); |
1337 | } else if ((U == 0) && (op == 0xf)) { |
1338 | if (sz == 2) { |
1339 | Format(instr, "vabss 'vd, 'vn" ); |
1340 | } else if (sz == 3) { |
1341 | Format(instr, "vabsd 'vd, 'vn" ); |
1342 | } else { |
1343 | Unknown(instr); |
1344 | } |
1345 | } else if ((U == 1) && (op == 0xf)) { |
1346 | if (sz == 2) { |
1347 | Format(instr, "vnegs 'vd, 'vn" ); |
1348 | } else if (sz == 3) { |
1349 | Format(instr, "vnegd 'vd, 'vn" ); |
1350 | } else { |
1351 | Unknown(instr); |
1352 | } |
1353 | } else if ((U == 1) && (op == 0x1f)) { |
1354 | if (sz == 2) { |
1355 | Format(instr, "vsqrts 'vd, 'vn" ); |
1356 | } else if (sz == 3) { |
1357 | Format(instr, "vsqrtd 'vd, 'vn" ); |
1358 | } else { |
1359 | Unknown(instr); |
1360 | } |
1361 | } else if ((U == 0) && (op == 0x1d)) { |
1362 | if (sz != 2) { |
1363 | Unknown(instr); |
1364 | return; |
1365 | } |
1366 | Format(instr, "vrecpes 'vd, 'vn" ); |
1367 | } else if ((U == 1) && (op == 0x1d)) { |
1368 | if (sz != 2) { |
1369 | Unknown(instr); |
1370 | return; |
1371 | } |
1372 | Format(instr, "vrsqrtes 'vd, 'vn" ); |
1373 | } else { |
1374 | Unknown(instr); |
1375 | } |
1376 | } |
1377 | |
1378 | void ARM64Decoder::DecodeDPSimd1(Instr* instr) { |
1379 | if (instr->IsSIMDCopyOp()) { |
1380 | DecodeSIMDCopy(instr); |
1381 | } else if (instr->IsSIMDThreeSameOp()) { |
1382 | DecodeSIMDThreeSame(instr); |
1383 | } else if (instr->IsSIMDTwoRegOp()) { |
1384 | DecodeSIMDTwoReg(instr); |
1385 | } else { |
1386 | Unknown(instr); |
1387 | } |
1388 | } |
1389 | |
1390 | void ARM64Decoder::DecodeFPImm(Instr* instr) { |
1391 | if ((instr->Bit(31) != 0) || (instr->Bit(29) != 0) || (instr->Bit(23) != 0) || |
1392 | (instr->Bits(5, 5) != 0)) { |
1393 | Unknown(instr); |
1394 | return; |
1395 | } |
1396 | if (instr->Bit(22) == 1) { |
1397 | // Double. |
1398 | Format(instr, "fmovd 'vd, 'immd" ); |
1399 | } else { |
1400 | // Single. |
1401 | Unknown(instr); |
1402 | } |
1403 | } |
1404 | |
1405 | void ARM64Decoder::DecodeFPIntCvt(Instr* instr) { |
1406 | if ((instr->Bit(29) != 0)) { |
1407 | Unknown(instr); |
1408 | return; |
1409 | } |
1410 | |
1411 | if ((instr->SFField() == 0) && (instr->Bits(22, 2) == 0)) { |
1412 | if (instr->Bits(16, 5) == 6) { |
1413 | Format(instr, "fmovrs'sf 'rd, 'vn" ); |
1414 | } else if (instr->Bits(16, 5) == 7) { |
1415 | Format(instr, "fmovsr'sf 'vd, 'rn" ); |
1416 | } else { |
1417 | Unknown(instr); |
1418 | } |
1419 | } else if (instr->Bits(22, 2) == 1) { |
1420 | if (instr->Bits(16, 5) == 2) { |
1421 | Format(instr, "scvtfd'sf 'vd, 'rn" ); |
1422 | } else if (instr->Bits(16, 5) == 6) { |
1423 | Format(instr, "fmovrd'sf 'rd, 'vn" ); |
1424 | } else if (instr->Bits(16, 5) == 7) { |
1425 | Format(instr, "fmovdr'sf 'vd, 'rn" ); |
1426 | } else if (instr->Bits(16, 5) == 24) { |
1427 | Format(instr, "fcvtzds'sf 'rd, 'vn" ); |
1428 | } else { |
1429 | Unknown(instr); |
1430 | } |
1431 | } else { |
1432 | Unknown(instr); |
1433 | } |
1434 | } |
1435 | |
1436 | void ARM64Decoder::DecodeFPOneSource(Instr* instr) { |
1437 | const int opc = instr->Bits(15, 6); |
1438 | |
1439 | if ((opc != 5) && (instr->Bit(22) != 1)) { |
1440 | // Source is interpreted as single-precision only if we're doing a |
1441 | // conversion from single -> double. |
1442 | Unknown(instr); |
1443 | return; |
1444 | } |
1445 | |
1446 | switch (opc) { |
1447 | case 0: |
1448 | Format(instr, "fmovdd 'vd, 'vn" ); |
1449 | break; |
1450 | case 1: |
1451 | Format(instr, "fabsd 'vd, 'vn" ); |
1452 | break; |
1453 | case 2: |
1454 | Format(instr, "fnegd 'vd, 'vn" ); |
1455 | break; |
1456 | case 3: |
1457 | Format(instr, "fsqrtd 'vd, 'vn" ); |
1458 | break; |
1459 | case 4: |
1460 | Format(instr, "fcvtsd 'vd, 'vn" ); |
1461 | break; |
1462 | case 5: |
1463 | Format(instr, "fcvtds 'vd, 'vn" ); |
1464 | break; |
1465 | default: |
1466 | Unknown(instr); |
1467 | break; |
1468 | } |
1469 | } |
1470 | |
1471 | void ARM64Decoder::DecodeFPTwoSource(Instr* instr) { |
1472 | if (instr->Bits(22, 2) != 1) { |
1473 | Unknown(instr); |
1474 | return; |
1475 | } |
1476 | const int opc = instr->Bits(12, 4); |
1477 | |
1478 | switch (opc) { |
1479 | case 0: |
1480 | Format(instr, "fmuld 'vd, 'vn, 'vm" ); |
1481 | break; |
1482 | case 1: |
1483 | Format(instr, "fdivd 'vd, 'vn, 'vm" ); |
1484 | break; |
1485 | case 2: |
1486 | Format(instr, "faddd 'vd, 'vn, 'vm" ); |
1487 | break; |
1488 | case 3: |
1489 | Format(instr, "fsubd 'vd, 'vn, 'vm" ); |
1490 | break; |
1491 | default: |
1492 | Unknown(instr); |
1493 | break; |
1494 | } |
1495 | } |
1496 | |
1497 | void ARM64Decoder::DecodeFPCompare(Instr* instr) { |
1498 | if ((instr->Bit(22) == 1) && (instr->Bits(3, 2) == 0)) { |
1499 | Format(instr, "fcmpd 'vn, 'vm" ); |
1500 | } else if ((instr->Bit(22) == 1) && (instr->Bits(3, 2) == 1)) { |
1501 | if (instr->VmField() == V0) { |
1502 | Format(instr, "fcmpd 'vn, #0.0" ); |
1503 | } else { |
1504 | Unknown(instr); |
1505 | } |
1506 | } else { |
1507 | Unknown(instr); |
1508 | } |
1509 | } |
1510 | |
1511 | void ARM64Decoder::DecodeFP(Instr* instr) { |
1512 | if (instr->IsFPImmOp()) { |
1513 | DecodeFPImm(instr); |
1514 | } else if (instr->IsFPIntCvtOp()) { |
1515 | DecodeFPIntCvt(instr); |
1516 | } else if (instr->IsFPOneSourceOp()) { |
1517 | DecodeFPOneSource(instr); |
1518 | } else if (instr->IsFPTwoSourceOp()) { |
1519 | DecodeFPTwoSource(instr); |
1520 | } else if (instr->IsFPCompareOp()) { |
1521 | DecodeFPCompare(instr); |
1522 | } else { |
1523 | Unknown(instr); |
1524 | } |
1525 | } |
1526 | |
1527 | void ARM64Decoder::DecodeDPSimd2(Instr* instr) { |
1528 | if (instr->IsFPOp()) { |
1529 | DecodeFP(instr); |
1530 | } else { |
1531 | Unknown(instr); |
1532 | } |
1533 | } |
1534 | |
1535 | void ARM64Decoder::InstructionDecode(uword pc) { |
1536 | Instr* instr = Instr::At(pc); |
1537 | |
1538 | if (instr->IsDPImmediateOp()) { |
1539 | DecodeDPImmediate(instr); |
1540 | } else if (instr->IsCompareBranchOp()) { |
1541 | DecodeCompareBranch(instr); |
1542 | } else if (instr->IsLoadStoreOp()) { |
1543 | DecodeLoadStore(instr); |
1544 | } else if (instr->IsDPRegisterOp()) { |
1545 | DecodeDPRegister(instr); |
1546 | } else if (instr->IsDPSimd1Op()) { |
1547 | DecodeDPSimd1(instr); |
1548 | } else if (instr->IsDPSimd2Op()) { |
1549 | DecodeDPSimd2(instr); |
1550 | } else { |
1551 | Unknown(instr); |
1552 | } |
1553 | } |
1554 | |
1555 | void Disassembler::DecodeInstruction(char* hex_buffer, |
1556 | intptr_t hex_size, |
1557 | char* human_buffer, |
1558 | intptr_t human_size, |
1559 | int* out_instr_size, |
1560 | const Code& code, |
1561 | Object** object, |
1562 | uword pc) { |
1563 | ARM64Decoder decoder(human_buffer, human_size); |
1564 | decoder.InstructionDecode(pc); |
1565 | int32_t instruction_bits = Instr::At(pc)->InstructionBits(); |
1566 | Utils::SNPrint(hex_buffer, hex_size, "%08x" , instruction_bits); |
1567 | if (out_instr_size) { |
1568 | *out_instr_size = Instr::kInstrSize; |
1569 | } |
1570 | |
1571 | *object = NULL; |
1572 | if (!code.IsNull()) { |
1573 | *object = &Object::Handle(); |
1574 | if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { |
1575 | *object = NULL; |
1576 | } |
1577 | } |
1578 | } |
1579 | |
1580 | #endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) |
1581 | |
1582 | } // namespace dart |
1583 | |
1584 | #endif // defined(TARGET_ARCH_ARM64) |
1585 | |