blob: 8e022b1690f6e1efe86b344ee4e654e37aeeea8e [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <assert.h>
6#include <stdarg.h>
7#include <stdio.h>
8#include <string.h>
9
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#if V8_TARGET_ARCH_ARM64
11
12#include "src/arm64/decoder-arm64-inl.h"
13#include "src/arm64/disasm-arm64.h"
14#include "src/base/platform/platform.h"
15#include "src/disasm.h"
16#include "src/macro-assembler.h"
17
18namespace v8 {
19namespace internal {
20
21
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022DisassemblingDecoder::DisassemblingDecoder() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023 buffer_size_ = 256;
24 buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
25 buffer_pos_ = 0;
26 own_buffer_ = true;
27}
28
29
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030DisassemblingDecoder::DisassemblingDecoder(char* text_buffer, int buffer_size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 buffer_size_ = buffer_size;
32 buffer_ = text_buffer;
33 buffer_pos_ = 0;
34 own_buffer_ = false;
35}
36
37
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000038DisassemblingDecoder::~DisassemblingDecoder() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039 if (own_buffer_) {
40 free(buffer_);
41 }
42}
43
44
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045char* DisassemblingDecoder::GetOutput() { return buffer_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046
47
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000048void DisassemblingDecoder::VisitAddSubImmediate(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049 bool rd_is_zr = RdIsZROrSP(instr);
50 bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
51 (instr->ImmAddSub() == 0) ? true : false;
52 const char *mnemonic = "";
53 const char *form = "'Rds, 'Rns, 'IAddSub";
54 const char *form_cmp = "'Rns, 'IAddSub";
55 const char *form_mov = "'Rds, 'Rns";
56
57 switch (instr->Mask(AddSubImmediateMask)) {
58 case ADD_w_imm:
59 case ADD_x_imm: {
60 mnemonic = "add";
61 if (stack_op) {
62 mnemonic = "mov";
63 form = form_mov;
64 }
65 break;
66 }
67 case ADDS_w_imm:
68 case ADDS_x_imm: {
69 mnemonic = "adds";
70 if (rd_is_zr) {
71 mnemonic = "cmn";
72 form = form_cmp;
73 }
74 break;
75 }
76 case SUB_w_imm:
77 case SUB_x_imm: mnemonic = "sub"; break;
78 case SUBS_w_imm:
79 case SUBS_x_imm: {
80 mnemonic = "subs";
81 if (rd_is_zr) {
82 mnemonic = "cmp";
83 form = form_cmp;
84 }
85 break;
86 }
87 default: UNREACHABLE();
88 }
89 Format(instr, mnemonic, form);
90}
91
92
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000093void DisassemblingDecoder::VisitAddSubShifted(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000094 bool rd_is_zr = RdIsZROrSP(instr);
95 bool rn_is_zr = RnIsZROrSP(instr);
96 const char *mnemonic = "";
97 const char *form = "'Rd, 'Rn, 'Rm'HDP";
98 const char *form_cmp = "'Rn, 'Rm'HDP";
99 const char *form_neg = "'Rd, 'Rm'HDP";
100
101 switch (instr->Mask(AddSubShiftedMask)) {
102 case ADD_w_shift:
103 case ADD_x_shift: mnemonic = "add"; break;
104 case ADDS_w_shift:
105 case ADDS_x_shift: {
106 mnemonic = "adds";
107 if (rd_is_zr) {
108 mnemonic = "cmn";
109 form = form_cmp;
110 }
111 break;
112 }
113 case SUB_w_shift:
114 case SUB_x_shift: {
115 mnemonic = "sub";
116 if (rn_is_zr) {
117 mnemonic = "neg";
118 form = form_neg;
119 }
120 break;
121 }
122 case SUBS_w_shift:
123 case SUBS_x_shift: {
124 mnemonic = "subs";
125 if (rd_is_zr) {
126 mnemonic = "cmp";
127 form = form_cmp;
128 } else if (rn_is_zr) {
129 mnemonic = "negs";
130 form = form_neg;
131 }
132 break;
133 }
134 default: UNREACHABLE();
135 }
136 Format(instr, mnemonic, form);
137}
138
139
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140void DisassemblingDecoder::VisitAddSubExtended(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 bool rd_is_zr = RdIsZROrSP(instr);
142 const char *mnemonic = "";
143 Extend mode = static_cast<Extend>(instr->ExtendMode());
144 const char *form = ((mode == UXTX) || (mode == SXTX)) ?
145 "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
146 const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
147 "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
148
149 switch (instr->Mask(AddSubExtendedMask)) {
150 case ADD_w_ext:
151 case ADD_x_ext: mnemonic = "add"; break;
152 case ADDS_w_ext:
153 case ADDS_x_ext: {
154 mnemonic = "adds";
155 if (rd_is_zr) {
156 mnemonic = "cmn";
157 form = form_cmp;
158 }
159 break;
160 }
161 case SUB_w_ext:
162 case SUB_x_ext: mnemonic = "sub"; break;
163 case SUBS_w_ext:
164 case SUBS_x_ext: {
165 mnemonic = "subs";
166 if (rd_is_zr) {
167 mnemonic = "cmp";
168 form = form_cmp;
169 }
170 break;
171 }
172 default: UNREACHABLE();
173 }
174 Format(instr, mnemonic, form);
175}
176
177
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000178void DisassemblingDecoder::VisitAddSubWithCarry(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179 bool rn_is_zr = RnIsZROrSP(instr);
180 const char *mnemonic = "";
181 const char *form = "'Rd, 'Rn, 'Rm";
182 const char *form_neg = "'Rd, 'Rm";
183
184 switch (instr->Mask(AddSubWithCarryMask)) {
185 case ADC_w:
186 case ADC_x: mnemonic = "adc"; break;
187 case ADCS_w:
188 case ADCS_x: mnemonic = "adcs"; break;
189 case SBC_w:
190 case SBC_x: {
191 mnemonic = "sbc";
192 if (rn_is_zr) {
193 mnemonic = "ngc";
194 form = form_neg;
195 }
196 break;
197 }
198 case SBCS_w:
199 case SBCS_x: {
200 mnemonic = "sbcs";
201 if (rn_is_zr) {
202 mnemonic = "ngcs";
203 form = form_neg;
204 }
205 break;
206 }
207 default: UNREACHABLE();
208 }
209 Format(instr, mnemonic, form);
210}
211
212
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213void DisassemblingDecoder::VisitLogicalImmediate(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 bool rd_is_zr = RdIsZROrSP(instr);
215 bool rn_is_zr = RnIsZROrSP(instr);
216 const char *mnemonic = "";
217 const char *form = "'Rds, 'Rn, 'ITri";
218
219 if (instr->ImmLogical() == 0) {
220 // The immediate encoded in the instruction is not in the expected format.
221 Format(instr, "unallocated", "(LogicalImmediate)");
222 return;
223 }
224
225 switch (instr->Mask(LogicalImmediateMask)) {
226 case AND_w_imm:
227 case AND_x_imm: mnemonic = "and"; break;
228 case ORR_w_imm:
229 case ORR_x_imm: {
230 mnemonic = "orr";
231 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
232 : kWRegSizeInBits;
233 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
234 mnemonic = "mov";
235 form = "'Rds, 'ITri";
236 }
237 break;
238 }
239 case EOR_w_imm:
240 case EOR_x_imm: mnemonic = "eor"; break;
241 case ANDS_w_imm:
242 case ANDS_x_imm: {
243 mnemonic = "ands";
244 if (rd_is_zr) {
245 mnemonic = "tst";
246 form = "'Rn, 'ITri";
247 }
248 break;
249 }
250 default: UNREACHABLE();
251 }
252 Format(instr, mnemonic, form);
253}
254
255
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256bool DisassemblingDecoder::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257 DCHECK((reg_size == kXRegSizeInBits) ||
258 ((reg_size == kWRegSizeInBits) && (value <= 0xffffffff)));
259
260 // Test for movz: 16-bits set at positions 0, 16, 32 or 48.
261 if (((value & 0xffffffffffff0000UL) == 0UL) ||
262 ((value & 0xffffffff0000ffffUL) == 0UL) ||
263 ((value & 0xffff0000ffffffffUL) == 0UL) ||
264 ((value & 0x0000ffffffffffffUL) == 0UL)) {
265 return true;
266 }
267
268 // Test for movn: NOT(16-bits set at positions 0, 16, 32 or 48).
269 if ((reg_size == kXRegSizeInBits) &&
270 (((value & 0xffffffffffff0000UL) == 0xffffffffffff0000UL) ||
271 ((value & 0xffffffff0000ffffUL) == 0xffffffff0000ffffUL) ||
272 ((value & 0xffff0000ffffffffUL) == 0xffff0000ffffffffUL) ||
273 ((value & 0x0000ffffffffffffUL) == 0x0000ffffffffffffUL))) {
274 return true;
275 }
276 if ((reg_size == kWRegSizeInBits) &&
277 (((value & 0xffff0000) == 0xffff0000) ||
278 ((value & 0x0000ffff) == 0x0000ffff))) {
279 return true;
280 }
281 return false;
282}
283
284
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285void DisassemblingDecoder::VisitLogicalShifted(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 bool rd_is_zr = RdIsZROrSP(instr);
287 bool rn_is_zr = RnIsZROrSP(instr);
288 const char *mnemonic = "";
289 const char *form = "'Rd, 'Rn, 'Rm'HLo";
290
291 switch (instr->Mask(LogicalShiftedMask)) {
292 case AND_w:
293 case AND_x: mnemonic = "and"; break;
294 case BIC_w:
295 case BIC_x: mnemonic = "bic"; break;
296 case EOR_w:
297 case EOR_x: mnemonic = "eor"; break;
298 case EON_w:
299 case EON_x: mnemonic = "eon"; break;
300 case BICS_w:
301 case BICS_x: mnemonic = "bics"; break;
302 case ANDS_w:
303 case ANDS_x: {
304 mnemonic = "ands";
305 if (rd_is_zr) {
306 mnemonic = "tst";
307 form = "'Rn, 'Rm'HLo";
308 }
309 break;
310 }
311 case ORR_w:
312 case ORR_x: {
313 mnemonic = "orr";
314 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
315 mnemonic = "mov";
316 form = "'Rd, 'Rm";
317 }
318 break;
319 }
320 case ORN_w:
321 case ORN_x: {
322 mnemonic = "orn";
323 if (rn_is_zr) {
324 mnemonic = "mvn";
325 form = "'Rd, 'Rm'HLo";
326 }
327 break;
328 }
329 default: UNREACHABLE();
330 }
331
332 Format(instr, mnemonic, form);
333}
334
335
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336void DisassemblingDecoder::VisitConditionalCompareRegister(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337 const char *mnemonic = "";
338 const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
339
340 switch (instr->Mask(ConditionalCompareRegisterMask)) {
341 case CCMN_w:
342 case CCMN_x: mnemonic = "ccmn"; break;
343 case CCMP_w:
344 case CCMP_x: mnemonic = "ccmp"; break;
345 default: UNREACHABLE();
346 }
347 Format(instr, mnemonic, form);
348}
349
350
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351void DisassemblingDecoder::VisitConditionalCompareImmediate(
352 Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000353 const char *mnemonic = "";
354 const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
355
356 switch (instr->Mask(ConditionalCompareImmediateMask)) {
357 case CCMN_w_imm:
358 case CCMN_x_imm: mnemonic = "ccmn"; break;
359 case CCMP_w_imm:
360 case CCMP_x_imm: mnemonic = "ccmp"; break;
361 default: UNREACHABLE();
362 }
363 Format(instr, mnemonic, form);
364}
365
366
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367void DisassemblingDecoder::VisitConditionalSelect(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000368 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
369 bool rn_is_rm = (instr->Rn() == instr->Rm());
370 const char *mnemonic = "";
371 const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
372 const char *form_test = "'Rd, 'CInv";
373 const char *form_update = "'Rd, 'Rn, 'CInv";
374
375 Condition cond = static_cast<Condition>(instr->Condition());
376 bool invertible_cond = (cond != al) && (cond != nv);
377
378 switch (instr->Mask(ConditionalSelectMask)) {
379 case CSEL_w:
380 case CSEL_x: mnemonic = "csel"; break;
381 case CSINC_w:
382 case CSINC_x: {
383 mnemonic = "csinc";
384 if (rnm_is_zr && invertible_cond) {
385 mnemonic = "cset";
386 form = form_test;
387 } else if (rn_is_rm && invertible_cond) {
388 mnemonic = "cinc";
389 form = form_update;
390 }
391 break;
392 }
393 case CSINV_w:
394 case CSINV_x: {
395 mnemonic = "csinv";
396 if (rnm_is_zr && invertible_cond) {
397 mnemonic = "csetm";
398 form = form_test;
399 } else if (rn_is_rm && invertible_cond) {
400 mnemonic = "cinv";
401 form = form_update;
402 }
403 break;
404 }
405 case CSNEG_w:
406 case CSNEG_x: {
407 mnemonic = "csneg";
408 if (rn_is_rm && invertible_cond) {
409 mnemonic = "cneg";
410 form = form_update;
411 }
412 break;
413 }
414 default: UNREACHABLE();
415 }
416 Format(instr, mnemonic, form);
417}
418
419
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000420void DisassemblingDecoder::VisitBitfield(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000421 unsigned s = instr->ImmS();
422 unsigned r = instr->ImmR();
423 unsigned rd_size_minus_1 =
424 ((instr->SixtyFourBits() == 1) ? kXRegSizeInBits : kWRegSizeInBits) - 1;
425 const char *mnemonic = "";
426 const char *form = "";
427 const char *form_shift_right = "'Rd, 'Rn, 'IBr";
428 const char *form_extend = "'Rd, 'Wn";
429 const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
430 const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
431 const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
432
433 switch (instr->Mask(BitfieldMask)) {
434 case SBFM_w:
435 case SBFM_x: {
436 mnemonic = "sbfx";
437 form = form_bfx;
438 if (r == 0) {
439 form = form_extend;
440 if (s == 7) {
441 mnemonic = "sxtb";
442 } else if (s == 15) {
443 mnemonic = "sxth";
444 } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
445 mnemonic = "sxtw";
446 } else {
447 form = form_bfx;
448 }
449 } else if (s == rd_size_minus_1) {
450 mnemonic = "asr";
451 form = form_shift_right;
452 } else if (s < r) {
453 mnemonic = "sbfiz";
454 form = form_bfiz;
455 }
456 break;
457 }
458 case UBFM_w:
459 case UBFM_x: {
460 mnemonic = "ubfx";
461 form = form_bfx;
462 if (r == 0) {
463 form = form_extend;
464 if (s == 7) {
465 mnemonic = "uxtb";
466 } else if (s == 15) {
467 mnemonic = "uxth";
468 } else {
469 form = form_bfx;
470 }
471 }
472 if (s == rd_size_minus_1) {
473 mnemonic = "lsr";
474 form = form_shift_right;
475 } else if (r == s + 1) {
476 mnemonic = "lsl";
477 form = form_lsl;
478 } else if (s < r) {
479 mnemonic = "ubfiz";
480 form = form_bfiz;
481 }
482 break;
483 }
484 case BFM_w:
485 case BFM_x: {
486 mnemonic = "bfxil";
487 form = form_bfx;
488 if (s < r) {
489 mnemonic = "bfi";
490 form = form_bfiz;
491 }
492 }
493 }
494 Format(instr, mnemonic, form);
495}
496
497
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000498void DisassemblingDecoder::VisitExtract(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000499 const char *mnemonic = "";
500 const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
501
502 switch (instr->Mask(ExtractMask)) {
503 case EXTR_w:
504 case EXTR_x: {
505 if (instr->Rn() == instr->Rm()) {
506 mnemonic = "ror";
507 form = "'Rd, 'Rn, 'IExtract";
508 } else {
509 mnemonic = "extr";
510 }
511 break;
512 }
513 default: UNREACHABLE();
514 }
515 Format(instr, mnemonic, form);
516}
517
518
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000519void DisassemblingDecoder::VisitPCRelAddressing(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000520 switch (instr->Mask(PCRelAddressingMask)) {
521 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
522 // ADRP is not implemented.
523 default: Format(instr, "unimplemented", "(PCRelAddressing)");
524 }
525}
526
527
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000528void DisassemblingDecoder::VisitConditionalBranch(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 switch (instr->Mask(ConditionalBranchMask)) {
530 case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
531 default: UNREACHABLE();
532 }
533}
534
535
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000536void DisassemblingDecoder::VisitUnconditionalBranchToRegister(
537 Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000538 const char *mnemonic = "unimplemented";
539 const char *form = "'Xn";
540
541 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
542 case BR: mnemonic = "br"; break;
543 case BLR: mnemonic = "blr"; break;
544 case RET: {
545 mnemonic = "ret";
546 if (instr->Rn() == kLinkRegCode) {
547 form = NULL;
548 }
549 break;
550 }
551 default: form = "(UnconditionalBranchToRegister)";
552 }
553 Format(instr, mnemonic, form);
554}
555
556
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557void DisassemblingDecoder::VisitUnconditionalBranch(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000558 const char *mnemonic = "";
559 const char *form = "'BImmUncn";
560
561 switch (instr->Mask(UnconditionalBranchMask)) {
562 case B: mnemonic = "b"; break;
563 case BL: mnemonic = "bl"; break;
564 default: UNREACHABLE();
565 }
566 Format(instr, mnemonic, form);
567}
568
569
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000570void DisassemblingDecoder::VisitDataProcessing1Source(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000571 const char *mnemonic = "";
572 const char *form = "'Rd, 'Rn";
573
574 switch (instr->Mask(DataProcessing1SourceMask)) {
575 #define FORMAT(A, B) \
576 case A##_w: \
577 case A##_x: mnemonic = B; break;
578 FORMAT(RBIT, "rbit");
579 FORMAT(REV16, "rev16");
580 FORMAT(REV, "rev");
581 FORMAT(CLZ, "clz");
582 FORMAT(CLS, "cls");
583 #undef FORMAT
584 case REV32_x: mnemonic = "rev32"; break;
585 default: UNREACHABLE();
586 }
587 Format(instr, mnemonic, form);
588}
589
590
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000591void DisassemblingDecoder::VisitDataProcessing2Source(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000592 const char *mnemonic = "unimplemented";
593 const char *form = "'Rd, 'Rn, 'Rm";
594
595 switch (instr->Mask(DataProcessing2SourceMask)) {
596 #define FORMAT(A, B) \
597 case A##_w: \
598 case A##_x: mnemonic = B; break;
599 FORMAT(UDIV, "udiv");
600 FORMAT(SDIV, "sdiv");
601 FORMAT(LSLV, "lsl");
602 FORMAT(LSRV, "lsr");
603 FORMAT(ASRV, "asr");
604 FORMAT(RORV, "ror");
605 #undef FORMAT
606 default: form = "(DataProcessing2Source)";
607 }
608 Format(instr, mnemonic, form);
609}
610
611
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612void DisassemblingDecoder::VisitDataProcessing3Source(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 bool ra_is_zr = RaIsZROrSP(instr);
614 const char *mnemonic = "";
615 const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
616 const char *form_rrr = "'Rd, 'Rn, 'Rm";
617 const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
618 const char *form_xww = "'Xd, 'Wn, 'Wm";
619 const char *form_xxx = "'Xd, 'Xn, 'Xm";
620
621 switch (instr->Mask(DataProcessing3SourceMask)) {
622 case MADD_w:
623 case MADD_x: {
624 mnemonic = "madd";
625 form = form_rrrr;
626 if (ra_is_zr) {
627 mnemonic = "mul";
628 form = form_rrr;
629 }
630 break;
631 }
632 case MSUB_w:
633 case MSUB_x: {
634 mnemonic = "msub";
635 form = form_rrrr;
636 if (ra_is_zr) {
637 mnemonic = "mneg";
638 form = form_rrr;
639 }
640 break;
641 }
642 case SMADDL_x: {
643 mnemonic = "smaddl";
644 if (ra_is_zr) {
645 mnemonic = "smull";
646 form = form_xww;
647 }
648 break;
649 }
650 case SMSUBL_x: {
651 mnemonic = "smsubl";
652 if (ra_is_zr) {
653 mnemonic = "smnegl";
654 form = form_xww;
655 }
656 break;
657 }
658 case UMADDL_x: {
659 mnemonic = "umaddl";
660 if (ra_is_zr) {
661 mnemonic = "umull";
662 form = form_xww;
663 }
664 break;
665 }
666 case UMSUBL_x: {
667 mnemonic = "umsubl";
668 if (ra_is_zr) {
669 mnemonic = "umnegl";
670 form = form_xww;
671 }
672 break;
673 }
674 case SMULH_x: {
675 mnemonic = "smulh";
676 form = form_xxx;
677 break;
678 }
679 case UMULH_x: {
680 mnemonic = "umulh";
681 form = form_xxx;
682 break;
683 }
684 default: UNREACHABLE();
685 }
686 Format(instr, mnemonic, form);
687}
688
689
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000690void DisassemblingDecoder::VisitCompareBranch(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000691 const char *mnemonic = "";
692 const char *form = "'Rt, 'BImmCmpa";
693
694 switch (instr->Mask(CompareBranchMask)) {
695 case CBZ_w:
696 case CBZ_x: mnemonic = "cbz"; break;
697 case CBNZ_w:
698 case CBNZ_x: mnemonic = "cbnz"; break;
699 default: UNREACHABLE();
700 }
701 Format(instr, mnemonic, form);
702}
703
704
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000705void DisassemblingDecoder::VisitTestBranch(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706 const char *mnemonic = "";
707 // If the top bit of the immediate is clear, the tested register is
708 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
709 // encoded in bit 31 of the instruction, we can reuse the Rt form, which
710 // uses bit 31 (normally "sf") to choose the register size.
711 const char *form = "'Rt, 'IS, 'BImmTest";
712
713 switch (instr->Mask(TestBranchMask)) {
714 case TBZ: mnemonic = "tbz"; break;
715 case TBNZ: mnemonic = "tbnz"; break;
716 default: UNREACHABLE();
717 }
718 Format(instr, mnemonic, form);
719}
720
721
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000722void DisassemblingDecoder::VisitMoveWideImmediate(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723 const char *mnemonic = "";
724 const char *form = "'Rd, 'IMoveImm";
725
726 // Print the shift separately for movk, to make it clear which half word will
727 // be overwritten. Movn and movz print the computed immediate, which includes
728 // shift calculation.
729 switch (instr->Mask(MoveWideImmediateMask)) {
730 case MOVN_w:
731 case MOVN_x: mnemonic = "movn"; break;
732 case MOVZ_w:
733 case MOVZ_x: mnemonic = "movz"; break;
734 case MOVK_w:
735 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
736 default: UNREACHABLE();
737 }
738 Format(instr, mnemonic, form);
739}
740
741
742#define LOAD_STORE_LIST(V) \
743 V(STRB_w, "strb", "'Wt") \
744 V(STRH_w, "strh", "'Wt") \
745 V(STR_w, "str", "'Wt") \
746 V(STR_x, "str", "'Xt") \
747 V(LDRB_w, "ldrb", "'Wt") \
748 V(LDRH_w, "ldrh", "'Wt") \
749 V(LDR_w, "ldr", "'Wt") \
750 V(LDR_x, "ldr", "'Xt") \
751 V(LDRSB_x, "ldrsb", "'Xt") \
752 V(LDRSH_x, "ldrsh", "'Xt") \
753 V(LDRSW_x, "ldrsw", "'Xt") \
754 V(LDRSB_w, "ldrsb", "'Wt") \
755 V(LDRSH_w, "ldrsh", "'Wt") \
756 V(STR_s, "str", "'St") \
757 V(STR_d, "str", "'Dt") \
758 V(LDR_s, "ldr", "'St") \
759 V(LDR_d, "ldr", "'Dt")
760
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761void DisassemblingDecoder::VisitLoadStorePreIndex(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000762 const char *mnemonic = "unimplemented";
763 const char *form = "(LoadStorePreIndex)";
764
765 switch (instr->Mask(LoadStorePreIndexMask)) {
766 #define LS_PREINDEX(A, B, C) \
767 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
768 LOAD_STORE_LIST(LS_PREINDEX)
769 #undef LS_PREINDEX
770 }
771 Format(instr, mnemonic, form);
772}
773
774
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000775void DisassemblingDecoder::VisitLoadStorePostIndex(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000776 const char *mnemonic = "unimplemented";
777 const char *form = "(LoadStorePostIndex)";
778
779 switch (instr->Mask(LoadStorePostIndexMask)) {
780 #define LS_POSTINDEX(A, B, C) \
781 case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
782 LOAD_STORE_LIST(LS_POSTINDEX)
783 #undef LS_POSTINDEX
784 }
785 Format(instr, mnemonic, form);
786}
787
788
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000789void DisassemblingDecoder::VisitLoadStoreUnsignedOffset(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000790 const char *mnemonic = "unimplemented";
791 const char *form = "(LoadStoreUnsignedOffset)";
792
793 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
794 #define LS_UNSIGNEDOFFSET(A, B, C) \
795 case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
796 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
797 #undef LS_UNSIGNEDOFFSET
798 case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]";
799 }
800 Format(instr, mnemonic, form);
801}
802
803
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000804void DisassemblingDecoder::VisitLoadStoreRegisterOffset(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000805 const char *mnemonic = "unimplemented";
806 const char *form = "(LoadStoreRegisterOffset)";
807
808 switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
809 #define LS_REGISTEROFFSET(A, B, C) \
810 case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
811 LOAD_STORE_LIST(LS_REGISTEROFFSET)
812 #undef LS_REGISTEROFFSET
813 case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
814 }
815 Format(instr, mnemonic, form);
816}
817
818
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819void DisassemblingDecoder::VisitLoadStoreUnscaledOffset(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000820 const char *mnemonic = "unimplemented";
821 const char *form = "'Wt, ['Xns'ILS]";
822 const char *form_x = "'Xt, ['Xns'ILS]";
823 const char *form_s = "'St, ['Xns'ILS]";
824 const char *form_d = "'Dt, ['Xns'ILS]";
825
826 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
827 case STURB_w: mnemonic = "sturb"; break;
828 case STURH_w: mnemonic = "sturh"; break;
829 case STUR_w: mnemonic = "stur"; break;
830 case STUR_x: mnemonic = "stur"; form = form_x; break;
831 case STUR_s: mnemonic = "stur"; form = form_s; break;
832 case STUR_d: mnemonic = "stur"; form = form_d; break;
833 case LDURB_w: mnemonic = "ldurb"; break;
834 case LDURH_w: mnemonic = "ldurh"; break;
835 case LDUR_w: mnemonic = "ldur"; break;
836 case LDUR_x: mnemonic = "ldur"; form = form_x; break;
837 case LDUR_s: mnemonic = "ldur"; form = form_s; break;
838 case LDUR_d: mnemonic = "ldur"; form = form_d; break;
839 case LDURSB_x: form = form_x; // Fall through.
840 case LDURSB_w: mnemonic = "ldursb"; break;
841 case LDURSH_x: form = form_x; // Fall through.
842 case LDURSH_w: mnemonic = "ldursh"; break;
843 case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
844 default: form = "(LoadStoreUnscaledOffset)";
845 }
846 Format(instr, mnemonic, form);
847}
848
849
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000850void DisassemblingDecoder::VisitLoadLiteral(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000851 const char *mnemonic = "ldr";
852 const char *form = "(LoadLiteral)";
853
854 switch (instr->Mask(LoadLiteralMask)) {
855 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
856 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
857 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
858 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
859 default: mnemonic = "unimplemented";
860 }
861 Format(instr, mnemonic, form);
862}
863
864
865#define LOAD_STORE_PAIR_LIST(V) \
866 V(STP_w, "stp", "'Wt, 'Wt2", "4") \
867 V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \
868 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
869 V(STP_x, "stp", "'Xt, 'Xt2", "8") \
870 V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \
871 V(STP_s, "stp", "'St, 'St2", "4") \
872 V(LDP_s, "ldp", "'St, 'St2", "4") \
873 V(STP_d, "stp", "'Dt, 'Dt2", "8") \
874 V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
875
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000876void DisassemblingDecoder::VisitLoadStorePairPostIndex(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000877 const char *mnemonic = "unimplemented";
878 const char *form = "(LoadStorePairPostIndex)";
879
880 switch (instr->Mask(LoadStorePairPostIndexMask)) {
881 #define LSP_POSTINDEX(A, B, C, D) \
882 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
883 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
884 #undef LSP_POSTINDEX
885 }
886 Format(instr, mnemonic, form);
887}
888
889
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890void DisassemblingDecoder::VisitLoadStorePairPreIndex(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000891 const char *mnemonic = "unimplemented";
892 const char *form = "(LoadStorePairPreIndex)";
893
894 switch (instr->Mask(LoadStorePairPreIndexMask)) {
895 #define LSP_PREINDEX(A, B, C, D) \
896 case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
897 LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
898 #undef LSP_PREINDEX
899 }
900 Format(instr, mnemonic, form);
901}
902
903
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000904void DisassemblingDecoder::VisitLoadStorePairOffset(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000905 const char *mnemonic = "unimplemented";
906 const char *form = "(LoadStorePairOffset)";
907
908 switch (instr->Mask(LoadStorePairOffsetMask)) {
909 #define LSP_OFFSET(A, B, C, D) \
910 case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
911 LOAD_STORE_PAIR_LIST(LSP_OFFSET)
912 #undef LSP_OFFSET
913 }
914 Format(instr, mnemonic, form);
915}
916
Ben Murdoch61f157c2016-09-16 13:49:30 +0100917void DisassemblingDecoder::VisitLoadStoreAcquireRelease(Instruction *instr) {
918 const char *mnemonic = "unimplemented";
919 const char *form = "'Wt, ['Xn]";
920 const char *form_x = "'Xt, ['Xn]";
921 const char *form_stlx = "'Ws, 'Wt, ['Xn]";
922 const char *form_stlx_x = "'Ws, 'Xt, ['Xn]";
923
924 switch (instr->Mask(LoadStoreAcquireReleaseMask)) {
925 case LDAXR_b: mnemonic = "ldaxrb"; break;
926 case STLR_b: mnemonic = "stlrb"; break;
927 case LDAR_b: mnemonic = "ldarb"; break;
928 case LDAXR_h: mnemonic = "ldaxrh"; break;
929 case STLR_h: mnemonic = "stlrh"; break;
930 case LDAR_h: mnemonic = "ldarh"; break;
931 case LDAXR_w: mnemonic = "ldaxr"; break;
932 case STLR_w: mnemonic = "stlr"; break;
933 case LDAR_w: mnemonic = "ldar"; break;
934 case LDAXR_x: mnemonic = "ldaxr"; form = form_x; break;
935 case STLR_x: mnemonic = "stlr"; form = form_x; break;
936 case LDAR_x: mnemonic = "ldar"; form = form_x; break;
937 case STLXR_h: mnemonic = "stlxrh"; form = form_stlx; break;
938 case STLXR_b: mnemonic = "stlxrb"; form = form_stlx; break;
939 case STLXR_w: mnemonic = "stlxr"; form = form_stlx; break;
940 case STLXR_x: mnemonic = "stlxr"; form = form_stlx_x; break;
941 default: form = "(LoadStoreAcquireReleaseMask)";
942 }
943 Format(instr, mnemonic, form);
944}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000945
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000946void DisassemblingDecoder::VisitFPCompare(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000947 const char *mnemonic = "unimplemented";
948 const char *form = "'Fn, 'Fm";
949 const char *form_zero = "'Fn, #0.0";
950
951 switch (instr->Mask(FPCompareMask)) {
952 case FCMP_s_zero:
953 case FCMP_d_zero: form = form_zero; // Fall through.
954 case FCMP_s:
955 case FCMP_d: mnemonic = "fcmp"; break;
956 default: form = "(FPCompare)";
957 }
958 Format(instr, mnemonic, form);
959}
960
961
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000962void DisassemblingDecoder::VisitFPConditionalCompare(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963 const char *mnemonic = "unimplemented";
964 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
965
966 switch (instr->Mask(FPConditionalCompareMask)) {
967 case FCCMP_s:
968 case FCCMP_d: mnemonic = "fccmp"; break;
969 case FCCMPE_s:
970 case FCCMPE_d: mnemonic = "fccmpe"; break;
971 default: form = "(FPConditionalCompare)";
972 }
973 Format(instr, mnemonic, form);
974}
975
976
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000977void DisassemblingDecoder::VisitFPConditionalSelect(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000978 const char *mnemonic = "";
979 const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
980
981 switch (instr->Mask(FPConditionalSelectMask)) {
982 case FCSEL_s:
983 case FCSEL_d: mnemonic = "fcsel"; break;
984 default: UNREACHABLE();
985 }
986 Format(instr, mnemonic, form);
987}
988
989
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000990void DisassemblingDecoder::VisitFPDataProcessing1Source(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000991 const char *mnemonic = "unimplemented";
992 const char *form = "'Fd, 'Fn";
993
994 switch (instr->Mask(FPDataProcessing1SourceMask)) {
995 #define FORMAT(A, B) \
996 case A##_s: \
997 case A##_d: mnemonic = B; break;
998 FORMAT(FMOV, "fmov");
999 FORMAT(FABS, "fabs");
1000 FORMAT(FNEG, "fneg");
1001 FORMAT(FSQRT, "fsqrt");
1002 FORMAT(FRINTN, "frintn");
1003 FORMAT(FRINTP, "frintp");
1004 FORMAT(FRINTM, "frintm");
1005 FORMAT(FRINTZ, "frintz");
1006 FORMAT(FRINTA, "frinta");
1007 FORMAT(FRINTX, "frintx");
1008 FORMAT(FRINTI, "frinti");
1009 #undef FORMAT
1010 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
1011 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
1012 default: form = "(FPDataProcessing1Source)";
1013 }
1014 Format(instr, mnemonic, form);
1015}
1016
1017
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001018void DisassemblingDecoder::VisitFPDataProcessing2Source(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001019 const char *mnemonic = "";
1020 const char *form = "'Fd, 'Fn, 'Fm";
1021
1022 switch (instr->Mask(FPDataProcessing2SourceMask)) {
1023 #define FORMAT(A, B) \
1024 case A##_s: \
1025 case A##_d: mnemonic = B; break;
1026 FORMAT(FMUL, "fmul");
1027 FORMAT(FDIV, "fdiv");
1028 FORMAT(FADD, "fadd");
1029 FORMAT(FSUB, "fsub");
1030 FORMAT(FMAX, "fmax");
1031 FORMAT(FMIN, "fmin");
1032 FORMAT(FMAXNM, "fmaxnm");
1033 FORMAT(FMINNM, "fminnm");
1034 FORMAT(FNMUL, "fnmul");
1035 #undef FORMAT
1036 default: UNREACHABLE();
1037 }
1038 Format(instr, mnemonic, form);
1039}
1040
1041
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001042void DisassemblingDecoder::VisitFPDataProcessing3Source(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001043 const char *mnemonic = "";
1044 const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1045
1046 switch (instr->Mask(FPDataProcessing3SourceMask)) {
1047 #define FORMAT(A, B) \
1048 case A##_s: \
1049 case A##_d: mnemonic = B; break;
1050 FORMAT(FMADD, "fmadd");
1051 FORMAT(FMSUB, "fmsub");
1052 FORMAT(FNMADD, "fnmadd");
1053 FORMAT(FNMSUB, "fnmsub");
1054 #undef FORMAT
1055 default: UNREACHABLE();
1056 }
1057 Format(instr, mnemonic, form);
1058}
1059
1060
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001061void DisassemblingDecoder::VisitFPImmediate(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001062 const char *mnemonic = "";
1063 const char *form = "(FPImmediate)";
1064
1065 switch (instr->Mask(FPImmediateMask)) {
1066 case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1067 case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1068 default: UNREACHABLE();
1069 }
1070 Format(instr, mnemonic, form);
1071}
1072
1073
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074void DisassemblingDecoder::VisitFPIntegerConvert(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001075 const char *mnemonic = "unimplemented";
1076 const char *form = "(FPIntegerConvert)";
1077 const char *form_rf = "'Rd, 'Fn";
1078 const char *form_fr = "'Fd, 'Rn";
1079
1080 switch (instr->Mask(FPIntegerConvertMask)) {
1081 case FMOV_ws:
1082 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1083 case FMOV_sw:
1084 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1085 case FCVTAS_ws:
1086 case FCVTAS_xs:
1087 case FCVTAS_wd:
1088 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
1089 case FCVTAU_ws:
1090 case FCVTAU_xs:
1091 case FCVTAU_wd:
1092 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
1093 case FCVTMS_ws:
1094 case FCVTMS_xs:
1095 case FCVTMS_wd:
1096 case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1097 case FCVTMU_ws:
1098 case FCVTMU_xs:
1099 case FCVTMU_wd:
1100 case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1101 case FCVTNS_ws:
1102 case FCVTNS_xs:
1103 case FCVTNS_wd:
1104 case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1105 case FCVTNU_ws:
1106 case FCVTNU_xs:
1107 case FCVTNU_wd:
1108 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1109 case FCVTZU_xd:
1110 case FCVTZU_ws:
1111 case FCVTZU_wd:
1112 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1113 case FCVTZS_xd:
1114 case FCVTZS_wd:
1115 case FCVTZS_xs:
1116 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1117 case SCVTF_sw:
1118 case SCVTF_sx:
1119 case SCVTF_dw:
1120 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1121 case UCVTF_sw:
1122 case UCVTF_sx:
1123 case UCVTF_dw:
1124 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1125 }
1126 Format(instr, mnemonic, form);
1127}
1128
1129
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001130void DisassemblingDecoder::VisitFPFixedPointConvert(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001131 const char *mnemonic = "";
1132 const char *form = "'Rd, 'Fn, 'IFPFBits";
1133 const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1134
1135 switch (instr->Mask(FPFixedPointConvertMask)) {
1136 case FCVTZS_ws_fixed:
1137 case FCVTZS_xs_fixed:
1138 case FCVTZS_wd_fixed:
1139 case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1140 case FCVTZU_ws_fixed:
1141 case FCVTZU_xs_fixed:
1142 case FCVTZU_wd_fixed:
1143 case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1144 case SCVTF_sw_fixed:
1145 case SCVTF_sx_fixed:
1146 case SCVTF_dw_fixed:
1147 case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1148 case UCVTF_sw_fixed:
1149 case UCVTF_sx_fixed:
1150 case UCVTF_dw_fixed:
1151 case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1152 }
1153 Format(instr, mnemonic, form);
1154}
1155
1156
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157void DisassemblingDecoder::VisitSystem(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001158 // Some system instructions hijack their Op and Cp fields to represent a
1159 // range of immediates instead of indicating a different instruction. This
1160 // makes the decoding tricky.
1161 const char *mnemonic = "unimplemented";
1162 const char *form = "(System)";
1163
1164 if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1165 switch (instr->Mask(SystemSysRegMask)) {
1166 case MRS: {
1167 mnemonic = "mrs";
1168 switch (instr->ImmSystemRegister()) {
1169 case NZCV: form = "'Xt, nzcv"; break;
1170 case FPCR: form = "'Xt, fpcr"; break;
1171 default: form = "'Xt, (unknown)"; break;
1172 }
1173 break;
1174 }
1175 case MSR: {
1176 mnemonic = "msr";
1177 switch (instr->ImmSystemRegister()) {
1178 case NZCV: form = "nzcv, 'Xt"; break;
1179 case FPCR: form = "fpcr, 'Xt"; break;
1180 default: form = "(unknown), 'Xt"; break;
1181 }
1182 break;
1183 }
1184 }
1185 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1186 DCHECK(instr->Mask(SystemHintMask) == HINT);
1187 switch (instr->ImmHint()) {
1188 case NOP: {
1189 mnemonic = "nop";
1190 form = NULL;
1191 break;
1192 }
1193 }
1194 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1195 switch (instr->Mask(MemBarrierMask)) {
1196 case DMB: {
1197 mnemonic = "dmb";
1198 form = "'M";
1199 break;
1200 }
1201 case DSB: {
1202 mnemonic = "dsb";
1203 form = "'M";
1204 break;
1205 }
1206 case ISB: {
1207 mnemonic = "isb";
1208 form = NULL;
1209 break;
1210 }
1211 }
1212 }
1213
1214 Format(instr, mnemonic, form);
1215}
1216
1217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001218void DisassemblingDecoder::VisitException(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219 const char *mnemonic = "unimplemented";
1220 const char *form = "'IDebug";
1221
1222 switch (instr->Mask(ExceptionMask)) {
1223 case HLT: mnemonic = "hlt"; break;
1224 case BRK: mnemonic = "brk"; break;
1225 case SVC: mnemonic = "svc"; break;
1226 case HVC: mnemonic = "hvc"; break;
1227 case SMC: mnemonic = "smc"; break;
1228 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1229 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1230 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1231 default: form = "(Exception)";
1232 }
1233 Format(instr, mnemonic, form);
1234}
1235
1236
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001237void DisassemblingDecoder::VisitUnimplemented(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001238 Format(instr, "unimplemented", "(Unimplemented)");
1239}
1240
1241
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001242void DisassemblingDecoder::VisitUnallocated(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 Format(instr, "unallocated", "(Unallocated)");
1244}
1245
1246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001247void DisassemblingDecoder::ProcessOutput(Instruction* /*instr*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001248 // The base disasm does nothing more than disassembling into a buffer.
1249}
1250
1251
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001252void DisassemblingDecoder::Format(Instruction* instr, const char* mnemonic,
1253 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001254 // TODO(mcapewel) don't think I can use the instr address here - there needs
1255 // to be a base address too
1256 DCHECK(mnemonic != NULL);
1257 ResetOutput();
1258 Substitute(instr, mnemonic);
1259 if (format != NULL) {
1260 buffer_[buffer_pos_++] = ' ';
1261 Substitute(instr, format);
1262 }
1263 buffer_[buffer_pos_] = 0;
1264 ProcessOutput(instr);
1265}
1266
1267
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001268void DisassemblingDecoder::Substitute(Instruction* instr, const char* string) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001269 char chr = *string++;
1270 while (chr != '\0') {
1271 if (chr == '\'') {
1272 string += SubstituteField(instr, string);
1273 } else {
1274 buffer_[buffer_pos_++] = chr;
1275 }
1276 chr = *string++;
1277 }
1278}
1279
1280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001281int DisassemblingDecoder::SubstituteField(Instruction* instr,
1282 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001283 switch (format[0]) {
1284 case 'R': // Register. X or W, selected by sf bit.
1285 case 'F': // FP Register. S or D, selected by type field.
1286 case 'W':
1287 case 'X':
1288 case 'S':
1289 case 'D': return SubstituteRegisterField(instr, format);
1290 case 'I': return SubstituteImmediateField(instr, format);
1291 case 'L': return SubstituteLiteralField(instr, format);
1292 case 'H': return SubstituteShiftField(instr, format);
1293 case 'P': return SubstitutePrefetchField(instr, format);
1294 case 'C': return SubstituteConditionField(instr, format);
1295 case 'E': return SubstituteExtendField(instr, format);
1296 case 'A': return SubstitutePCRelAddressField(instr, format);
1297 case 'B': return SubstituteBranchTargetField(instr, format);
1298 case 'O': return SubstituteLSRegOffsetField(instr, format);
1299 case 'M': return SubstituteBarrierField(instr, format);
1300 default: {
1301 UNREACHABLE();
1302 return 1;
1303 }
1304 }
1305}
1306
1307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001308int DisassemblingDecoder::SubstituteRegisterField(Instruction* instr,
1309 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001310 unsigned reg_num = 0;
1311 unsigned field_len = 2;
1312 switch (format[1]) {
1313 case 'd': reg_num = instr->Rd(); break;
1314 case 'n': reg_num = instr->Rn(); break;
1315 case 'm': reg_num = instr->Rm(); break;
1316 case 'a': reg_num = instr->Ra(); break;
1317 case 't': {
1318 if (format[2] == '2') {
1319 reg_num = instr->Rt2();
1320 field_len = 3;
1321 } else {
1322 reg_num = instr->Rt();
1323 }
1324 break;
1325 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001326 case 's':
1327 reg_num = instr->Rs();
1328 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001329 default: UNREACHABLE();
1330 }
1331
1332 // Increase field length for registers tagged as stack.
1333 if (format[2] == 's') {
1334 field_len = 3;
1335 }
1336
1337 char reg_type;
1338 if (format[0] == 'R') {
1339 // Register type is R: use sf bit to choose X and W.
1340 reg_type = instr->SixtyFourBits() ? 'x' : 'w';
1341 } else if (format[0] == 'F') {
1342 // Floating-point register: use type field to choose S or D.
1343 reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
1344 } else {
1345 // Register type is specified. Make it lower case.
1346 reg_type = format[0] + 0x20;
1347 }
1348
1349 if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
1350 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
1351
1352 // Filter special registers
1353 if ((reg_type == 'x') && (reg_num == 27)) {
1354 AppendToOutput("cp");
1355 } else if ((reg_type == 'x') && (reg_num == 28)) {
1356 AppendToOutput("jssp");
1357 } else if ((reg_type == 'x') && (reg_num == 29)) {
1358 AppendToOutput("fp");
1359 } else if ((reg_type == 'x') && (reg_num == 30)) {
1360 AppendToOutput("lr");
1361 } else {
1362 AppendToOutput("%c%d", reg_type, reg_num);
1363 }
1364 } else if (format[2] == 's') {
1365 // Disassemble w31/x31 as stack pointer wcsp/csp.
1366 AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp");
1367 } else {
1368 // Disassemble w31/x31 as zero register wzr/xzr.
1369 AppendToOutput("%czr", reg_type);
1370 }
1371
1372 return field_len;
1373}
1374
1375
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001376int DisassemblingDecoder::SubstituteImmediateField(Instruction* instr,
1377 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378 DCHECK(format[0] == 'I');
1379
1380 switch (format[1]) {
1381 case 'M': { // IMoveImm or IMoveLSL.
1382 if (format[5] == 'I') {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001383 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide())
1384 << (16 * instr->ShiftMoveWide());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001385 AppendToOutput("#0x%" PRIx64, imm);
1386 } else {
1387 DCHECK(format[5] == 'L');
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001388 AppendToOutput("#0x%" PRIx32, instr->ImmMoveWide());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001389 if (instr->ShiftMoveWide() > 0) {
1390 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
1391 }
1392 }
1393 return 8;
1394 }
1395 case 'L': {
1396 switch (format[2]) {
1397 case 'L': { // ILLiteral - Immediate Load Literal.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001398 AppendToOutput("pc%+" PRId32, instr->ImmLLiteral()
1399 << kLoadLiteralScaleLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001400 return 9;
1401 }
1402 case 'S': { // ILS - Immediate Load/Store.
1403 if (instr->ImmLS() != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001404 AppendToOutput(", #%" PRId32, instr->ImmLS());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001405 }
1406 return 3;
1407 }
1408 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
1409 if (instr->ImmLSPair() != 0) {
1410 // format[3] is the scale value. Convert to a number.
1411 int scale = format[3] - 0x30;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001412 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413 }
1414 return 4;
1415 }
1416 case 'U': { // ILU - Immediate Load/Store Unsigned.
1417 if (instr->ImmLSUnsigned() != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001418 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned()
1419 << instr->SizeLS());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001420 }
1421 return 3;
1422 }
1423 }
1424 }
1425 case 'C': { // ICondB - Immediate Conditional Branch.
1426 int64_t offset = instr->ImmCondBranch() << 2;
1427 char sign = (offset >= 0) ? '+' : '-';
1428 AppendToOutput("#%c0x%" PRIx64, sign, offset);
1429 return 6;
1430 }
1431 case 'A': { // IAddSub.
1432 DCHECK(instr->ShiftAddSub() <= 1);
1433 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
1434 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
1435 return 7;
1436 }
1437 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
1438 if (format[3] == 'F') { // IFPFBits.
1439 AppendToOutput("#%d", 64 - instr->FPScale());
1440 return 8;
1441 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001442 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmFP(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001443 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
1444 return 9;
1445 }
1446 }
1447 case 'T': { // ITri - Immediate Triangular Encoded.
1448 AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
1449 return 4;
1450 }
1451 case 'N': { // INzcv.
1452 int nzcv = (instr->Nzcv() << Flags_offset);
1453 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
1454 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
1455 ((nzcv & CFlag) == 0) ? 'c' : 'C',
1456 ((nzcv & VFlag) == 0) ? 'v' : 'V');
1457 return 5;
1458 }
1459 case 'P': { // IP - Conditional compare.
1460 AppendToOutput("#%d", instr->ImmCondCmp());
1461 return 2;
1462 }
1463 case 'B': { // Bitfields.
1464 return SubstituteBitfieldImmediateField(instr, format);
1465 }
1466 case 'E': { // IExtract.
1467 AppendToOutput("#%d", instr->ImmS());
1468 return 8;
1469 }
1470 case 'S': { // IS - Test and branch bit.
1471 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
1472 instr->ImmTestBranchBit40());
1473 return 2;
1474 }
1475 case 'D': { // IDebug - HLT and BRK instructions.
1476 AppendToOutput("#0x%x", instr->ImmException());
1477 return 6;
1478 }
1479 default: {
1480 UNREACHABLE();
1481 return 0;
1482 }
1483 }
1484}
1485
1486
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001487int DisassemblingDecoder::SubstituteBitfieldImmediateField(Instruction* instr,
1488 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001489 DCHECK((format[0] == 'I') && (format[1] == 'B'));
1490 unsigned r = instr->ImmR();
1491 unsigned s = instr->ImmS();
1492
1493 switch (format[2]) {
1494 case 'r': { // IBr.
1495 AppendToOutput("#%d", r);
1496 return 3;
1497 }
1498 case 's': { // IBs+1 or IBs-r+1.
1499 if (format[3] == '+') {
1500 AppendToOutput("#%d", s + 1);
1501 return 5;
1502 } else {
1503 DCHECK(format[3] == '-');
1504 AppendToOutput("#%d", s - r + 1);
1505 return 7;
1506 }
1507 }
1508 case 'Z': { // IBZ-r.
1509 DCHECK((format[3] == '-') && (format[4] == 'r'));
1510 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
1511 : kWRegSizeInBits;
1512 AppendToOutput("#%d", reg_size - r);
1513 return 5;
1514 }
1515 default: {
1516 UNREACHABLE();
1517 return 0;
1518 }
1519 }
1520}
1521
1522
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001523int DisassemblingDecoder::SubstituteLiteralField(Instruction* instr,
1524 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001525 DCHECK(strncmp(format, "LValue", 6) == 0);
1526 USE(format);
1527
1528 switch (instr->Mask(LoadLiteralMask)) {
1529 case LDR_w_lit:
1530 case LDR_x_lit:
1531 case LDR_s_lit:
1532 case LDR_d_lit:
1533 AppendToOutput("(addr 0x%016" PRIxPTR ")", instr->LiteralAddress());
1534 break;
1535 default: UNREACHABLE();
1536 }
1537
1538 return 6;
1539}
1540
1541
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001542int DisassemblingDecoder::SubstituteShiftField(Instruction* instr,
1543 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001544 DCHECK(format[0] == 'H');
1545 DCHECK(instr->ShiftDP() <= 0x3);
1546
1547 switch (format[1]) {
1548 case 'D': { // HDP.
1549 DCHECK(instr->ShiftDP() != ROR);
1550 } // Fall through.
1551 case 'L': { // HLo.
1552 if (instr->ImmDPShift() != 0) {
1553 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001554 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()],
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001555 instr->ImmDPShift());
1556 }
1557 return 3;
1558 }
1559 default:
1560 UNREACHABLE();
1561 return 0;
1562 }
1563}
1564
1565
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001566int DisassemblingDecoder::SubstituteConditionField(Instruction* instr,
1567 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001568 DCHECK(format[0] == 'C');
1569 const char* condition_code[] = { "eq", "ne", "hs", "lo",
1570 "mi", "pl", "vs", "vc",
1571 "hi", "ls", "ge", "lt",
1572 "gt", "le", "al", "nv" };
1573 int cond;
1574 switch (format[1]) {
1575 case 'B': cond = instr->ConditionBranch(); break;
1576 case 'I': {
1577 cond = NegateCondition(static_cast<Condition>(instr->Condition()));
1578 break;
1579 }
1580 default: cond = instr->Condition();
1581 }
1582 AppendToOutput("%s", condition_code[cond]);
1583 return 4;
1584}
1585
1586
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001587int DisassemblingDecoder::SubstitutePCRelAddressField(Instruction* instr,
1588 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001589 USE(format);
1590 DCHECK(strncmp(format, "AddrPCRel", 9) == 0);
1591
1592 int offset = instr->ImmPCRel();
1593
1594 // Only ADR (AddrPCRelByte) is supported.
1595 DCHECK(strcmp(format, "AddrPCRelByte") == 0);
1596
1597 char sign = '+';
1598 if (offset < 0) {
1599 offset = -offset;
1600 sign = '-';
1601 }
1602 AppendToOutput("#%c0x%x (addr %p)", sign, offset,
1603 instr->InstructionAtOffset(offset, Instruction::NO_CHECK));
1604 return 13;
1605}
1606
1607
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001608int DisassemblingDecoder::SubstituteBranchTargetField(Instruction* instr,
1609 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001610 DCHECK(strncmp(format, "BImm", 4) == 0);
1611
1612 int64_t offset = 0;
1613 switch (format[5]) {
1614 // BImmUncn - unconditional branch immediate.
1615 case 'n': offset = instr->ImmUncondBranch(); break;
1616 // BImmCond - conditional branch immediate.
1617 case 'o': offset = instr->ImmCondBranch(); break;
1618 // BImmCmpa - compare and branch immediate.
1619 case 'm': offset = instr->ImmCmpBranch(); break;
1620 // BImmTest - test and branch immediate.
1621 case 'e': offset = instr->ImmTestBranch(); break;
1622 default: UNREACHABLE();
1623 }
1624 offset <<= kInstructionSizeLog2;
1625 char sign = '+';
1626 if (offset < 0) {
1627 sign = '-';
1628 }
1629 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset),
1630 instr->InstructionAtOffset(offset), Instruction::NO_CHECK);
1631 return 8;
1632}
1633
1634
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001635int DisassemblingDecoder::SubstituteExtendField(Instruction* instr,
1636 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001637 DCHECK(strncmp(format, "Ext", 3) == 0);
1638 DCHECK(instr->ExtendMode() <= 7);
1639 USE(format);
1640
1641 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
1642 "sxtb", "sxth", "sxtw", "sxtx" };
1643
1644 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
1645 // registers becomes lsl.
1646 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
1647 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
1648 (instr->ExtendMode() == UXTX))) {
1649 if (instr->ImmExtendShift() > 0) {
1650 AppendToOutput(", lsl #%d", instr->ImmExtendShift());
1651 }
1652 } else {
1653 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
1654 if (instr->ImmExtendShift() > 0) {
1655 AppendToOutput(" #%d", instr->ImmExtendShift());
1656 }
1657 }
1658 return 3;
1659}
1660
1661
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001662int DisassemblingDecoder::SubstituteLSRegOffsetField(Instruction* instr,
1663 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664 DCHECK(strncmp(format, "Offsetreg", 9) == 0);
1665 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
1666 "undefined", "undefined", "sxtw", "sxtx" };
1667 USE(format);
1668
1669 unsigned shift = instr->ImmShiftLS();
1670 Extend ext = static_cast<Extend>(instr->ExtendMode());
1671 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
1672
1673 unsigned rm = instr->Rm();
1674 if (rm == kZeroRegCode) {
1675 AppendToOutput("%czr", reg_type);
1676 } else {
1677 AppendToOutput("%c%d", reg_type, rm);
1678 }
1679
1680 // Extend mode UXTX is an alias for shift mode LSL here.
1681 if (!((ext == UXTX) && (shift == 0))) {
1682 AppendToOutput(", %s", extend_mode[ext]);
1683 if (shift != 0) {
1684 AppendToOutput(" #%d", instr->SizeLS());
1685 }
1686 }
1687 return 9;
1688}
1689
1690
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001691int DisassemblingDecoder::SubstitutePrefetchField(Instruction* instr,
1692 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001693 DCHECK(format[0] == 'P');
1694 USE(format);
1695
1696 int prefetch_mode = instr->PrefetchMode();
1697
1698 const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
1699 int level = (prefetch_mode >> 1) + 1;
1700 const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
1701
1702 AppendToOutput("p%sl%d%s", ls, level, ks);
1703 return 6;
1704}
1705
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001706int DisassemblingDecoder::SubstituteBarrierField(Instruction* instr,
1707 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001708 DCHECK(format[0] == 'M');
1709 USE(format);
1710
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001711 static const char* const options[4][4] = {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001712 { "sy (0b0000)", "oshld", "oshst", "osh" },
1713 { "sy (0b0100)", "nshld", "nshst", "nsh" },
1714 { "sy (0b1000)", "ishld", "ishst", "ish" },
1715 { "sy (0b1100)", "ld", "st", "sy" }
1716 };
1717 int domain = instr->ImmBarrierDomain();
1718 int type = instr->ImmBarrierType();
1719
1720 AppendToOutput("%s", options[domain][type]);
1721 return 1;
1722}
1723
1724
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001725void DisassemblingDecoder::ResetOutput() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001726 buffer_pos_ = 0;
1727 buffer_[buffer_pos_] = 0;
1728}
1729
1730
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001731void DisassemblingDecoder::AppendToOutput(const char* format, ...) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001732 va_list args;
1733 va_start(args, format);
1734 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
1735 va_end(args);
1736}
1737
1738
1739void PrintDisassembler::ProcessOutput(Instruction* instr) {
1740 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
1741 reinterpret_cast<uint64_t>(instr), instr->InstructionBits(),
1742 GetOutput());
1743}
1744
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001745} // namespace internal
1746} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001747
1748
1749namespace disasm {
1750
1751
1752const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001753 v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void *>(addr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001754 return tmp_buffer_.start();
1755}
1756
1757
1758const char* NameConverter::NameOfConstant(byte* addr) const {
1759 return NameOfAddress(addr);
1760}
1761
1762
1763const char* NameConverter::NameOfCPURegister(int reg) const {
1764 unsigned ureg = reg; // Avoid warnings about signed/unsigned comparisons.
1765 if (ureg >= v8::internal::kNumberOfRegisters) {
1766 return "noreg";
1767 }
1768 if (ureg == v8::internal::kZeroRegCode) {
1769 return "xzr";
1770 }
1771 v8::internal::SNPrintF(tmp_buffer_, "x%u", ureg);
1772 return tmp_buffer_.start();
1773}
1774
1775
1776const char* NameConverter::NameOfByteCPURegister(int reg) const {
1777 UNREACHABLE(); // ARM64 does not have the concept of a byte register
1778 return "nobytereg";
1779}
1780
1781
1782const char* NameConverter::NameOfXMMRegister(int reg) const {
1783 UNREACHABLE(); // ARM64 does not have any XMM registers
1784 return "noxmmreg";
1785}
1786
1787
1788const char* NameConverter::NameInCode(byte* addr) const {
1789 // The default name converter is called for unknown code, so we will not try
1790 // to access any memory.
1791 return "";
1792}
1793
1794
1795//------------------------------------------------------------------------------
1796
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001797class BufferDisassembler : public v8::internal::DisassemblingDecoder {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001798 public:
1799 explicit BufferDisassembler(v8::internal::Vector<char> out_buffer)
1800 : out_buffer_(out_buffer) { }
1801
1802 ~BufferDisassembler() { }
1803
1804 virtual void ProcessOutput(v8::internal::Instruction* instr) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001805 v8::internal::SNPrintF(out_buffer_, "%08" PRIx32 " %s",
1806 instr->InstructionBits(), GetOutput());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001807 }
1808
1809 private:
1810 v8::internal::Vector<char> out_buffer_;
1811};
1812
1813Disassembler::Disassembler(const NameConverter& converter)
1814 : converter_(converter) {}
1815
1816
1817Disassembler::~Disassembler() { USE(converter_); }
1818
1819
1820int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1821 byte* instr) {
1822 v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
1823 BufferDisassembler disasm(buffer);
1824 decoder.AppendVisitor(&disasm);
1825
1826 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(instr));
1827 return v8::internal::kInstructionSize;
1828}
1829
1830
1831int Disassembler::ConstantPoolSizeAt(byte* instr) {
1832 return v8::internal::Assembler::ConstantPoolSizeAt(
1833 reinterpret_cast<v8::internal::Instruction*>(instr));
1834}
1835
1836
1837void Disassembler::Disassemble(FILE* file, byte* start, byte* end) {
1838 v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
1839 v8::internal::PrintDisassembler disasm(file);
1840 decoder.AppendVisitor(&disasm);
1841
1842 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) {
1843 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc));
1844 }
1845}
1846
1847} // namespace disasm
1848
1849#endif // V8_TARGET_ARCH_ARM64