blob: 00c3ec25d6a76331547e6e5ecbc14e6196703789 [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
917
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000918void DisassemblingDecoder::VisitFPCompare(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000919 const char *mnemonic = "unimplemented";
920 const char *form = "'Fn, 'Fm";
921 const char *form_zero = "'Fn, #0.0";
922
923 switch (instr->Mask(FPCompareMask)) {
924 case FCMP_s_zero:
925 case FCMP_d_zero: form = form_zero; // Fall through.
926 case FCMP_s:
927 case FCMP_d: mnemonic = "fcmp"; break;
928 default: form = "(FPCompare)";
929 }
930 Format(instr, mnemonic, form);
931}
932
933
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000934void DisassemblingDecoder::VisitFPConditionalCompare(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000935 const char *mnemonic = "unimplemented";
936 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
937
938 switch (instr->Mask(FPConditionalCompareMask)) {
939 case FCCMP_s:
940 case FCCMP_d: mnemonic = "fccmp"; break;
941 case FCCMPE_s:
942 case FCCMPE_d: mnemonic = "fccmpe"; break;
943 default: form = "(FPConditionalCompare)";
944 }
945 Format(instr, mnemonic, form);
946}
947
948
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000949void DisassemblingDecoder::VisitFPConditionalSelect(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000950 const char *mnemonic = "";
951 const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
952
953 switch (instr->Mask(FPConditionalSelectMask)) {
954 case FCSEL_s:
955 case FCSEL_d: mnemonic = "fcsel"; break;
956 default: UNREACHABLE();
957 }
958 Format(instr, mnemonic, form);
959}
960
961
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000962void DisassemblingDecoder::VisitFPDataProcessing1Source(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963 const char *mnemonic = "unimplemented";
964 const char *form = "'Fd, 'Fn";
965
966 switch (instr->Mask(FPDataProcessing1SourceMask)) {
967 #define FORMAT(A, B) \
968 case A##_s: \
969 case A##_d: mnemonic = B; break;
970 FORMAT(FMOV, "fmov");
971 FORMAT(FABS, "fabs");
972 FORMAT(FNEG, "fneg");
973 FORMAT(FSQRT, "fsqrt");
974 FORMAT(FRINTN, "frintn");
975 FORMAT(FRINTP, "frintp");
976 FORMAT(FRINTM, "frintm");
977 FORMAT(FRINTZ, "frintz");
978 FORMAT(FRINTA, "frinta");
979 FORMAT(FRINTX, "frintx");
980 FORMAT(FRINTI, "frinti");
981 #undef FORMAT
982 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
983 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
984 default: form = "(FPDataProcessing1Source)";
985 }
986 Format(instr, mnemonic, form);
987}
988
989
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000990void DisassemblingDecoder::VisitFPDataProcessing2Source(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000991 const char *mnemonic = "";
992 const char *form = "'Fd, 'Fn, 'Fm";
993
994 switch (instr->Mask(FPDataProcessing2SourceMask)) {
995 #define FORMAT(A, B) \
996 case A##_s: \
997 case A##_d: mnemonic = B; break;
998 FORMAT(FMUL, "fmul");
999 FORMAT(FDIV, "fdiv");
1000 FORMAT(FADD, "fadd");
1001 FORMAT(FSUB, "fsub");
1002 FORMAT(FMAX, "fmax");
1003 FORMAT(FMIN, "fmin");
1004 FORMAT(FMAXNM, "fmaxnm");
1005 FORMAT(FMINNM, "fminnm");
1006 FORMAT(FNMUL, "fnmul");
1007 #undef FORMAT
1008 default: UNREACHABLE();
1009 }
1010 Format(instr, mnemonic, form);
1011}
1012
1013
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001014void DisassemblingDecoder::VisitFPDataProcessing3Source(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001015 const char *mnemonic = "";
1016 const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1017
1018 switch (instr->Mask(FPDataProcessing3SourceMask)) {
1019 #define FORMAT(A, B) \
1020 case A##_s: \
1021 case A##_d: mnemonic = B; break;
1022 FORMAT(FMADD, "fmadd");
1023 FORMAT(FMSUB, "fmsub");
1024 FORMAT(FNMADD, "fnmadd");
1025 FORMAT(FNMSUB, "fnmsub");
1026 #undef FORMAT
1027 default: UNREACHABLE();
1028 }
1029 Format(instr, mnemonic, form);
1030}
1031
1032
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001033void DisassemblingDecoder::VisitFPImmediate(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001034 const char *mnemonic = "";
1035 const char *form = "(FPImmediate)";
1036
1037 switch (instr->Mask(FPImmediateMask)) {
1038 case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1039 case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1040 default: UNREACHABLE();
1041 }
1042 Format(instr, mnemonic, form);
1043}
1044
1045
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001046void DisassemblingDecoder::VisitFPIntegerConvert(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001047 const char *mnemonic = "unimplemented";
1048 const char *form = "(FPIntegerConvert)";
1049 const char *form_rf = "'Rd, 'Fn";
1050 const char *form_fr = "'Fd, 'Rn";
1051
1052 switch (instr->Mask(FPIntegerConvertMask)) {
1053 case FMOV_ws:
1054 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1055 case FMOV_sw:
1056 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1057 case FCVTAS_ws:
1058 case FCVTAS_xs:
1059 case FCVTAS_wd:
1060 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
1061 case FCVTAU_ws:
1062 case FCVTAU_xs:
1063 case FCVTAU_wd:
1064 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
1065 case FCVTMS_ws:
1066 case FCVTMS_xs:
1067 case FCVTMS_wd:
1068 case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1069 case FCVTMU_ws:
1070 case FCVTMU_xs:
1071 case FCVTMU_wd:
1072 case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1073 case FCVTNS_ws:
1074 case FCVTNS_xs:
1075 case FCVTNS_wd:
1076 case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1077 case FCVTNU_ws:
1078 case FCVTNU_xs:
1079 case FCVTNU_wd:
1080 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1081 case FCVTZU_xd:
1082 case FCVTZU_ws:
1083 case FCVTZU_wd:
1084 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1085 case FCVTZS_xd:
1086 case FCVTZS_wd:
1087 case FCVTZS_xs:
1088 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1089 case SCVTF_sw:
1090 case SCVTF_sx:
1091 case SCVTF_dw:
1092 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1093 case UCVTF_sw:
1094 case UCVTF_sx:
1095 case UCVTF_dw:
1096 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1097 }
1098 Format(instr, mnemonic, form);
1099}
1100
1101
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001102void DisassemblingDecoder::VisitFPFixedPointConvert(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001103 const char *mnemonic = "";
1104 const char *form = "'Rd, 'Fn, 'IFPFBits";
1105 const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1106
1107 switch (instr->Mask(FPFixedPointConvertMask)) {
1108 case FCVTZS_ws_fixed:
1109 case FCVTZS_xs_fixed:
1110 case FCVTZS_wd_fixed:
1111 case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1112 case FCVTZU_ws_fixed:
1113 case FCVTZU_xs_fixed:
1114 case FCVTZU_wd_fixed:
1115 case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1116 case SCVTF_sw_fixed:
1117 case SCVTF_sx_fixed:
1118 case SCVTF_dw_fixed:
1119 case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1120 case UCVTF_sw_fixed:
1121 case UCVTF_sx_fixed:
1122 case UCVTF_dw_fixed:
1123 case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1124 }
1125 Format(instr, mnemonic, form);
1126}
1127
1128
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001129void DisassemblingDecoder::VisitSystem(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001130 // Some system instructions hijack their Op and Cp fields to represent a
1131 // range of immediates instead of indicating a different instruction. This
1132 // makes the decoding tricky.
1133 const char *mnemonic = "unimplemented";
1134 const char *form = "(System)";
1135
1136 if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1137 switch (instr->Mask(SystemSysRegMask)) {
1138 case MRS: {
1139 mnemonic = "mrs";
1140 switch (instr->ImmSystemRegister()) {
1141 case NZCV: form = "'Xt, nzcv"; break;
1142 case FPCR: form = "'Xt, fpcr"; break;
1143 default: form = "'Xt, (unknown)"; break;
1144 }
1145 break;
1146 }
1147 case MSR: {
1148 mnemonic = "msr";
1149 switch (instr->ImmSystemRegister()) {
1150 case NZCV: form = "nzcv, 'Xt"; break;
1151 case FPCR: form = "fpcr, 'Xt"; break;
1152 default: form = "(unknown), 'Xt"; break;
1153 }
1154 break;
1155 }
1156 }
1157 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1158 DCHECK(instr->Mask(SystemHintMask) == HINT);
1159 switch (instr->ImmHint()) {
1160 case NOP: {
1161 mnemonic = "nop";
1162 form = NULL;
1163 break;
1164 }
1165 }
1166 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1167 switch (instr->Mask(MemBarrierMask)) {
1168 case DMB: {
1169 mnemonic = "dmb";
1170 form = "'M";
1171 break;
1172 }
1173 case DSB: {
1174 mnemonic = "dsb";
1175 form = "'M";
1176 break;
1177 }
1178 case ISB: {
1179 mnemonic = "isb";
1180 form = NULL;
1181 break;
1182 }
1183 }
1184 }
1185
1186 Format(instr, mnemonic, form);
1187}
1188
1189
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001190void DisassemblingDecoder::VisitException(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001191 const char *mnemonic = "unimplemented";
1192 const char *form = "'IDebug";
1193
1194 switch (instr->Mask(ExceptionMask)) {
1195 case HLT: mnemonic = "hlt"; break;
1196 case BRK: mnemonic = "brk"; break;
1197 case SVC: mnemonic = "svc"; break;
1198 case HVC: mnemonic = "hvc"; break;
1199 case SMC: mnemonic = "smc"; break;
1200 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1201 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1202 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1203 default: form = "(Exception)";
1204 }
1205 Format(instr, mnemonic, form);
1206}
1207
1208
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209void DisassemblingDecoder::VisitUnimplemented(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001210 Format(instr, "unimplemented", "(Unimplemented)");
1211}
1212
1213
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214void DisassemblingDecoder::VisitUnallocated(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001215 Format(instr, "unallocated", "(Unallocated)");
1216}
1217
1218
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001219void DisassemblingDecoder::ProcessOutput(Instruction* /*instr*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001220 // The base disasm does nothing more than disassembling into a buffer.
1221}
1222
1223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001224void DisassemblingDecoder::Format(Instruction* instr, const char* mnemonic,
1225 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001226 // TODO(mcapewel) don't think I can use the instr address here - there needs
1227 // to be a base address too
1228 DCHECK(mnemonic != NULL);
1229 ResetOutput();
1230 Substitute(instr, mnemonic);
1231 if (format != NULL) {
1232 buffer_[buffer_pos_++] = ' ';
1233 Substitute(instr, format);
1234 }
1235 buffer_[buffer_pos_] = 0;
1236 ProcessOutput(instr);
1237}
1238
1239
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240void DisassemblingDecoder::Substitute(Instruction* instr, const char* string) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001241 char chr = *string++;
1242 while (chr != '\0') {
1243 if (chr == '\'') {
1244 string += SubstituteField(instr, string);
1245 } else {
1246 buffer_[buffer_pos_++] = chr;
1247 }
1248 chr = *string++;
1249 }
1250}
1251
1252
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001253int DisassemblingDecoder::SubstituteField(Instruction* instr,
1254 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001255 switch (format[0]) {
1256 case 'R': // Register. X or W, selected by sf bit.
1257 case 'F': // FP Register. S or D, selected by type field.
1258 case 'W':
1259 case 'X':
1260 case 'S':
1261 case 'D': return SubstituteRegisterField(instr, format);
1262 case 'I': return SubstituteImmediateField(instr, format);
1263 case 'L': return SubstituteLiteralField(instr, format);
1264 case 'H': return SubstituteShiftField(instr, format);
1265 case 'P': return SubstitutePrefetchField(instr, format);
1266 case 'C': return SubstituteConditionField(instr, format);
1267 case 'E': return SubstituteExtendField(instr, format);
1268 case 'A': return SubstitutePCRelAddressField(instr, format);
1269 case 'B': return SubstituteBranchTargetField(instr, format);
1270 case 'O': return SubstituteLSRegOffsetField(instr, format);
1271 case 'M': return SubstituteBarrierField(instr, format);
1272 default: {
1273 UNREACHABLE();
1274 return 1;
1275 }
1276 }
1277}
1278
1279
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001280int DisassemblingDecoder::SubstituteRegisterField(Instruction* instr,
1281 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001282 unsigned reg_num = 0;
1283 unsigned field_len = 2;
1284 switch (format[1]) {
1285 case 'd': reg_num = instr->Rd(); break;
1286 case 'n': reg_num = instr->Rn(); break;
1287 case 'm': reg_num = instr->Rm(); break;
1288 case 'a': reg_num = instr->Ra(); break;
1289 case 't': {
1290 if (format[2] == '2') {
1291 reg_num = instr->Rt2();
1292 field_len = 3;
1293 } else {
1294 reg_num = instr->Rt();
1295 }
1296 break;
1297 }
1298 default: UNREACHABLE();
1299 }
1300
1301 // Increase field length for registers tagged as stack.
1302 if (format[2] == 's') {
1303 field_len = 3;
1304 }
1305
1306 char reg_type;
1307 if (format[0] == 'R') {
1308 // Register type is R: use sf bit to choose X and W.
1309 reg_type = instr->SixtyFourBits() ? 'x' : 'w';
1310 } else if (format[0] == 'F') {
1311 // Floating-point register: use type field to choose S or D.
1312 reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
1313 } else {
1314 // Register type is specified. Make it lower case.
1315 reg_type = format[0] + 0x20;
1316 }
1317
1318 if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
1319 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
1320
1321 // Filter special registers
1322 if ((reg_type == 'x') && (reg_num == 27)) {
1323 AppendToOutput("cp");
1324 } else if ((reg_type == 'x') && (reg_num == 28)) {
1325 AppendToOutput("jssp");
1326 } else if ((reg_type == 'x') && (reg_num == 29)) {
1327 AppendToOutput("fp");
1328 } else if ((reg_type == 'x') && (reg_num == 30)) {
1329 AppendToOutput("lr");
1330 } else {
1331 AppendToOutput("%c%d", reg_type, reg_num);
1332 }
1333 } else if (format[2] == 's') {
1334 // Disassemble w31/x31 as stack pointer wcsp/csp.
1335 AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp");
1336 } else {
1337 // Disassemble w31/x31 as zero register wzr/xzr.
1338 AppendToOutput("%czr", reg_type);
1339 }
1340
1341 return field_len;
1342}
1343
1344
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001345int DisassemblingDecoder::SubstituteImmediateField(Instruction* instr,
1346 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001347 DCHECK(format[0] == 'I');
1348
1349 switch (format[1]) {
1350 case 'M': { // IMoveImm or IMoveLSL.
1351 if (format[5] == 'I') {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001352 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide())
1353 << (16 * instr->ShiftMoveWide());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001354 AppendToOutput("#0x%" PRIx64, imm);
1355 } else {
1356 DCHECK(format[5] == 'L');
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001357 AppendToOutput("#0x%" PRIx32, instr->ImmMoveWide());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358 if (instr->ShiftMoveWide() > 0) {
1359 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
1360 }
1361 }
1362 return 8;
1363 }
1364 case 'L': {
1365 switch (format[2]) {
1366 case 'L': { // ILLiteral - Immediate Load Literal.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001367 AppendToOutput("pc%+" PRId32, instr->ImmLLiteral()
1368 << kLoadLiteralScaleLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001369 return 9;
1370 }
1371 case 'S': { // ILS - Immediate Load/Store.
1372 if (instr->ImmLS() != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001373 AppendToOutput(", #%" PRId32, instr->ImmLS());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001374 }
1375 return 3;
1376 }
1377 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
1378 if (instr->ImmLSPair() != 0) {
1379 // format[3] is the scale value. Convert to a number.
1380 int scale = format[3] - 0x30;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001381 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001382 }
1383 return 4;
1384 }
1385 case 'U': { // ILU - Immediate Load/Store Unsigned.
1386 if (instr->ImmLSUnsigned() != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001387 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned()
1388 << instr->SizeLS());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001389 }
1390 return 3;
1391 }
1392 }
1393 }
1394 case 'C': { // ICondB - Immediate Conditional Branch.
1395 int64_t offset = instr->ImmCondBranch() << 2;
1396 char sign = (offset >= 0) ? '+' : '-';
1397 AppendToOutput("#%c0x%" PRIx64, sign, offset);
1398 return 6;
1399 }
1400 case 'A': { // IAddSub.
1401 DCHECK(instr->ShiftAddSub() <= 1);
1402 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
1403 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
1404 return 7;
1405 }
1406 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
1407 if (format[3] == 'F') { // IFPFBits.
1408 AppendToOutput("#%d", 64 - instr->FPScale());
1409 return 8;
1410 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001411 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmFP(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
1413 return 9;
1414 }
1415 }
1416 case 'T': { // ITri - Immediate Triangular Encoded.
1417 AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
1418 return 4;
1419 }
1420 case 'N': { // INzcv.
1421 int nzcv = (instr->Nzcv() << Flags_offset);
1422 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
1423 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
1424 ((nzcv & CFlag) == 0) ? 'c' : 'C',
1425 ((nzcv & VFlag) == 0) ? 'v' : 'V');
1426 return 5;
1427 }
1428 case 'P': { // IP - Conditional compare.
1429 AppendToOutput("#%d", instr->ImmCondCmp());
1430 return 2;
1431 }
1432 case 'B': { // Bitfields.
1433 return SubstituteBitfieldImmediateField(instr, format);
1434 }
1435 case 'E': { // IExtract.
1436 AppendToOutput("#%d", instr->ImmS());
1437 return 8;
1438 }
1439 case 'S': { // IS - Test and branch bit.
1440 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
1441 instr->ImmTestBranchBit40());
1442 return 2;
1443 }
1444 case 'D': { // IDebug - HLT and BRK instructions.
1445 AppendToOutput("#0x%x", instr->ImmException());
1446 return 6;
1447 }
1448 default: {
1449 UNREACHABLE();
1450 return 0;
1451 }
1452 }
1453}
1454
1455
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001456int DisassemblingDecoder::SubstituteBitfieldImmediateField(Instruction* instr,
1457 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001458 DCHECK((format[0] == 'I') && (format[1] == 'B'));
1459 unsigned r = instr->ImmR();
1460 unsigned s = instr->ImmS();
1461
1462 switch (format[2]) {
1463 case 'r': { // IBr.
1464 AppendToOutput("#%d", r);
1465 return 3;
1466 }
1467 case 's': { // IBs+1 or IBs-r+1.
1468 if (format[3] == '+') {
1469 AppendToOutput("#%d", s + 1);
1470 return 5;
1471 } else {
1472 DCHECK(format[3] == '-');
1473 AppendToOutput("#%d", s - r + 1);
1474 return 7;
1475 }
1476 }
1477 case 'Z': { // IBZ-r.
1478 DCHECK((format[3] == '-') && (format[4] == 'r'));
1479 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
1480 : kWRegSizeInBits;
1481 AppendToOutput("#%d", reg_size - r);
1482 return 5;
1483 }
1484 default: {
1485 UNREACHABLE();
1486 return 0;
1487 }
1488 }
1489}
1490
1491
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001492int DisassemblingDecoder::SubstituteLiteralField(Instruction* instr,
1493 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001494 DCHECK(strncmp(format, "LValue", 6) == 0);
1495 USE(format);
1496
1497 switch (instr->Mask(LoadLiteralMask)) {
1498 case LDR_w_lit:
1499 case LDR_x_lit:
1500 case LDR_s_lit:
1501 case LDR_d_lit:
1502 AppendToOutput("(addr 0x%016" PRIxPTR ")", instr->LiteralAddress());
1503 break;
1504 default: UNREACHABLE();
1505 }
1506
1507 return 6;
1508}
1509
1510
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001511int DisassemblingDecoder::SubstituteShiftField(Instruction* instr,
1512 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001513 DCHECK(format[0] == 'H');
1514 DCHECK(instr->ShiftDP() <= 0x3);
1515
1516 switch (format[1]) {
1517 case 'D': { // HDP.
1518 DCHECK(instr->ShiftDP() != ROR);
1519 } // Fall through.
1520 case 'L': { // HLo.
1521 if (instr->ImmDPShift() != 0) {
1522 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001523 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()],
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001524 instr->ImmDPShift());
1525 }
1526 return 3;
1527 }
1528 default:
1529 UNREACHABLE();
1530 return 0;
1531 }
1532}
1533
1534
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001535int DisassemblingDecoder::SubstituteConditionField(Instruction* instr,
1536 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 DCHECK(format[0] == 'C');
1538 const char* condition_code[] = { "eq", "ne", "hs", "lo",
1539 "mi", "pl", "vs", "vc",
1540 "hi", "ls", "ge", "lt",
1541 "gt", "le", "al", "nv" };
1542 int cond;
1543 switch (format[1]) {
1544 case 'B': cond = instr->ConditionBranch(); break;
1545 case 'I': {
1546 cond = NegateCondition(static_cast<Condition>(instr->Condition()));
1547 break;
1548 }
1549 default: cond = instr->Condition();
1550 }
1551 AppendToOutput("%s", condition_code[cond]);
1552 return 4;
1553}
1554
1555
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001556int DisassemblingDecoder::SubstitutePCRelAddressField(Instruction* instr,
1557 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001558 USE(format);
1559 DCHECK(strncmp(format, "AddrPCRel", 9) == 0);
1560
1561 int offset = instr->ImmPCRel();
1562
1563 // Only ADR (AddrPCRelByte) is supported.
1564 DCHECK(strcmp(format, "AddrPCRelByte") == 0);
1565
1566 char sign = '+';
1567 if (offset < 0) {
1568 offset = -offset;
1569 sign = '-';
1570 }
1571 AppendToOutput("#%c0x%x (addr %p)", sign, offset,
1572 instr->InstructionAtOffset(offset, Instruction::NO_CHECK));
1573 return 13;
1574}
1575
1576
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001577int DisassemblingDecoder::SubstituteBranchTargetField(Instruction* instr,
1578 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001579 DCHECK(strncmp(format, "BImm", 4) == 0);
1580
1581 int64_t offset = 0;
1582 switch (format[5]) {
1583 // BImmUncn - unconditional branch immediate.
1584 case 'n': offset = instr->ImmUncondBranch(); break;
1585 // BImmCond - conditional branch immediate.
1586 case 'o': offset = instr->ImmCondBranch(); break;
1587 // BImmCmpa - compare and branch immediate.
1588 case 'm': offset = instr->ImmCmpBranch(); break;
1589 // BImmTest - test and branch immediate.
1590 case 'e': offset = instr->ImmTestBranch(); break;
1591 default: UNREACHABLE();
1592 }
1593 offset <<= kInstructionSizeLog2;
1594 char sign = '+';
1595 if (offset < 0) {
1596 sign = '-';
1597 }
1598 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset),
1599 instr->InstructionAtOffset(offset), Instruction::NO_CHECK);
1600 return 8;
1601}
1602
1603
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001604int DisassemblingDecoder::SubstituteExtendField(Instruction* instr,
1605 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606 DCHECK(strncmp(format, "Ext", 3) == 0);
1607 DCHECK(instr->ExtendMode() <= 7);
1608 USE(format);
1609
1610 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
1611 "sxtb", "sxth", "sxtw", "sxtx" };
1612
1613 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
1614 // registers becomes lsl.
1615 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
1616 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
1617 (instr->ExtendMode() == UXTX))) {
1618 if (instr->ImmExtendShift() > 0) {
1619 AppendToOutput(", lsl #%d", instr->ImmExtendShift());
1620 }
1621 } else {
1622 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
1623 if (instr->ImmExtendShift() > 0) {
1624 AppendToOutput(" #%d", instr->ImmExtendShift());
1625 }
1626 }
1627 return 3;
1628}
1629
1630
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001631int DisassemblingDecoder::SubstituteLSRegOffsetField(Instruction* instr,
1632 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001633 DCHECK(strncmp(format, "Offsetreg", 9) == 0);
1634 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
1635 "undefined", "undefined", "sxtw", "sxtx" };
1636 USE(format);
1637
1638 unsigned shift = instr->ImmShiftLS();
1639 Extend ext = static_cast<Extend>(instr->ExtendMode());
1640 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
1641
1642 unsigned rm = instr->Rm();
1643 if (rm == kZeroRegCode) {
1644 AppendToOutput("%czr", reg_type);
1645 } else {
1646 AppendToOutput("%c%d", reg_type, rm);
1647 }
1648
1649 // Extend mode UXTX is an alias for shift mode LSL here.
1650 if (!((ext == UXTX) && (shift == 0))) {
1651 AppendToOutput(", %s", extend_mode[ext]);
1652 if (shift != 0) {
1653 AppendToOutput(" #%d", instr->SizeLS());
1654 }
1655 }
1656 return 9;
1657}
1658
1659
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001660int DisassemblingDecoder::SubstitutePrefetchField(Instruction* instr,
1661 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001662 DCHECK(format[0] == 'P');
1663 USE(format);
1664
1665 int prefetch_mode = instr->PrefetchMode();
1666
1667 const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
1668 int level = (prefetch_mode >> 1) + 1;
1669 const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
1670
1671 AppendToOutput("p%sl%d%s", ls, level, ks);
1672 return 6;
1673}
1674
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001675int DisassemblingDecoder::SubstituteBarrierField(Instruction* instr,
1676 const char* format) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001677 DCHECK(format[0] == 'M');
1678 USE(format);
1679
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001680 static const char* const options[4][4] = {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001681 { "sy (0b0000)", "oshld", "oshst", "osh" },
1682 { "sy (0b0100)", "nshld", "nshst", "nsh" },
1683 { "sy (0b1000)", "ishld", "ishst", "ish" },
1684 { "sy (0b1100)", "ld", "st", "sy" }
1685 };
1686 int domain = instr->ImmBarrierDomain();
1687 int type = instr->ImmBarrierType();
1688
1689 AppendToOutput("%s", options[domain][type]);
1690 return 1;
1691}
1692
1693
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001694void DisassemblingDecoder::ResetOutput() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001695 buffer_pos_ = 0;
1696 buffer_[buffer_pos_] = 0;
1697}
1698
1699
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001700void DisassemblingDecoder::AppendToOutput(const char* format, ...) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001701 va_list args;
1702 va_start(args, format);
1703 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
1704 va_end(args);
1705}
1706
1707
1708void PrintDisassembler::ProcessOutput(Instruction* instr) {
1709 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
1710 reinterpret_cast<uint64_t>(instr), instr->InstructionBits(),
1711 GetOutput());
1712}
1713
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001714} // namespace internal
1715} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001716
1717
1718namespace disasm {
1719
1720
1721const char* NameConverter::NameOfAddress(byte* addr) const {
1722 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1723 return tmp_buffer_.start();
1724}
1725
1726
1727const char* NameConverter::NameOfConstant(byte* addr) const {
1728 return NameOfAddress(addr);
1729}
1730
1731
1732const char* NameConverter::NameOfCPURegister(int reg) const {
1733 unsigned ureg = reg; // Avoid warnings about signed/unsigned comparisons.
1734 if (ureg >= v8::internal::kNumberOfRegisters) {
1735 return "noreg";
1736 }
1737 if (ureg == v8::internal::kZeroRegCode) {
1738 return "xzr";
1739 }
1740 v8::internal::SNPrintF(tmp_buffer_, "x%u", ureg);
1741 return tmp_buffer_.start();
1742}
1743
1744
1745const char* NameConverter::NameOfByteCPURegister(int reg) const {
1746 UNREACHABLE(); // ARM64 does not have the concept of a byte register
1747 return "nobytereg";
1748}
1749
1750
1751const char* NameConverter::NameOfXMMRegister(int reg) const {
1752 UNREACHABLE(); // ARM64 does not have any XMM registers
1753 return "noxmmreg";
1754}
1755
1756
1757const char* NameConverter::NameInCode(byte* addr) const {
1758 // The default name converter is called for unknown code, so we will not try
1759 // to access any memory.
1760 return "";
1761}
1762
1763
1764//------------------------------------------------------------------------------
1765
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001766class BufferDisassembler : public v8::internal::DisassemblingDecoder {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001767 public:
1768 explicit BufferDisassembler(v8::internal::Vector<char> out_buffer)
1769 : out_buffer_(out_buffer) { }
1770
1771 ~BufferDisassembler() { }
1772
1773 virtual void ProcessOutput(v8::internal::Instruction* instr) {
1774 v8::internal::SNPrintF(out_buffer_, "%s", GetOutput());
1775 }
1776
1777 private:
1778 v8::internal::Vector<char> out_buffer_;
1779};
1780
1781Disassembler::Disassembler(const NameConverter& converter)
1782 : converter_(converter) {}
1783
1784
1785Disassembler::~Disassembler() { USE(converter_); }
1786
1787
1788int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1789 byte* instr) {
1790 v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
1791 BufferDisassembler disasm(buffer);
1792 decoder.AppendVisitor(&disasm);
1793
1794 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(instr));
1795 return v8::internal::kInstructionSize;
1796}
1797
1798
1799int Disassembler::ConstantPoolSizeAt(byte* instr) {
1800 return v8::internal::Assembler::ConstantPoolSizeAt(
1801 reinterpret_cast<v8::internal::Instruction*>(instr));
1802}
1803
1804
1805void Disassembler::Disassemble(FILE* file, byte* start, byte* end) {
1806 v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
1807 v8::internal::PrintDisassembler disasm(file);
1808 decoder.AppendVisitor(&disasm);
1809
1810 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) {
1811 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc));
1812 }
1813}
1814
1815} // namespace disasm
1816
1817#endif // V8_TARGET_ARCH_ARM64