1 // Copyright 2015, ARM Limited
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of ARM Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #include "jit/arm64/vixl/Disasm-vixl.h"
28
29 #include "mozilla/Sprintf.h"
30 #include <cstdlib>
31
32 namespace vixl {
33
Disassembler()34 Disassembler::Disassembler() {
35 buffer_size_ = 256;
36 buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
37 buffer_pos_ = 0;
38 own_buffer_ = true;
39 code_address_offset_ = 0;
40 }
41
42
Disassembler(char * text_buffer,int buffer_size)43 Disassembler::Disassembler(char* text_buffer, int buffer_size) {
44 buffer_size_ = buffer_size;
45 buffer_ = text_buffer;
46 buffer_pos_ = 0;
47 own_buffer_ = false;
48 code_address_offset_ = 0;
49 }
50
51
~Disassembler()52 Disassembler::~Disassembler() {
53 if (own_buffer_) {
54 free(buffer_);
55 }
56 }
57
58
GetOutput()59 char* Disassembler::GetOutput() {
60 return buffer_;
61 }
62
63
VisitAddSubImmediate(const Instruction * instr)64 void Disassembler::VisitAddSubImmediate(const Instruction* instr) {
65 bool rd_is_zr = RdIsZROrSP(instr);
66 bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
67 (instr->ImmAddSub() == 0) ? true : false;
68 const char *mnemonic = "";
69 const char *form = "'Rds, 'Rns, 'IAddSub";
70 const char *form_cmp = "'Rns, 'IAddSub";
71 const char *form_mov = "'Rds, 'Rns";
72
73 switch (instr->Mask(AddSubImmediateMask)) {
74 case ADD_w_imm:
75 case ADD_x_imm: {
76 mnemonic = "add";
77 if (stack_op) {
78 mnemonic = "mov";
79 form = form_mov;
80 }
81 break;
82 }
83 case ADDS_w_imm:
84 case ADDS_x_imm: {
85 mnemonic = "adds";
86 if (rd_is_zr) {
87 mnemonic = "cmn";
88 form = form_cmp;
89 }
90 break;
91 }
92 case SUB_w_imm:
93 case SUB_x_imm: mnemonic = "sub"; break;
94 case SUBS_w_imm:
95 case SUBS_x_imm: {
96 mnemonic = "subs";
97 if (rd_is_zr) {
98 mnemonic = "cmp";
99 form = form_cmp;
100 }
101 break;
102 }
103 default: VIXL_UNREACHABLE();
104 }
105 Format(instr, mnemonic, form);
106 }
107
108
VisitAddSubShifted(const Instruction * instr)109 void Disassembler::VisitAddSubShifted(const Instruction* instr) {
110 bool rd_is_zr = RdIsZROrSP(instr);
111 bool rn_is_zr = RnIsZROrSP(instr);
112 const char *mnemonic = "";
113 const char *form = "'Rd, 'Rn, 'Rm'NDP";
114 const char *form_cmp = "'Rn, 'Rm'NDP";
115 const char *form_neg = "'Rd, 'Rm'NDP";
116
117 switch (instr->Mask(AddSubShiftedMask)) {
118 case ADD_w_shift:
119 case ADD_x_shift: mnemonic = "add"; break;
120 case ADDS_w_shift:
121 case ADDS_x_shift: {
122 mnemonic = "adds";
123 if (rd_is_zr) {
124 mnemonic = "cmn";
125 form = form_cmp;
126 }
127 break;
128 }
129 case SUB_w_shift:
130 case SUB_x_shift: {
131 mnemonic = "sub";
132 if (rn_is_zr) {
133 mnemonic = "neg";
134 form = form_neg;
135 }
136 break;
137 }
138 case SUBS_w_shift:
139 case SUBS_x_shift: {
140 mnemonic = "subs";
141 if (rd_is_zr) {
142 mnemonic = "cmp";
143 form = form_cmp;
144 } else if (rn_is_zr) {
145 mnemonic = "negs";
146 form = form_neg;
147 }
148 break;
149 }
150 default: VIXL_UNREACHABLE();
151 }
152 Format(instr, mnemonic, form);
153 }
154
155
VisitAddSubExtended(const Instruction * instr)156 void Disassembler::VisitAddSubExtended(const Instruction* instr) {
157 bool rd_is_zr = RdIsZROrSP(instr);
158 const char *mnemonic = "";
159 Extend mode = static_cast<Extend>(instr->ExtendMode());
160 const char *form = ((mode == UXTX) || (mode == SXTX)) ?
161 "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
162 const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
163 "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
164
165 switch (instr->Mask(AddSubExtendedMask)) {
166 case ADD_w_ext:
167 case ADD_x_ext: mnemonic = "add"; break;
168 case ADDS_w_ext:
169 case ADDS_x_ext: {
170 mnemonic = "adds";
171 if (rd_is_zr) {
172 mnemonic = "cmn";
173 form = form_cmp;
174 }
175 break;
176 }
177 case SUB_w_ext:
178 case SUB_x_ext: mnemonic = "sub"; break;
179 case SUBS_w_ext:
180 case SUBS_x_ext: {
181 mnemonic = "subs";
182 if (rd_is_zr) {
183 mnemonic = "cmp";
184 form = form_cmp;
185 }
186 break;
187 }
188 default: VIXL_UNREACHABLE();
189 }
190 Format(instr, mnemonic, form);
191 }
192
193
VisitAddSubWithCarry(const Instruction * instr)194 void Disassembler::VisitAddSubWithCarry(const Instruction* instr) {
195 bool rn_is_zr = RnIsZROrSP(instr);
196 const char *mnemonic = "";
197 const char *form = "'Rd, 'Rn, 'Rm";
198 const char *form_neg = "'Rd, 'Rm";
199
200 switch (instr->Mask(AddSubWithCarryMask)) {
201 case ADC_w:
202 case ADC_x: mnemonic = "adc"; break;
203 case ADCS_w:
204 case ADCS_x: mnemonic = "adcs"; break;
205 case SBC_w:
206 case SBC_x: {
207 mnemonic = "sbc";
208 if (rn_is_zr) {
209 mnemonic = "ngc";
210 form = form_neg;
211 }
212 break;
213 }
214 case SBCS_w:
215 case SBCS_x: {
216 mnemonic = "sbcs";
217 if (rn_is_zr) {
218 mnemonic = "ngcs";
219 form = form_neg;
220 }
221 break;
222 }
223 default: VIXL_UNREACHABLE();
224 }
225 Format(instr, mnemonic, form);
226 }
227
228
VisitLogicalImmediate(const Instruction * instr)229 void Disassembler::VisitLogicalImmediate(const Instruction* instr) {
230 bool rd_is_zr = RdIsZROrSP(instr);
231 bool rn_is_zr = RnIsZROrSP(instr);
232 const char *mnemonic = "";
233 const char *form = "'Rds, 'Rn, 'ITri";
234
235 if (instr->ImmLogical() == 0) {
236 // The immediate encoded in the instruction is not in the expected format.
237 Format(instr, "unallocated", "(LogicalImmediate)");
238 return;
239 }
240
241 switch (instr->Mask(LogicalImmediateMask)) {
242 case AND_w_imm:
243 case AND_x_imm: mnemonic = "and"; break;
244 case ORR_w_imm:
245 case ORR_x_imm: {
246 mnemonic = "orr";
247 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize
248 : kWRegSize;
249 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
250 mnemonic = "mov";
251 form = "'Rds, 'ITri";
252 }
253 break;
254 }
255 case EOR_w_imm:
256 case EOR_x_imm: mnemonic = "eor"; break;
257 case ANDS_w_imm:
258 case ANDS_x_imm: {
259 mnemonic = "ands";
260 if (rd_is_zr) {
261 mnemonic = "tst";
262 form = "'Rn, 'ITri";
263 }
264 break;
265 }
266 default: VIXL_UNREACHABLE();
267 }
268 Format(instr, mnemonic, form);
269 }
270
271
IsMovzMovnImm(unsigned reg_size,uint64_t value)272 bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
273 VIXL_ASSERT((reg_size == kXRegSize) ||
274 ((reg_size == kWRegSize) && (value <= 0xffffffff)));
275
276 // Test for movz: 16 bits set at positions 0, 16, 32 or 48.
277 if (((value & UINT64_C(0xffffffffffff0000)) == 0) ||
278 ((value & UINT64_C(0xffffffff0000ffff)) == 0) ||
279 ((value & UINT64_C(0xffff0000ffffffff)) == 0) ||
280 ((value & UINT64_C(0x0000ffffffffffff)) == 0)) {
281 return true;
282 }
283
284 // Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
285 if ((reg_size == kXRegSize) &&
286 (((~value & UINT64_C(0xffffffffffff0000)) == 0) ||
287 ((~value & UINT64_C(0xffffffff0000ffff)) == 0) ||
288 ((~value & UINT64_C(0xffff0000ffffffff)) == 0) ||
289 ((~value & UINT64_C(0x0000ffffffffffff)) == 0))) {
290 return true;
291 }
292 if ((reg_size == kWRegSize) &&
293 (((value & 0xffff0000) == 0xffff0000) ||
294 ((value & 0x0000ffff) == 0x0000ffff))) {
295 return true;
296 }
297 return false;
298 }
299
300
VisitLogicalShifted(const Instruction * instr)301 void Disassembler::VisitLogicalShifted(const Instruction* instr) {
302 bool rd_is_zr = RdIsZROrSP(instr);
303 bool rn_is_zr = RnIsZROrSP(instr);
304 const char *mnemonic = "";
305 const char *form = "'Rd, 'Rn, 'Rm'NLo";
306
307 switch (instr->Mask(LogicalShiftedMask)) {
308 case AND_w:
309 case AND_x: mnemonic = "and"; break;
310 case BIC_w:
311 case BIC_x: mnemonic = "bic"; break;
312 case EOR_w:
313 case EOR_x: mnemonic = "eor"; break;
314 case EON_w:
315 case EON_x: mnemonic = "eon"; break;
316 case BICS_w:
317 case BICS_x: mnemonic = "bics"; break;
318 case ANDS_w:
319 case ANDS_x: {
320 mnemonic = "ands";
321 if (rd_is_zr) {
322 mnemonic = "tst";
323 form = "'Rn, 'Rm'NLo";
324 }
325 break;
326 }
327 case ORR_w:
328 case ORR_x: {
329 mnemonic = "orr";
330 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
331 mnemonic = "mov";
332 form = "'Rd, 'Rm";
333 }
334 break;
335 }
336 case ORN_w:
337 case ORN_x: {
338 mnemonic = "orn";
339 if (rn_is_zr) {
340 mnemonic = "mvn";
341 form = "'Rd, 'Rm'NLo";
342 }
343 break;
344 }
345 default: VIXL_UNREACHABLE();
346 }
347
348 Format(instr, mnemonic, form);
349 }
350
351
VisitConditionalCompareRegister(const Instruction * instr)352 void Disassembler::VisitConditionalCompareRegister(const Instruction* instr) {
353 const char *mnemonic = "";
354 const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
355
356 switch (instr->Mask(ConditionalCompareRegisterMask)) {
357 case CCMN_w:
358 case CCMN_x: mnemonic = "ccmn"; break;
359 case CCMP_w:
360 case CCMP_x: mnemonic = "ccmp"; break;
361 default: VIXL_UNREACHABLE();
362 }
363 Format(instr, mnemonic, form);
364 }
365
366
VisitConditionalCompareImmediate(const Instruction * instr)367 void Disassembler::VisitConditionalCompareImmediate(const Instruction* instr) {
368 const char *mnemonic = "";
369 const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
370
371 switch (instr->Mask(ConditionalCompareImmediateMask)) {
372 case CCMN_w_imm:
373 case CCMN_x_imm: mnemonic = "ccmn"; break;
374 case CCMP_w_imm:
375 case CCMP_x_imm: mnemonic = "ccmp"; break;
376 default: VIXL_UNREACHABLE();
377 }
378 Format(instr, mnemonic, form);
379 }
380
381
VisitConditionalSelect(const Instruction * instr)382 void Disassembler::VisitConditionalSelect(const Instruction* instr) {
383 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
384 bool rn_is_rm = (instr->Rn() == instr->Rm());
385 const char *mnemonic = "";
386 const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
387 const char *form_test = "'Rd, 'CInv";
388 const char *form_update = "'Rd, 'Rn, 'CInv";
389
390 Condition cond = static_cast<Condition>(instr->Condition());
391 bool invertible_cond = (cond != al) && (cond != nv);
392
393 switch (instr->Mask(ConditionalSelectMask)) {
394 case CSEL_w:
395 case CSEL_x: mnemonic = "csel"; break;
396 case CSINC_w:
397 case CSINC_x: {
398 mnemonic = "csinc";
399 if (rnm_is_zr && invertible_cond) {
400 mnemonic = "cset";
401 form = form_test;
402 } else if (rn_is_rm && invertible_cond) {
403 mnemonic = "cinc";
404 form = form_update;
405 }
406 break;
407 }
408 case CSINV_w:
409 case CSINV_x: {
410 mnemonic = "csinv";
411 if (rnm_is_zr && invertible_cond) {
412 mnemonic = "csetm";
413 form = form_test;
414 } else if (rn_is_rm && invertible_cond) {
415 mnemonic = "cinv";
416 form = form_update;
417 }
418 break;
419 }
420 case CSNEG_w:
421 case CSNEG_x: {
422 mnemonic = "csneg";
423 if (rn_is_rm && invertible_cond) {
424 mnemonic = "cneg";
425 form = form_update;
426 }
427 break;
428 }
429 default: VIXL_UNREACHABLE();
430 }
431 Format(instr, mnemonic, form);
432 }
433
434
VisitBitfield(const Instruction * instr)435 void Disassembler::VisitBitfield(const Instruction* instr) {
436 unsigned s = instr->ImmS();
437 unsigned r = instr->ImmR();
438 unsigned rd_size_minus_1 =
439 ((instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize) - 1;
440 const char *mnemonic = "";
441 const char *form = "";
442 const char *form_shift_right = "'Rd, 'Rn, 'IBr";
443 const char *form_extend = "'Rd, 'Wn";
444 const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
445 const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
446 const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
447
448 switch (instr->Mask(BitfieldMask)) {
449 case SBFM_w:
450 case SBFM_x: {
451 mnemonic = "sbfx";
452 form = form_bfx;
453 if (r == 0) {
454 form = form_extend;
455 if (s == 7) {
456 mnemonic = "sxtb";
457 } else if (s == 15) {
458 mnemonic = "sxth";
459 } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
460 mnemonic = "sxtw";
461 } else {
462 form = form_bfx;
463 }
464 } else if (s == rd_size_minus_1) {
465 mnemonic = "asr";
466 form = form_shift_right;
467 } else if (s < r) {
468 mnemonic = "sbfiz";
469 form = form_bfiz;
470 }
471 break;
472 }
473 case UBFM_w:
474 case UBFM_x: {
475 mnemonic = "ubfx";
476 form = form_bfx;
477 if (r == 0) {
478 form = form_extend;
479 if (s == 7) {
480 mnemonic = "uxtb";
481 } else if (s == 15) {
482 mnemonic = "uxth";
483 } else {
484 form = form_bfx;
485 }
486 }
487 if (s == rd_size_minus_1) {
488 mnemonic = "lsr";
489 form = form_shift_right;
490 } else if (r == s + 1) {
491 mnemonic = "lsl";
492 form = form_lsl;
493 } else if (s < r) {
494 mnemonic = "ubfiz";
495 form = form_bfiz;
496 }
497 break;
498 }
499 case BFM_w:
500 case BFM_x: {
501 mnemonic = "bfxil";
502 form = form_bfx;
503 if (s < r) {
504 mnemonic = "bfi";
505 form = form_bfiz;
506 }
507 }
508 }
509 Format(instr, mnemonic, form);
510 }
511
512
VisitExtract(const Instruction * instr)513 void Disassembler::VisitExtract(const Instruction* instr) {
514 const char *mnemonic = "";
515 const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
516
517 switch (instr->Mask(ExtractMask)) {
518 case EXTR_w:
519 case EXTR_x: {
520 if (instr->Rn() == instr->Rm()) {
521 mnemonic = "ror";
522 form = "'Rd, 'Rn, 'IExtract";
523 } else {
524 mnemonic = "extr";
525 }
526 break;
527 }
528 default: VIXL_UNREACHABLE();
529 }
530 Format(instr, mnemonic, form);
531 }
532
533
VisitPCRelAddressing(const Instruction * instr)534 void Disassembler::VisitPCRelAddressing(const Instruction* instr) {
535 switch (instr->Mask(PCRelAddressingMask)) {
536 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
537 case ADRP: Format(instr, "adrp", "'Xd, 'AddrPCRelPage"); break;
538 default: Format(instr, "unimplemented", "(PCRelAddressing)");
539 }
540 }
541
542
VisitConditionalBranch(const Instruction * instr)543 void Disassembler::VisitConditionalBranch(const Instruction* instr) {
544 switch (instr->Mask(ConditionalBranchMask)) {
545 case B_cond: Format(instr, "b.'CBrn", "'TImmCond"); break;
546 default: VIXL_UNREACHABLE();
547 }
548 }
549
550
VisitUnconditionalBranchToRegister(const Instruction * instr)551 void Disassembler::VisitUnconditionalBranchToRegister(
552 const Instruction* instr) {
553 const char *mnemonic = "unimplemented";
554 const char *form = "'Xn";
555
556 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
557 case BR: mnemonic = "br"; break;
558 case BLR: mnemonic = "blr"; break;
559 case RET: {
560 mnemonic = "ret";
561 if (instr->Rn() == kLinkRegCode) {
562 form = NULL;
563 }
564 break;
565 }
566 default: form = "(UnconditionalBranchToRegister)";
567 }
568 Format(instr, mnemonic, form);
569 }
570
571
VisitUnconditionalBranch(const Instruction * instr)572 void Disassembler::VisitUnconditionalBranch(const Instruction* instr) {
573 const char *mnemonic = "";
574 const char *form = "'TImmUncn";
575
576 switch (instr->Mask(UnconditionalBranchMask)) {
577 case B: mnemonic = "b"; break;
578 case BL: mnemonic = "bl"; break;
579 default: VIXL_UNREACHABLE();
580 }
581 Format(instr, mnemonic, form);
582 }
583
584
VisitDataProcessing1Source(const Instruction * instr)585 void Disassembler::VisitDataProcessing1Source(const Instruction* instr) {
586 const char *mnemonic = "";
587 const char *form = "'Rd, 'Rn";
588
589 switch (instr->Mask(DataProcessing1SourceMask)) {
590 #define FORMAT(A, B) \
591 case A##_w: \
592 case A##_x: mnemonic = B; break;
593 FORMAT(RBIT, "rbit");
594 FORMAT(REV16, "rev16");
595 FORMAT(REV, "rev");
596 FORMAT(CLZ, "clz");
597 FORMAT(CLS, "cls");
598 #undef FORMAT
599 case REV32_x: mnemonic = "rev32"; break;
600 default: VIXL_UNREACHABLE();
601 }
602 Format(instr, mnemonic, form);
603 }
604
605
VisitDataProcessing2Source(const Instruction * instr)606 void Disassembler::VisitDataProcessing2Source(const Instruction* instr) {
607 const char *mnemonic = "unimplemented";
608 const char *form = "'Rd, 'Rn, 'Rm";
609 const char *form_wwx = "'Wd, 'Wn, 'Xm";
610
611 switch (instr->Mask(DataProcessing2SourceMask)) {
612 #define FORMAT(A, B) \
613 case A##_w: \
614 case A##_x: mnemonic = B; break;
615 FORMAT(UDIV, "udiv");
616 FORMAT(SDIV, "sdiv");
617 FORMAT(LSLV, "lsl");
618 FORMAT(LSRV, "lsr");
619 FORMAT(ASRV, "asr");
620 FORMAT(RORV, "ror");
621 #undef FORMAT
622 case CRC32B: mnemonic = "crc32b"; break;
623 case CRC32H: mnemonic = "crc32h"; break;
624 case CRC32W: mnemonic = "crc32w"; break;
625 case CRC32X: mnemonic = "crc32x"; form = form_wwx; break;
626 case CRC32CB: mnemonic = "crc32cb"; break;
627 case CRC32CH: mnemonic = "crc32ch"; break;
628 case CRC32CW: mnemonic = "crc32cw"; break;
629 case CRC32CX: mnemonic = "crc32cx"; form = form_wwx; break;
630 default: form = "(DataProcessing2Source)";
631 }
632 Format(instr, mnemonic, form);
633 }
634
635
VisitDataProcessing3Source(const Instruction * instr)636 void Disassembler::VisitDataProcessing3Source(const Instruction* instr) {
637 bool ra_is_zr = RaIsZROrSP(instr);
638 const char *mnemonic = "";
639 const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
640 const char *form_rrr = "'Rd, 'Rn, 'Rm";
641 const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
642 const char *form_xww = "'Xd, 'Wn, 'Wm";
643 const char *form_xxx = "'Xd, 'Xn, 'Xm";
644
645 switch (instr->Mask(DataProcessing3SourceMask)) {
646 case MADD_w:
647 case MADD_x: {
648 mnemonic = "madd";
649 form = form_rrrr;
650 if (ra_is_zr) {
651 mnemonic = "mul";
652 form = form_rrr;
653 }
654 break;
655 }
656 case MSUB_w:
657 case MSUB_x: {
658 mnemonic = "msub";
659 form = form_rrrr;
660 if (ra_is_zr) {
661 mnemonic = "mneg";
662 form = form_rrr;
663 }
664 break;
665 }
666 case SMADDL_x: {
667 mnemonic = "smaddl";
668 if (ra_is_zr) {
669 mnemonic = "smull";
670 form = form_xww;
671 }
672 break;
673 }
674 case SMSUBL_x: {
675 mnemonic = "smsubl";
676 if (ra_is_zr) {
677 mnemonic = "smnegl";
678 form = form_xww;
679 }
680 break;
681 }
682 case UMADDL_x: {
683 mnemonic = "umaddl";
684 if (ra_is_zr) {
685 mnemonic = "umull";
686 form = form_xww;
687 }
688 break;
689 }
690 case UMSUBL_x: {
691 mnemonic = "umsubl";
692 if (ra_is_zr) {
693 mnemonic = "umnegl";
694 form = form_xww;
695 }
696 break;
697 }
698 case SMULH_x: {
699 mnemonic = "smulh";
700 form = form_xxx;
701 break;
702 }
703 case UMULH_x: {
704 mnemonic = "umulh";
705 form = form_xxx;
706 break;
707 }
708 default: VIXL_UNREACHABLE();
709 }
710 Format(instr, mnemonic, form);
711 }
712
713
VisitCompareBranch(const Instruction * instr)714 void Disassembler::VisitCompareBranch(const Instruction* instr) {
715 const char *mnemonic = "";
716 const char *form = "'Rt, 'TImmCmpa";
717
718 switch (instr->Mask(CompareBranchMask)) {
719 case CBZ_w:
720 case CBZ_x: mnemonic = "cbz"; break;
721 case CBNZ_w:
722 case CBNZ_x: mnemonic = "cbnz"; break;
723 default: VIXL_UNREACHABLE();
724 }
725 Format(instr, mnemonic, form);
726 }
727
728
VisitTestBranch(const Instruction * instr)729 void Disassembler::VisitTestBranch(const Instruction* instr) {
730 const char *mnemonic = "";
731 // If the top bit of the immediate is clear, the tested register is
732 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
733 // encoded in bit 31 of the instruction, we can reuse the Rt form, which
734 // uses bit 31 (normally "sf") to choose the register size.
735 const char *form = "'Rt, 'IS, 'TImmTest";
736
737 switch (instr->Mask(TestBranchMask)) {
738 case TBZ: mnemonic = "tbz"; break;
739 case TBNZ: mnemonic = "tbnz"; break;
740 default: VIXL_UNREACHABLE();
741 }
742 Format(instr, mnemonic, form);
743 }
744
745
VisitMoveWideImmediate(const Instruction * instr)746 void Disassembler::VisitMoveWideImmediate(const Instruction* instr) {
747 const char *mnemonic = "";
748 const char *form = "'Rd, 'IMoveImm";
749
750 // Print the shift separately for movk, to make it clear which half word will
751 // be overwritten. Movn and movz print the computed immediate, which includes
752 // shift calculation.
753 switch (instr->Mask(MoveWideImmediateMask)) {
754 case MOVN_w:
755 case MOVN_x:
756 if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) {
757 if ((instr->SixtyFourBits() == 0) && (instr->ImmMoveWide() == 0xffff)) {
758 mnemonic = "movn";
759 } else {
760 mnemonic = "mov";
761 form = "'Rd, 'IMoveNeg";
762 }
763 } else {
764 mnemonic = "movn";
765 }
766 break;
767 case MOVZ_w:
768 case MOVZ_x:
769 if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0))
770 mnemonic = "mov";
771 else
772 mnemonic = "movz";
773 break;
774 case MOVK_w:
775 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
776 default: VIXL_UNREACHABLE();
777 }
778 Format(instr, mnemonic, form);
779 }
780
781
782 #define LOAD_STORE_LIST(V) \
783 V(STRB_w, "strb", "'Wt") \
784 V(STRH_w, "strh", "'Wt") \
785 V(STR_w, "str", "'Wt") \
786 V(STR_x, "str", "'Xt") \
787 V(LDRB_w, "ldrb", "'Wt") \
788 V(LDRH_w, "ldrh", "'Wt") \
789 V(LDR_w, "ldr", "'Wt") \
790 V(LDR_x, "ldr", "'Xt") \
791 V(LDRSB_x, "ldrsb", "'Xt") \
792 V(LDRSH_x, "ldrsh", "'Xt") \
793 V(LDRSW_x, "ldrsw", "'Xt") \
794 V(LDRSB_w, "ldrsb", "'Wt") \
795 V(LDRSH_w, "ldrsh", "'Wt") \
796 V(STR_b, "str", "'Bt") \
797 V(STR_h, "str", "'Ht") \
798 V(STR_s, "str", "'St") \
799 V(STR_d, "str", "'Dt") \
800 V(LDR_b, "ldr", "'Bt") \
801 V(LDR_h, "ldr", "'Ht") \
802 V(LDR_s, "ldr", "'St") \
803 V(LDR_d, "ldr", "'Dt") \
804 V(STR_q, "str", "'Qt") \
805 V(LDR_q, "ldr", "'Qt")
806
VisitLoadStorePreIndex(const Instruction * instr)807 void Disassembler::VisitLoadStorePreIndex(const Instruction* instr) {
808 const char *mnemonic = "unimplemented";
809 const char *form = "(LoadStorePreIndex)";
810
811 switch (instr->Mask(LoadStorePreIndexMask)) {
812 #define LS_PREINDEX(A, B, C) \
813 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
814 LOAD_STORE_LIST(LS_PREINDEX)
815 #undef LS_PREINDEX
816 }
817 Format(instr, mnemonic, form);
818 }
819
820
VisitLoadStorePostIndex(const Instruction * instr)821 void Disassembler::VisitLoadStorePostIndex(const Instruction* instr) {
822 const char *mnemonic = "unimplemented";
823 const char *form = "(LoadStorePostIndex)";
824
825 switch (instr->Mask(LoadStorePostIndexMask)) {
826 #define LS_POSTINDEX(A, B, C) \
827 case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
828 LOAD_STORE_LIST(LS_POSTINDEX)
829 #undef LS_POSTINDEX
830 }
831 Format(instr, mnemonic, form);
832 }
833
834
VisitLoadStoreUnsignedOffset(const Instruction * instr)835 void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
836 const char *mnemonic = "unimplemented";
837 const char *form = "(LoadStoreUnsignedOffset)";
838
839 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
840 #define LS_UNSIGNEDOFFSET(A, B, C) \
841 case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
842 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
843 #undef LS_UNSIGNEDOFFSET
844 case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xns'ILU]";
845 }
846 Format(instr, mnemonic, form);
847 }
848
849
VisitLoadStoreRegisterOffset(const Instruction * instr)850 void Disassembler::VisitLoadStoreRegisterOffset(const Instruction* instr) {
851 const char *mnemonic = "unimplemented";
852 const char *form = "(LoadStoreRegisterOffset)";
853
854 switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
855 #define LS_REGISTEROFFSET(A, B, C) \
856 case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
857 LOAD_STORE_LIST(LS_REGISTEROFFSET)
858 #undef LS_REGISTEROFFSET
859 case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
860 }
861 Format(instr, mnemonic, form);
862 }
863
864
VisitLoadStoreUnscaledOffset(const Instruction * instr)865 void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
866 const char *mnemonic = "unimplemented";
867 const char *form = "'Wt, ['Xns'ILS]";
868 const char *form_x = "'Xt, ['Xns'ILS]";
869 const char *form_b = "'Bt, ['Xns'ILS]";
870 const char *form_h = "'Ht, ['Xns'ILS]";
871 const char *form_s = "'St, ['Xns'ILS]";
872 const char *form_d = "'Dt, ['Xns'ILS]";
873 const char *form_q = "'Qt, ['Xns'ILS]";
874 const char *form_prefetch = "'PrefOp, ['Xns'ILS]";
875
876 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
877 case STURB_w: mnemonic = "sturb"; break;
878 case STURH_w: mnemonic = "sturh"; break;
879 case STUR_w: mnemonic = "stur"; break;
880 case STUR_x: mnemonic = "stur"; form = form_x; break;
881 case STUR_b: mnemonic = "stur"; form = form_b; break;
882 case STUR_h: mnemonic = "stur"; form = form_h; break;
883 case STUR_s: mnemonic = "stur"; form = form_s; break;
884 case STUR_d: mnemonic = "stur"; form = form_d; break;
885 case STUR_q: mnemonic = "stur"; form = form_q; break;
886 case LDURB_w: mnemonic = "ldurb"; break;
887 case LDURH_w: mnemonic = "ldurh"; break;
888 case LDUR_w: mnemonic = "ldur"; break;
889 case LDUR_x: mnemonic = "ldur"; form = form_x; break;
890 case LDUR_b: mnemonic = "ldur"; form = form_b; break;
891 case LDUR_h: mnemonic = "ldur"; form = form_h; break;
892 case LDUR_s: mnemonic = "ldur"; form = form_s; break;
893 case LDUR_d: mnemonic = "ldur"; form = form_d; break;
894 case LDUR_q: mnemonic = "ldur"; form = form_q; break;
895 case LDURSB_x: form = form_x; VIXL_FALLTHROUGH();
896 case LDURSB_w: mnemonic = "ldursb"; break;
897 case LDURSH_x: form = form_x; VIXL_FALLTHROUGH();
898 case LDURSH_w: mnemonic = "ldursh"; break;
899 case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
900 case PRFUM: mnemonic = "prfum"; form = form_prefetch; break;
901 default: form = "(LoadStoreUnscaledOffset)";
902 }
903 Format(instr, mnemonic, form);
904 }
905
906
VisitLoadLiteral(const Instruction * instr)907 void Disassembler::VisitLoadLiteral(const Instruction* instr) {
908 const char *mnemonic = "ldr";
909 const char *form = "(LoadLiteral)";
910
911 switch (instr->Mask(LoadLiteralMask)) {
912 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
913 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
914 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
915 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
916 case LDR_q_lit: form = "'Qt, 'ILLiteral 'LValue"; break;
917 case LDRSW_x_lit: {
918 mnemonic = "ldrsw";
919 form = "'Xt, 'ILLiteral 'LValue";
920 break;
921 }
922 case PRFM_lit: {
923 mnemonic = "prfm";
924 form = "'PrefOp, 'ILLiteral 'LValue";
925 break;
926 }
927 default: mnemonic = "unimplemented";
928 }
929 Format(instr, mnemonic, form);
930 }
931
932
933 #define LOAD_STORE_PAIR_LIST(V) \
934 V(STP_w, "stp", "'Wt, 'Wt2", "2") \
935 V(LDP_w, "ldp", "'Wt, 'Wt2", "2") \
936 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "2") \
937 V(STP_x, "stp", "'Xt, 'Xt2", "3") \
938 V(LDP_x, "ldp", "'Xt, 'Xt2", "3") \
939 V(STP_s, "stp", "'St, 'St2", "2") \
940 V(LDP_s, "ldp", "'St, 'St2", "2") \
941 V(STP_d, "stp", "'Dt, 'Dt2", "3") \
942 V(LDP_d, "ldp", "'Dt, 'Dt2", "3") \
943 V(LDP_q, "ldp", "'Qt, 'Qt2", "4") \
944 V(STP_q, "stp", "'Qt, 'Qt2", "4")
945
VisitLoadStorePairPostIndex(const Instruction * instr)946 void Disassembler::VisitLoadStorePairPostIndex(const Instruction* instr) {
947 const char *mnemonic = "unimplemented";
948 const char *form = "(LoadStorePairPostIndex)";
949
950 switch (instr->Mask(LoadStorePairPostIndexMask)) {
951 #define LSP_POSTINDEX(A, B, C, D) \
952 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
953 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
954 #undef LSP_POSTINDEX
955 }
956 Format(instr, mnemonic, form);
957 }
958
959
VisitLoadStorePairPreIndex(const Instruction * instr)960 void Disassembler::VisitLoadStorePairPreIndex(const Instruction* instr) {
961 const char *mnemonic = "unimplemented";
962 const char *form = "(LoadStorePairPreIndex)";
963
964 switch (instr->Mask(LoadStorePairPreIndexMask)) {
965 #define LSP_PREINDEX(A, B, C, D) \
966 case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
967 LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
968 #undef LSP_PREINDEX
969 }
970 Format(instr, mnemonic, form);
971 }
972
973
VisitLoadStorePairOffset(const Instruction * instr)974 void Disassembler::VisitLoadStorePairOffset(const Instruction* instr) {
975 const char *mnemonic = "unimplemented";
976 const char *form = "(LoadStorePairOffset)";
977
978 switch (instr->Mask(LoadStorePairOffsetMask)) {
979 #define LSP_OFFSET(A, B, C, D) \
980 case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
981 LOAD_STORE_PAIR_LIST(LSP_OFFSET)
982 #undef LSP_OFFSET
983 }
984 Format(instr, mnemonic, form);
985 }
986
987
VisitLoadStorePairNonTemporal(const Instruction * instr)988 void Disassembler::VisitLoadStorePairNonTemporal(const Instruction* instr) {
989 const char *mnemonic = "unimplemented";
990 const char *form;
991
992 switch (instr->Mask(LoadStorePairNonTemporalMask)) {
993 case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP2]"; break;
994 case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP2]"; break;
995 case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP3]"; break;
996 case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP3]"; break;
997 case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP2]"; break;
998 case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP2]"; break;
999 case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP3]"; break;
1000 case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP3]"; break;
1001 case STNP_q: mnemonic = "stnp"; form = "'Qt, 'Qt2, ['Xns'ILP4]"; break;
1002 case LDNP_q: mnemonic = "ldnp"; form = "'Qt, 'Qt2, ['Xns'ILP4]"; break;
1003 default: form = "(LoadStorePairNonTemporal)";
1004 }
1005 Format(instr, mnemonic, form);
1006 }
1007
1008
VisitLoadStoreExclusive(const Instruction * instr)1009 void Disassembler::VisitLoadStoreExclusive(const Instruction* instr) {
1010 const char *mnemonic = "unimplemented";
1011 const char *form;
1012
1013 switch (instr->Mask(LoadStoreExclusiveMask)) {
1014 case STXRB_w: mnemonic = "stxrb"; form = "'Ws, 'Wt, ['Xns]"; break;
1015 case STXRH_w: mnemonic = "stxrh"; form = "'Ws, 'Wt, ['Xns]"; break;
1016 case STXR_w: mnemonic = "stxr"; form = "'Ws, 'Wt, ['Xns]"; break;
1017 case STXR_x: mnemonic = "stxr"; form = "'Ws, 'Xt, ['Xns]"; break;
1018 case LDXRB_w: mnemonic = "ldxrb"; form = "'Wt, ['Xns]"; break;
1019 case LDXRH_w: mnemonic = "ldxrh"; form = "'Wt, ['Xns]"; break;
1020 case LDXR_w: mnemonic = "ldxr"; form = "'Wt, ['Xns]"; break;
1021 case LDXR_x: mnemonic = "ldxr"; form = "'Xt, ['Xns]"; break;
1022 case STXP_w: mnemonic = "stxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
1023 case STXP_x: mnemonic = "stxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
1024 case LDXP_w: mnemonic = "ldxp"; form = "'Wt, 'Wt2, ['Xns]"; break;
1025 case LDXP_x: mnemonic = "ldxp"; form = "'Xt, 'Xt2, ['Xns]"; break;
1026 case STLXRB_w: mnemonic = "stlxrb"; form = "'Ws, 'Wt, ['Xns]"; break;
1027 case STLXRH_w: mnemonic = "stlxrh"; form = "'Ws, 'Wt, ['Xns]"; break;
1028 case STLXR_w: mnemonic = "stlxr"; form = "'Ws, 'Wt, ['Xns]"; break;
1029 case STLXR_x: mnemonic = "stlxr"; form = "'Ws, 'Xt, ['Xns]"; break;
1030 case LDAXRB_w: mnemonic = "ldaxrb"; form = "'Wt, ['Xns]"; break;
1031 case LDAXRH_w: mnemonic = "ldaxrh"; form = "'Wt, ['Xns]"; break;
1032 case LDAXR_w: mnemonic = "ldaxr"; form = "'Wt, ['Xns]"; break;
1033 case LDAXR_x: mnemonic = "ldaxr"; form = "'Xt, ['Xns]"; break;
1034 case STLXP_w: mnemonic = "stlxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
1035 case STLXP_x: mnemonic = "stlxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
1036 case LDAXP_w: mnemonic = "ldaxp"; form = "'Wt, 'Wt2, ['Xns]"; break;
1037 case LDAXP_x: mnemonic = "ldaxp"; form = "'Xt, 'Xt2, ['Xns]"; break;
1038 case STLRB_w: mnemonic = "stlrb"; form = "'Wt, ['Xns]"; break;
1039 case STLRH_w: mnemonic = "stlrh"; form = "'Wt, ['Xns]"; break;
1040 case STLR_w: mnemonic = "stlr"; form = "'Wt, ['Xns]"; break;
1041 case STLR_x: mnemonic = "stlr"; form = "'Xt, ['Xns]"; break;
1042 case LDARB_w: mnemonic = "ldarb"; form = "'Wt, ['Xns]"; break;
1043 case LDARH_w: mnemonic = "ldarh"; form = "'Wt, ['Xns]"; break;
1044 case LDAR_w: mnemonic = "ldar"; form = "'Wt, ['Xns]"; break;
1045 case LDAR_x: mnemonic = "ldar"; form = "'Xt, ['Xns]"; break;
1046 default: form = "(LoadStoreExclusive)";
1047 }
1048 Format(instr, mnemonic, form);
1049 }
1050
1051
VisitFPCompare(const Instruction * instr)1052 void Disassembler::VisitFPCompare(const Instruction* instr) {
1053 const char *mnemonic = "unimplemented";
1054 const char *form = "'Fn, 'Fm";
1055 const char *form_zero = "'Fn, #0.0";
1056
1057 switch (instr->Mask(FPCompareMask)) {
1058 case FCMP_s_zero:
1059 case FCMP_d_zero: form = form_zero; VIXL_FALLTHROUGH();
1060 case FCMP_s:
1061 case FCMP_d: mnemonic = "fcmp"; break;
1062 case FCMPE_s_zero:
1063 case FCMPE_d_zero: form = form_zero; VIXL_FALLTHROUGH();
1064 case FCMPE_s:
1065 case FCMPE_d: mnemonic = "fcmpe"; break;
1066 default: form = "(FPCompare)";
1067 }
1068 Format(instr, mnemonic, form);
1069 }
1070
1071
VisitFPConditionalCompare(const Instruction * instr)1072 void Disassembler::VisitFPConditionalCompare(const Instruction* instr) {
1073 const char *mnemonic = "unmplemented";
1074 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
1075
1076 switch (instr->Mask(FPConditionalCompareMask)) {
1077 case FCCMP_s:
1078 case FCCMP_d: mnemonic = "fccmp"; break;
1079 case FCCMPE_s:
1080 case FCCMPE_d: mnemonic = "fccmpe"; break;
1081 default: form = "(FPConditionalCompare)";
1082 }
1083 Format(instr, mnemonic, form);
1084 }
1085
1086
VisitFPConditionalSelect(const Instruction * instr)1087 void Disassembler::VisitFPConditionalSelect(const Instruction* instr) {
1088 const char *mnemonic = "";
1089 const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
1090
1091 switch (instr->Mask(FPConditionalSelectMask)) {
1092 case FCSEL_s:
1093 case FCSEL_d: mnemonic = "fcsel"; break;
1094 default: VIXL_UNREACHABLE();
1095 }
1096 Format(instr, mnemonic, form);
1097 }
1098
1099
VisitFPDataProcessing1Source(const Instruction * instr)1100 void Disassembler::VisitFPDataProcessing1Source(const Instruction* instr) {
1101 const char *mnemonic = "unimplemented";
1102 const char *form = "'Fd, 'Fn";
1103
1104 switch (instr->Mask(FPDataProcessing1SourceMask)) {
1105 #define FORMAT(A, B) \
1106 case A##_s: \
1107 case A##_d: mnemonic = B; break;
1108 FORMAT(FMOV, "fmov");
1109 FORMAT(FABS, "fabs");
1110 FORMAT(FNEG, "fneg");
1111 FORMAT(FSQRT, "fsqrt");
1112 FORMAT(FRINTN, "frintn");
1113 FORMAT(FRINTP, "frintp");
1114 FORMAT(FRINTM, "frintm");
1115 FORMAT(FRINTZ, "frintz");
1116 FORMAT(FRINTA, "frinta");
1117 FORMAT(FRINTX, "frintx");
1118 FORMAT(FRINTI, "frinti");
1119 #undef FORMAT
1120 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
1121 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
1122 case FCVT_hs: mnemonic = "fcvt"; form = "'Hd, 'Sn"; break;
1123 case FCVT_sh: mnemonic = "fcvt"; form = "'Sd, 'Hn"; break;
1124 case FCVT_dh: mnemonic = "fcvt"; form = "'Dd, 'Hn"; break;
1125 case FCVT_hd: mnemonic = "fcvt"; form = "'Hd, 'Dn"; break;
1126 default: form = "(FPDataProcessing1Source)";
1127 }
1128 Format(instr, mnemonic, form);
1129 }
1130
1131
VisitFPDataProcessing2Source(const Instruction * instr)1132 void Disassembler::VisitFPDataProcessing2Source(const Instruction* instr) {
1133 const char *mnemonic = "";
1134 const char *form = "'Fd, 'Fn, 'Fm";
1135
1136 switch (instr->Mask(FPDataProcessing2SourceMask)) {
1137 #define FORMAT(A, B) \
1138 case A##_s: \
1139 case A##_d: mnemonic = B; break;
1140 FORMAT(FMUL, "fmul");
1141 FORMAT(FDIV, "fdiv");
1142 FORMAT(FADD, "fadd");
1143 FORMAT(FSUB, "fsub");
1144 FORMAT(FMAX, "fmax");
1145 FORMAT(FMIN, "fmin");
1146 FORMAT(FMAXNM, "fmaxnm");
1147 FORMAT(FMINNM, "fminnm");
1148 FORMAT(FNMUL, "fnmul");
1149 #undef FORMAT
1150 default: VIXL_UNREACHABLE();
1151 }
1152 Format(instr, mnemonic, form);
1153 }
1154
1155
VisitFPDataProcessing3Source(const Instruction * instr)1156 void Disassembler::VisitFPDataProcessing3Source(const Instruction* instr) {
1157 const char *mnemonic = "";
1158 const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1159
1160 switch (instr->Mask(FPDataProcessing3SourceMask)) {
1161 #define FORMAT(A, B) \
1162 case A##_s: \
1163 case A##_d: mnemonic = B; break;
1164 FORMAT(FMADD, "fmadd");
1165 FORMAT(FMSUB, "fmsub");
1166 FORMAT(FNMADD, "fnmadd");
1167 FORMAT(FNMSUB, "fnmsub");
1168 #undef FORMAT
1169 default: VIXL_UNREACHABLE();
1170 }
1171 Format(instr, mnemonic, form);
1172 }
1173
1174
VisitFPImmediate(const Instruction * instr)1175 void Disassembler::VisitFPImmediate(const Instruction* instr) {
1176 const char *mnemonic = "";
1177 const char *form = "(FPImmediate)";
1178
1179 switch (instr->Mask(FPImmediateMask)) {
1180 case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1181 case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1182 default: VIXL_UNREACHABLE();
1183 }
1184 Format(instr, mnemonic, form);
1185 }
1186
1187
VisitFPIntegerConvert(const Instruction * instr)1188 void Disassembler::VisitFPIntegerConvert(const Instruction* instr) {
1189 const char *mnemonic = "unimplemented";
1190 const char *form = "(FPIntegerConvert)";
1191 const char *form_rf = "'Rd, 'Fn";
1192 const char *form_fr = "'Fd, 'Rn";
1193
1194 switch (instr->Mask(FPIntegerConvertMask)) {
1195 case FMOV_ws:
1196 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1197 case FMOV_sw:
1198 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1199 case FMOV_d1_x: mnemonic = "fmov"; form = "'Vd.D[1], 'Rn"; break;
1200 case FMOV_x_d1: mnemonic = "fmov"; form = "'Rd, 'Vn.D[1]"; break;
1201 case FCVTAS_ws:
1202 case FCVTAS_xs:
1203 case FCVTAS_wd:
1204 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
1205 case FCVTAU_ws:
1206 case FCVTAU_xs:
1207 case FCVTAU_wd:
1208 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
1209 case FCVTMS_ws:
1210 case FCVTMS_xs:
1211 case FCVTMS_wd:
1212 case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1213 case FCVTMU_ws:
1214 case FCVTMU_xs:
1215 case FCVTMU_wd:
1216 case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1217 case FCVTNS_ws:
1218 case FCVTNS_xs:
1219 case FCVTNS_wd:
1220 case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1221 case FCVTNU_ws:
1222 case FCVTNU_xs:
1223 case FCVTNU_wd:
1224 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1225 case FCVTZU_xd:
1226 case FCVTZU_ws:
1227 case FCVTZU_wd:
1228 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1229 case FCVTZS_xd:
1230 case FCVTZS_wd:
1231 case FCVTZS_xs:
1232 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1233 case FCVTPU_xd:
1234 case FCVTPU_ws:
1235 case FCVTPU_wd:
1236 case FCVTPU_xs: mnemonic = "fcvtpu"; form = form_rf; break;
1237 case FCVTPS_xd:
1238 case FCVTPS_wd:
1239 case FCVTPS_xs:
1240 case FCVTPS_ws: mnemonic = "fcvtps"; form = form_rf; break;
1241 case SCVTF_sw:
1242 case SCVTF_sx:
1243 case SCVTF_dw:
1244 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1245 case UCVTF_sw:
1246 case UCVTF_sx:
1247 case UCVTF_dw:
1248 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1249 case FJCVTZS: mnemonic = "fjcvtzs"; form = form_rf; break;
1250 }
1251 Format(instr, mnemonic, form);
1252 }
1253
1254
VisitFPFixedPointConvert(const Instruction * instr)1255 void Disassembler::VisitFPFixedPointConvert(const Instruction* instr) {
1256 const char *mnemonic = "";
1257 const char *form = "'Rd, 'Fn, 'IFPFBits";
1258 const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1259
1260 switch (instr->Mask(FPFixedPointConvertMask)) {
1261 case FCVTZS_ws_fixed:
1262 case FCVTZS_xs_fixed:
1263 case FCVTZS_wd_fixed:
1264 case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1265 case FCVTZU_ws_fixed:
1266 case FCVTZU_xs_fixed:
1267 case FCVTZU_wd_fixed:
1268 case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1269 case SCVTF_sw_fixed:
1270 case SCVTF_sx_fixed:
1271 case SCVTF_dw_fixed:
1272 case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1273 case UCVTF_sw_fixed:
1274 case UCVTF_sx_fixed:
1275 case UCVTF_dw_fixed:
1276 case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1277 default: VIXL_UNREACHABLE();
1278 }
1279 Format(instr, mnemonic, form);
1280 }
1281
1282
VisitSystem(const Instruction * instr)1283 void Disassembler::VisitSystem(const Instruction* instr) {
1284 // Some system instructions hijack their Op and Cp fields to represent a
1285 // range of immediates instead of indicating a different instruction. This
1286 // makes the decoding tricky.
1287 const char *mnemonic = "unimplemented";
1288 const char *form = "(System)";
1289
1290 if (instr->Mask(SystemExclusiveMonitorFMask) == SystemExclusiveMonitorFixed) {
1291 switch (instr->Mask(SystemExclusiveMonitorMask)) {
1292 case CLREX: {
1293 mnemonic = "clrex";
1294 form = (instr->CRm() == 0xf) ? NULL : "'IX";
1295 break;
1296 }
1297 }
1298 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1299 switch (instr->Mask(SystemSysRegMask)) {
1300 case MRS: {
1301 mnemonic = "mrs";
1302 switch (instr->ImmSystemRegister()) {
1303 case NZCV: form = "'Xt, nzcv"; break;
1304 case FPCR: form = "'Xt, fpcr"; break;
1305 default: form = "'Xt, (unknown)"; break;
1306 }
1307 break;
1308 }
1309 case MSR: {
1310 mnemonic = "msr";
1311 switch (instr->ImmSystemRegister()) {
1312 case NZCV: form = "nzcv, 'Xt"; break;
1313 case FPCR: form = "fpcr, 'Xt"; break;
1314 default: form = "(unknown), 'Xt"; break;
1315 }
1316 break;
1317 }
1318 }
1319 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1320 switch (instr->ImmHint()) {
1321 case NOP: {
1322 mnemonic = "nop";
1323 form = NULL;
1324 break;
1325 }
1326 case CSDB: {
1327 mnemonic = "csdb";
1328 form = NULL;
1329 break;
1330 }
1331 }
1332 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1333 switch (instr->Mask(MemBarrierMask)) {
1334 case DMB: {
1335 mnemonic = "dmb";
1336 form = "'M";
1337 break;
1338 }
1339 case DSB: {
1340 mnemonic = "dsb";
1341 form = "'M";
1342 break;
1343 }
1344 case ISB: {
1345 mnemonic = "isb";
1346 form = NULL;
1347 break;
1348 }
1349 }
1350 } else if (instr->Mask(SystemSysFMask) == SystemSysFixed) {
1351 switch (instr->SysOp()) {
1352 case IVAU:
1353 mnemonic = "ic";
1354 form = "ivau, 'Xt";
1355 break;
1356 case CVAC:
1357 mnemonic = "dc";
1358 form = "cvac, 'Xt";
1359 break;
1360 case CVAU:
1361 mnemonic = "dc";
1362 form = "cvau, 'Xt";
1363 break;
1364 case CIVAC:
1365 mnemonic = "dc";
1366 form = "civac, 'Xt";
1367 break;
1368 case ZVA:
1369 mnemonic = "dc";
1370 form = "zva, 'Xt";
1371 break;
1372 default:
1373 mnemonic = "sys";
1374 if (instr->Rt() == 31) {
1375 form = "'G1, 'Kn, 'Km, 'G2";
1376 } else {
1377 form = "'G1, 'Kn, 'Km, 'G2, 'Xt";
1378 }
1379 break;
1380 }
1381 }
1382 Format(instr, mnemonic, form);
1383 }
1384
1385
VisitException(const Instruction * instr)1386 void Disassembler::VisitException(const Instruction* instr) {
1387 const char *mnemonic = "unimplemented";
1388 const char *form = "'IDebug";
1389
1390 switch (instr->Mask(ExceptionMask)) {
1391 case HLT: mnemonic = "hlt"; break;
1392 case BRK: mnemonic = "brk"; break;
1393 case SVC: mnemonic = "svc"; break;
1394 case HVC: mnemonic = "hvc"; break;
1395 case SMC: mnemonic = "smc"; break;
1396 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1397 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1398 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1399 default: form = "(Exception)";
1400 }
1401 Format(instr, mnemonic, form);
1402 }
1403
1404
VisitCrypto2RegSHA(const Instruction * instr)1405 void Disassembler::VisitCrypto2RegSHA(const Instruction* instr) {
1406 VisitUnimplemented(instr);
1407 }
1408
1409
VisitCrypto3RegSHA(const Instruction * instr)1410 void Disassembler::VisitCrypto3RegSHA(const Instruction* instr) {
1411 VisitUnimplemented(instr);
1412 }
1413
1414
VisitCryptoAES(const Instruction * instr)1415 void Disassembler::VisitCryptoAES(const Instruction* instr) {
1416 VisitUnimplemented(instr);
1417 }
1418
1419
VisitNEON2RegMisc(const Instruction * instr)1420 void Disassembler::VisitNEON2RegMisc(const Instruction* instr) {
1421 const char *mnemonic = "unimplemented";
1422 const char *form = "'Vd.%s, 'Vn.%s";
1423 const char *form_cmp_zero = "'Vd.%s, 'Vn.%s, #0";
1424 const char *form_fcmp_zero = "'Vd.%s, 'Vn.%s, #0.0";
1425 NEONFormatDecoder nfd(instr);
1426
1427 static const NEONFormatMap map_lp_ta = {
1428 {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}
1429 };
1430
1431 static const NEONFormatMap map_cvt_ta = {
1432 {22}, {NF_4S, NF_2D}
1433 };
1434
1435 static const NEONFormatMap map_cvt_tb = {
1436 {22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S}
1437 };
1438
1439 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) {
1440 // These instructions all use a two bit size field, except NOT and RBIT,
1441 // which use the field to encode the operation.
1442 switch (instr->Mask(NEON2RegMiscMask)) {
1443 case NEON_REV64: mnemonic = "rev64"; break;
1444 case NEON_REV32: mnemonic = "rev32"; break;
1445 case NEON_REV16: mnemonic = "rev16"; break;
1446 case NEON_SADDLP:
1447 mnemonic = "saddlp";
1448 nfd.SetFormatMap(0, &map_lp_ta);
1449 break;
1450 case NEON_UADDLP:
1451 mnemonic = "uaddlp";
1452 nfd.SetFormatMap(0, &map_lp_ta);
1453 break;
1454 case NEON_SUQADD: mnemonic = "suqadd"; break;
1455 case NEON_USQADD: mnemonic = "usqadd"; break;
1456 case NEON_CLS: mnemonic = "cls"; break;
1457 case NEON_CLZ: mnemonic = "clz"; break;
1458 case NEON_CNT: mnemonic = "cnt"; break;
1459 case NEON_SADALP:
1460 mnemonic = "sadalp";
1461 nfd.SetFormatMap(0, &map_lp_ta);
1462 break;
1463 case NEON_UADALP:
1464 mnemonic = "uadalp";
1465 nfd.SetFormatMap(0, &map_lp_ta);
1466 break;
1467 case NEON_SQABS: mnemonic = "sqabs"; break;
1468 case NEON_SQNEG: mnemonic = "sqneg"; break;
1469 case NEON_CMGT_zero: mnemonic = "cmgt"; form = form_cmp_zero; break;
1470 case NEON_CMGE_zero: mnemonic = "cmge"; form = form_cmp_zero; break;
1471 case NEON_CMEQ_zero: mnemonic = "cmeq"; form = form_cmp_zero; break;
1472 case NEON_CMLE_zero: mnemonic = "cmle"; form = form_cmp_zero; break;
1473 case NEON_CMLT_zero: mnemonic = "cmlt"; form = form_cmp_zero; break;
1474 case NEON_ABS: mnemonic = "abs"; break;
1475 case NEON_NEG: mnemonic = "neg"; break;
1476 case NEON_RBIT_NOT:
1477 switch (instr->FPType()) {
1478 case 0: mnemonic = "mvn"; break;
1479 case 1: mnemonic = "rbit"; break;
1480 default: form = "(NEON2RegMisc)";
1481 }
1482 nfd.SetFormatMaps(nfd.LogicalFormatMap());
1483 break;
1484 }
1485 } else {
1486 // These instructions all use a one bit size field, except XTN, SQXTUN,
1487 // SHLL, SQXTN and UQXTN, which use a two bit size field.
1488 nfd.SetFormatMaps(nfd.FPFormatMap());
1489 switch (instr->Mask(NEON2RegMiscFPMask)) {
1490 case NEON_FABS: mnemonic = "fabs"; break;
1491 case NEON_FNEG: mnemonic = "fneg"; break;
1492 case NEON_FCVTN:
1493 mnemonic = instr->Mask(NEON_Q) ? "fcvtn2" : "fcvtn";
1494 nfd.SetFormatMap(0, &map_cvt_tb);
1495 nfd.SetFormatMap(1, &map_cvt_ta);
1496 break;
1497 case NEON_FCVTXN:
1498 mnemonic = instr->Mask(NEON_Q) ? "fcvtxn2" : "fcvtxn";
1499 nfd.SetFormatMap(0, &map_cvt_tb);
1500 nfd.SetFormatMap(1, &map_cvt_ta);
1501 break;
1502 case NEON_FCVTL:
1503 mnemonic = instr->Mask(NEON_Q) ? "fcvtl2" : "fcvtl";
1504 nfd.SetFormatMap(0, &map_cvt_ta);
1505 nfd.SetFormatMap(1, &map_cvt_tb);
1506 break;
1507 case NEON_FRINTN: mnemonic = "frintn"; break;
1508 case NEON_FRINTA: mnemonic = "frinta"; break;
1509 case NEON_FRINTP: mnemonic = "frintp"; break;
1510 case NEON_FRINTM: mnemonic = "frintm"; break;
1511 case NEON_FRINTX: mnemonic = "frintx"; break;
1512 case NEON_FRINTZ: mnemonic = "frintz"; break;
1513 case NEON_FRINTI: mnemonic = "frinti"; break;
1514 case NEON_FCVTNS: mnemonic = "fcvtns"; break;
1515 case NEON_FCVTNU: mnemonic = "fcvtnu"; break;
1516 case NEON_FCVTPS: mnemonic = "fcvtps"; break;
1517 case NEON_FCVTPU: mnemonic = "fcvtpu"; break;
1518 case NEON_FCVTMS: mnemonic = "fcvtms"; break;
1519 case NEON_FCVTMU: mnemonic = "fcvtmu"; break;
1520 case NEON_FCVTZS: mnemonic = "fcvtzs"; break;
1521 case NEON_FCVTZU: mnemonic = "fcvtzu"; break;
1522 case NEON_FCVTAS: mnemonic = "fcvtas"; break;
1523 case NEON_FCVTAU: mnemonic = "fcvtau"; break;
1524 case NEON_FSQRT: mnemonic = "fsqrt"; break;
1525 case NEON_SCVTF: mnemonic = "scvtf"; break;
1526 case NEON_UCVTF: mnemonic = "ucvtf"; break;
1527 case NEON_URSQRTE: mnemonic = "ursqrte"; break;
1528 case NEON_URECPE: mnemonic = "urecpe"; break;
1529 case NEON_FRSQRTE: mnemonic = "frsqrte"; break;
1530 case NEON_FRECPE: mnemonic = "frecpe"; break;
1531 case NEON_FCMGT_zero: mnemonic = "fcmgt"; form = form_fcmp_zero; break;
1532 case NEON_FCMGE_zero: mnemonic = "fcmge"; form = form_fcmp_zero; break;
1533 case NEON_FCMEQ_zero: mnemonic = "fcmeq"; form = form_fcmp_zero; break;
1534 case NEON_FCMLE_zero: mnemonic = "fcmle"; form = form_fcmp_zero; break;
1535 case NEON_FCMLT_zero: mnemonic = "fcmlt"; form = form_fcmp_zero; break;
1536 default:
1537 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) &&
1538 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) {
1539 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
1540 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
1541
1542 switch (instr->Mask(NEON2RegMiscMask)) {
1543 case NEON_XTN: mnemonic = "xtn"; break;
1544 case NEON_SQXTN: mnemonic = "sqxtn"; break;
1545 case NEON_UQXTN: mnemonic = "uqxtn"; break;
1546 case NEON_SQXTUN: mnemonic = "sqxtun"; break;
1547 case NEON_SHLL:
1548 mnemonic = "shll";
1549 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap());
1550 nfd.SetFormatMap(1, nfd.IntegerFormatMap());
1551 switch (instr->NEONSize()) {
1552 case 0: form = "'Vd.%s, 'Vn.%s, #8"; break;
1553 case 1: form = "'Vd.%s, 'Vn.%s, #16"; break;
1554 case 2: form = "'Vd.%s, 'Vn.%s, #32"; break;
1555 default: form = "(NEON2RegMisc)";
1556 }
1557 }
1558 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));
1559 return;
1560 } else {
1561 form = "(NEON2RegMisc)";
1562 }
1563 }
1564 }
1565 Format(instr, mnemonic, nfd.Substitute(form));
1566 }
1567
1568
VisitNEON3Same(const Instruction * instr)1569 void Disassembler::VisitNEON3Same(const Instruction* instr) {
1570 const char *mnemonic = "unimplemented";
1571 const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
1572 NEONFormatDecoder nfd(instr);
1573
1574 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) {
1575 switch (instr->Mask(NEON3SameLogicalMask)) {
1576 case NEON_AND: mnemonic = "and"; break;
1577 case NEON_ORR:
1578 mnemonic = "orr";
1579 if (instr->Rm() == instr->Rn()) {
1580 mnemonic = "mov";
1581 form = "'Vd.%s, 'Vn.%s";
1582 }
1583 break;
1584 case NEON_ORN: mnemonic = "orn"; break;
1585 case NEON_EOR: mnemonic = "eor"; break;
1586 case NEON_BIC: mnemonic = "bic"; break;
1587 case NEON_BIF: mnemonic = "bif"; break;
1588 case NEON_BIT: mnemonic = "bit"; break;
1589 case NEON_BSL: mnemonic = "bsl"; break;
1590 default: form = "(NEON3Same)";
1591 }
1592 nfd.SetFormatMaps(nfd.LogicalFormatMap());
1593 } else {
1594 static const char *mnemonics[] = {
1595 "shadd", "uhadd", "shadd", "uhadd",
1596 "sqadd", "uqadd", "sqadd", "uqadd",
1597 "srhadd", "urhadd", "srhadd", "urhadd",
1598 NULL, NULL, NULL, NULL, // Handled by logical cases above.
1599 "shsub", "uhsub", "shsub", "uhsub",
1600 "sqsub", "uqsub", "sqsub", "uqsub",
1601 "cmgt", "cmhi", "cmgt", "cmhi",
1602 "cmge", "cmhs", "cmge", "cmhs",
1603 "sshl", "ushl", "sshl", "ushl",
1604 "sqshl", "uqshl", "sqshl", "uqshl",
1605 "srshl", "urshl", "srshl", "urshl",
1606 "sqrshl", "uqrshl", "sqrshl", "uqrshl",
1607 "smax", "umax", "smax", "umax",
1608 "smin", "umin", "smin", "umin",
1609 "sabd", "uabd", "sabd", "uabd",
1610 "saba", "uaba", "saba", "uaba",
1611 "add", "sub", "add", "sub",
1612 "cmtst", "cmeq", "cmtst", "cmeq",
1613 "mla", "mls", "mla", "mls",
1614 "mul", "pmul", "mul", "pmul",
1615 "smaxp", "umaxp", "smaxp", "umaxp",
1616 "sminp", "uminp", "sminp", "uminp",
1617 "sqdmulh", "sqrdmulh", "sqdmulh", "sqrdmulh",
1618 "addp", "unallocated", "addp", "unallocated",
1619 "fmaxnm", "fmaxnmp", "fminnm", "fminnmp",
1620 "fmla", "unallocated", "fmls", "unallocated",
1621 "fadd", "faddp", "fsub", "fabd",
1622 "fmulx", "fmul", "unallocated", "unallocated",
1623 "fcmeq", "fcmge", "unallocated", "fcmgt",
1624 "unallocated", "facge", "unallocated", "facgt",
1625 "fmax", "fmaxp", "fmin", "fminp",
1626 "frecps", "fdiv", "frsqrts", "unallocated"};
1627
1628 // Operation is determined by the opcode bits (15-11), the top bit of
1629 // size (23) and the U bit (29).
1630 unsigned index = (instr->Bits(15, 11) << 2) | (instr->Bit(23) << 1) |
1631 instr->Bit(29);
1632 VIXL_ASSERT(index < (sizeof(mnemonics) / sizeof(mnemonics[0])));
1633 mnemonic = mnemonics[index];
1634 // Assert that index is not one of the previously handled logical
1635 // instructions.
1636 VIXL_ASSERT(mnemonic != NULL);
1637
1638 if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
1639 nfd.SetFormatMaps(nfd.FPFormatMap());
1640 }
1641 }
1642 Format(instr, mnemonic, nfd.Substitute(form));
1643 }
1644
1645
VisitNEON3Different(const Instruction * instr)1646 void Disassembler::VisitNEON3Different(const Instruction* instr) {
1647 const char *mnemonic = "unimplemented";
1648 const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
1649
1650 NEONFormatDecoder nfd(instr);
1651 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap());
1652
1653 // Ignore the Q bit. Appending a "2" suffix is handled later.
1654 switch (instr->Mask(NEON3DifferentMask) & ~NEON_Q) {
1655 case NEON_PMULL: mnemonic = "pmull"; break;
1656 case NEON_SABAL: mnemonic = "sabal"; break;
1657 case NEON_SABDL: mnemonic = "sabdl"; break;
1658 case NEON_SADDL: mnemonic = "saddl"; break;
1659 case NEON_SMLAL: mnemonic = "smlal"; break;
1660 case NEON_SMLSL: mnemonic = "smlsl"; break;
1661 case NEON_SMULL: mnemonic = "smull"; break;
1662 case NEON_SSUBL: mnemonic = "ssubl"; break;
1663 case NEON_SQDMLAL: mnemonic = "sqdmlal"; break;
1664 case NEON_SQDMLSL: mnemonic = "sqdmlsl"; break;
1665 case NEON_SQDMULL: mnemonic = "sqdmull"; break;
1666 case NEON_UABAL: mnemonic = "uabal"; break;
1667 case NEON_UABDL: mnemonic = "uabdl"; break;
1668 case NEON_UADDL: mnemonic = "uaddl"; break;
1669 case NEON_UMLAL: mnemonic = "umlal"; break;
1670 case NEON_UMLSL: mnemonic = "umlsl"; break;
1671 case NEON_UMULL: mnemonic = "umull"; break;
1672 case NEON_USUBL: mnemonic = "usubl"; break;
1673 case NEON_SADDW:
1674 mnemonic = "saddw";
1675 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
1676 break;
1677 case NEON_SSUBW:
1678 mnemonic = "ssubw";
1679 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
1680 break;
1681 case NEON_UADDW:
1682 mnemonic = "uaddw";
1683 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
1684 break;
1685 case NEON_USUBW:
1686 mnemonic = "usubw";
1687 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
1688 break;
1689 case NEON_ADDHN:
1690 mnemonic = "addhn";
1691 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
1692 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
1693 break;
1694 case NEON_RADDHN:
1695 mnemonic = "raddhn";
1696 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
1697 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
1698 break;
1699 case NEON_RSUBHN:
1700 mnemonic = "rsubhn";
1701 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
1702 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
1703 break;
1704 case NEON_SUBHN:
1705 mnemonic = "subhn";
1706 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
1707 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
1708 break;
1709 default: form = "(NEON3Different)";
1710 }
1711 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));
1712 }
1713
1714
VisitNEONAcrossLanes(const Instruction * instr)1715 void Disassembler::VisitNEONAcrossLanes(const Instruction* instr) {
1716 const char *mnemonic = "unimplemented";
1717 const char *form = "%sd, 'Vn.%s";
1718
1719 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap(),
1720 NEONFormatDecoder::IntegerFormatMap());
1721
1722 if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
1723 nfd.SetFormatMap(0, nfd.FPScalarFormatMap());
1724 nfd.SetFormatMap(1, nfd.FPFormatMap());
1725 switch (instr->Mask(NEONAcrossLanesFPMask)) {
1726 case NEON_FMAXV: mnemonic = "fmaxv"; break;
1727 case NEON_FMINV: mnemonic = "fminv"; break;
1728 case NEON_FMAXNMV: mnemonic = "fmaxnmv"; break;
1729 case NEON_FMINNMV: mnemonic = "fminnmv"; break;
1730 default: form = "(NEONAcrossLanes)"; break;
1731 }
1732 } else if (instr->Mask(NEONAcrossLanesFMask) == NEONAcrossLanesFixed) {
1733 switch (instr->Mask(NEONAcrossLanesMask)) {
1734 case NEON_ADDV: mnemonic = "addv"; break;
1735 case NEON_SMAXV: mnemonic = "smaxv"; break;
1736 case NEON_SMINV: mnemonic = "sminv"; break;
1737 case NEON_UMAXV: mnemonic = "umaxv"; break;
1738 case NEON_UMINV: mnemonic = "uminv"; break;
1739 case NEON_SADDLV:
1740 mnemonic = "saddlv";
1741 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
1742 break;
1743 case NEON_UADDLV:
1744 mnemonic = "uaddlv";
1745 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
1746 break;
1747 default: form = "(NEONAcrossLanes)"; break;
1748 }
1749 }
1750 Format(instr, mnemonic, nfd.Substitute(form,
1751 NEONFormatDecoder::kPlaceholder, NEONFormatDecoder::kFormat));
1752 }
1753
1754
VisitNEONByIndexedElement(const Instruction * instr)1755 void Disassembler::VisitNEONByIndexedElement(const Instruction* instr) {
1756 const char *mnemonic = "unimplemented";
1757 bool l_instr = false;
1758 bool fp_instr = false;
1759
1760 const char *form = "'Vd.%s, 'Vn.%s, 'Ve.%s['IVByElemIndex]";
1761
1762 static const NEONFormatMap map_ta = {
1763 {23, 22}, {NF_UNDEF, NF_4S, NF_2D}
1764 };
1765 NEONFormatDecoder nfd(instr, &map_ta,
1766 NEONFormatDecoder::IntegerFormatMap(),
1767 NEONFormatDecoder::ScalarFormatMap());
1768
1769 switch (instr->Mask(NEONByIndexedElementMask)) {
1770 case NEON_SMULL_byelement: mnemonic = "smull"; l_instr = true; break;
1771 case NEON_UMULL_byelement: mnemonic = "umull"; l_instr = true; break;
1772 case NEON_SMLAL_byelement: mnemonic = "smlal"; l_instr = true; break;
1773 case NEON_UMLAL_byelement: mnemonic = "umlal"; l_instr = true; break;
1774 case NEON_SMLSL_byelement: mnemonic = "smlsl"; l_instr = true; break;
1775 case NEON_UMLSL_byelement: mnemonic = "umlsl"; l_instr = true; break;
1776 case NEON_SQDMULL_byelement: mnemonic = "sqdmull"; l_instr = true; break;
1777 case NEON_SQDMLAL_byelement: mnemonic = "sqdmlal"; l_instr = true; break;
1778 case NEON_SQDMLSL_byelement: mnemonic = "sqdmlsl"; l_instr = true; break;
1779 case NEON_MUL_byelement: mnemonic = "mul"; break;
1780 case NEON_MLA_byelement: mnemonic = "mla"; break;
1781 case NEON_MLS_byelement: mnemonic = "mls"; break;
1782 case NEON_SQDMULH_byelement: mnemonic = "sqdmulh"; break;
1783 case NEON_SQRDMULH_byelement: mnemonic = "sqrdmulh"; break;
1784 default:
1785 switch (instr->Mask(NEONByIndexedElementFPMask)) {
1786 case NEON_FMUL_byelement: mnemonic = "fmul"; fp_instr = true; break;
1787 case NEON_FMLA_byelement: mnemonic = "fmla"; fp_instr = true; break;
1788 case NEON_FMLS_byelement: mnemonic = "fmls"; fp_instr = true; break;
1789 case NEON_FMULX_byelement: mnemonic = "fmulx"; fp_instr = true; break;
1790 }
1791 }
1792
1793 if (l_instr) {
1794 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));
1795 } else if (fp_instr) {
1796 nfd.SetFormatMap(0, nfd.FPFormatMap());
1797 Format(instr, mnemonic, nfd.Substitute(form));
1798 } else {
1799 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
1800 Format(instr, mnemonic, nfd.Substitute(form));
1801 }
1802 }
1803
1804
VisitNEONCopy(const Instruction * instr)1805 void Disassembler::VisitNEONCopy(const Instruction* instr) {
1806 const char *mnemonic = "unimplemented";
1807 const char *form = "(NEONCopy)";
1808
1809 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap(),
1810 NEONFormatDecoder::TriangularScalarFormatMap());
1811
1812 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) {
1813 mnemonic = "mov";
1814 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
1815 form = "'Vd.%s['IVInsIndex1], 'Vn.%s['IVInsIndex2]";
1816 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) {
1817 mnemonic = "mov";
1818 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
1819 if (nfd.GetVectorFormat() == kFormatD) {
1820 form = "'Vd.%s['IVInsIndex1], 'Xn";
1821 } else {
1822 form = "'Vd.%s['IVInsIndex1], 'Wn";
1823 }
1824 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) {
1825 if (instr->Mask(NEON_Q) || ((instr->ImmNEON5() & 7) == 4)) {
1826 mnemonic = "mov";
1827 } else {
1828 mnemonic = "umov";
1829 }
1830 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
1831 if (nfd.GetVectorFormat() == kFormatD) {
1832 form = "'Xd, 'Vn.%s['IVInsIndex1]";
1833 } else {
1834 form = "'Wd, 'Vn.%s['IVInsIndex1]";
1835 }
1836 } else if (instr->Mask(NEONCopySmovMask) == NEON_SMOV) {
1837 mnemonic = "smov";
1838 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
1839 form = "'Rdq, 'Vn.%s['IVInsIndex1]";
1840 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) {
1841 mnemonic = "dup";
1842 form = "'Vd.%s, 'Vn.%s['IVInsIndex1]";
1843 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) {
1844 mnemonic = "dup";
1845 if (nfd.GetVectorFormat() == kFormat2D) {
1846 form = "'Vd.%s, 'Xn";
1847 } else {
1848 form = "'Vd.%s, 'Wn";
1849 }
1850 }
1851 Format(instr, mnemonic, nfd.Substitute(form));
1852 }
1853
1854
VisitNEONExtract(const Instruction * instr)1855 void Disassembler::VisitNEONExtract(const Instruction* instr) {
1856 const char *mnemonic = "unimplemented";
1857 const char *form = "(NEONExtract)";
1858 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
1859 if (instr->Mask(NEONExtractMask) == NEON_EXT) {
1860 mnemonic = "ext";
1861 form = "'Vd.%s, 'Vn.%s, 'Vm.%s, 'IVExtract";
1862 }
1863 Format(instr, mnemonic, nfd.Substitute(form));
1864 }
1865
1866
VisitNEONLoadStoreMultiStruct(const Instruction * instr)1867 void Disassembler::VisitNEONLoadStoreMultiStruct(const Instruction* instr) {
1868 const char *mnemonic = "unimplemented";
1869 const char *form = "(NEONLoadStoreMultiStruct)";
1870 const char *form_1v = "{'Vt.%1$s}, ['Xns]";
1871 const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns]";
1872 const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns]";
1873 const char *form_4v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]";
1874 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
1875
1876 switch (instr->Mask(NEONLoadStoreMultiStructMask)) {
1877 case NEON_LD1_1v: mnemonic = "ld1"; form = form_1v; break;
1878 case NEON_LD1_2v: mnemonic = "ld1"; form = form_2v; break;
1879 case NEON_LD1_3v: mnemonic = "ld1"; form = form_3v; break;
1880 case NEON_LD1_4v: mnemonic = "ld1"; form = form_4v; break;
1881 case NEON_LD2: mnemonic = "ld2"; form = form_2v; break;
1882 case NEON_LD3: mnemonic = "ld3"; form = form_3v; break;
1883 case NEON_LD4: mnemonic = "ld4"; form = form_4v; break;
1884 case NEON_ST1_1v: mnemonic = "st1"; form = form_1v; break;
1885 case NEON_ST1_2v: mnemonic = "st1"; form = form_2v; break;
1886 case NEON_ST1_3v: mnemonic = "st1"; form = form_3v; break;
1887 case NEON_ST1_4v: mnemonic = "st1"; form = form_4v; break;
1888 case NEON_ST2: mnemonic = "st2"; form = form_2v; break;
1889 case NEON_ST3: mnemonic = "st3"; form = form_3v; break;
1890 case NEON_ST4: mnemonic = "st4"; form = form_4v; break;
1891 default: break;
1892 }
1893
1894 Format(instr, mnemonic, nfd.Substitute(form));
1895 }
1896
1897
VisitNEONLoadStoreMultiStructPostIndex(const Instruction * instr)1898 void Disassembler::VisitNEONLoadStoreMultiStructPostIndex(
1899 const Instruction* instr) {
1900 const char *mnemonic = "unimplemented";
1901 const char *form = "(NEONLoadStoreMultiStructPostIndex)";
1902 const char *form_1v = "{'Vt.%1$s}, ['Xns], 'Xmr1";
1903 const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns], 'Xmr2";
1904 const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns], 'Xmr3";
1905 const char *form_4v =
1906 "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmr4";
1907 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
1908
1909 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {
1910 case NEON_LD1_1v_post: mnemonic = "ld1"; form = form_1v; break;
1911 case NEON_LD1_2v_post: mnemonic = "ld1"; form = form_2v; break;
1912 case NEON_LD1_3v_post: mnemonic = "ld1"; form = form_3v; break;
1913 case NEON_LD1_4v_post: mnemonic = "ld1"; form = form_4v; break;
1914 case NEON_LD2_post: mnemonic = "ld2"; form = form_2v; break;
1915 case NEON_LD3_post: mnemonic = "ld3"; form = form_3v; break;
1916 case NEON_LD4_post: mnemonic = "ld4"; form = form_4v; break;
1917 case NEON_ST1_1v_post: mnemonic = "st1"; form = form_1v; break;
1918 case NEON_ST1_2v_post: mnemonic = "st1"; form = form_2v; break;
1919 case NEON_ST1_3v_post: mnemonic = "st1"; form = form_3v; break;
1920 case NEON_ST1_4v_post: mnemonic = "st1"; form = form_4v; break;
1921 case NEON_ST2_post: mnemonic = "st2"; form = form_2v; break;
1922 case NEON_ST3_post: mnemonic = "st3"; form = form_3v; break;
1923 case NEON_ST4_post: mnemonic = "st4"; form = form_4v; break;
1924 default: break;
1925 }
1926
1927 Format(instr, mnemonic, nfd.Substitute(form));
1928 }
1929
1930
VisitNEONLoadStoreSingleStruct(const Instruction * instr)1931 void Disassembler::VisitNEONLoadStoreSingleStruct(const Instruction* instr) {
1932 const char *mnemonic = "unimplemented";
1933 const char *form = "(NEONLoadStoreSingleStruct)";
1934
1935 const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns]";
1936 const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns]";
1937 const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns]";
1938 const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns]";
1939 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
1940
1941 switch (instr->Mask(NEONLoadStoreSingleStructMask)) {
1942 case NEON_LD1_b: mnemonic = "ld1"; form = form_1b; break;
1943 case NEON_LD1_h: mnemonic = "ld1"; form = form_1h; break;
1944 case NEON_LD1_s:
1945 mnemonic = "ld1";
1946 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);
1947 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d;
1948 break;
1949 case NEON_ST1_b: mnemonic = "st1"; form = form_1b; break;
1950 case NEON_ST1_h: mnemonic = "st1"; form = form_1h; break;
1951 case NEON_ST1_s:
1952 mnemonic = "st1";
1953 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);
1954 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d;
1955 break;
1956 case NEON_LD1R:
1957 mnemonic = "ld1r";
1958 form = "{'Vt.%s}, ['Xns]";
1959 break;
1960 case NEON_LD2_b:
1961 case NEON_ST2_b:
1962 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2";
1963 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns]";
1964 break;
1965 case NEON_LD2_h:
1966 case NEON_ST2_h:
1967 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2";
1968 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns]";
1969 break;
1970 case NEON_LD2_s:
1971 case NEON_ST2_s:
1972 VIXL_STATIC_ASSERT((NEON_ST2_s | (1 << NEONLSSize_offset)) == NEON_ST2_d);
1973 VIXL_STATIC_ASSERT((NEON_LD2_s | (1 << NEONLSSize_offset)) == NEON_LD2_d);
1974 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2";
1975 if ((instr->NEONLSSize() & 1) == 0)
1976 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns]";
1977 else
1978 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns]";
1979 break;
1980 case NEON_LD2R:
1981 mnemonic = "ld2r";
1982 form = "{'Vt.%s, 'Vt2.%s}, ['Xns]";
1983 break;
1984 case NEON_LD3_b:
1985 case NEON_ST3_b:
1986 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3";
1987 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns]";
1988 break;
1989 case NEON_LD3_h:
1990 case NEON_ST3_h:
1991 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3";
1992 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns]";
1993 break;
1994 case NEON_LD3_s:
1995 case NEON_ST3_s:
1996 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3";
1997 if ((instr->NEONLSSize() & 1) == 0)
1998 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns]";
1999 else
2000 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns]";
2001 break;
2002 case NEON_LD3R:
2003 mnemonic = "ld3r";
2004 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns]";
2005 break;
2006 case NEON_LD4_b:
2007 case NEON_ST4_b:
2008 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4";
2009 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns]";
2010 break;
2011 case NEON_LD4_h:
2012 case NEON_ST4_h:
2013 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4";
2014 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns]";
2015 break;
2016 case NEON_LD4_s:
2017 case NEON_ST4_s:
2018 VIXL_STATIC_ASSERT((NEON_LD4_s | (1 << NEONLSSize_offset)) == NEON_LD4_d);
2019 VIXL_STATIC_ASSERT((NEON_ST4_s | (1 << NEONLSSize_offset)) == NEON_ST4_d);
2020 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4";
2021 if ((instr->NEONLSSize() & 1) == 0)
2022 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns]";
2023 else
2024 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns]";
2025 break;
2026 case NEON_LD4R:
2027 mnemonic = "ld4r";
2028 form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]";
2029 break;
2030 default: break;
2031 }
2032
2033 Format(instr, mnemonic, nfd.Substitute(form));
2034 }
2035
2036
VisitNEONLoadStoreSingleStructPostIndex(const Instruction * instr)2037 void Disassembler::VisitNEONLoadStoreSingleStructPostIndex(
2038 const Instruction* instr) {
2039 const char *mnemonic = "unimplemented";
2040 const char *form = "(NEONLoadStoreSingleStructPostIndex)";
2041
2042 const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns], 'Xmb1";
2043 const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns], 'Xmb2";
2044 const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns], 'Xmb4";
2045 const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns], 'Xmb8";
2046 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
2047
2048 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {
2049 case NEON_LD1_b_post: mnemonic = "ld1"; form = form_1b; break;
2050 case NEON_LD1_h_post: mnemonic = "ld1"; form = form_1h; break;
2051 case NEON_LD1_s_post:
2052 mnemonic = "ld1";
2053 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);
2054 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d;
2055 break;
2056 case NEON_ST1_b_post: mnemonic = "st1"; form = form_1b; break;
2057 case NEON_ST1_h_post: mnemonic = "st1"; form = form_1h; break;
2058 case NEON_ST1_s_post:
2059 mnemonic = "st1";
2060 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);
2061 form = ((instr->NEONLSSize() & 1) == 0) ? form_1s : form_1d;
2062 break;
2063 case NEON_LD1R_post:
2064 mnemonic = "ld1r";
2065 form = "{'Vt.%s}, ['Xns], 'Xmz1";
2066 break;
2067 case NEON_LD2_b_post:
2068 case NEON_ST2_b_post:
2069 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2";
2070 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns], 'Xmb2";
2071 break;
2072 case NEON_ST2_h_post:
2073 case NEON_LD2_h_post:
2074 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2";
2075 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns], 'Xmb4";
2076 break;
2077 case NEON_LD2_s_post:
2078 case NEON_ST2_s_post:
2079 mnemonic = (instr->LdStXLoad() == 1) ? "ld2" : "st2";
2080 if ((instr->NEONLSSize() & 1) == 0)
2081 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns], 'Xmb8";
2082 else
2083 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns], 'Xmb16";
2084 break;
2085 case NEON_LD2R_post:
2086 mnemonic = "ld2r";
2087 form = "{'Vt.%s, 'Vt2.%s}, ['Xns], 'Xmz2";
2088 break;
2089 case NEON_LD3_b_post:
2090 case NEON_ST3_b_post:
2091 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3";
2092 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns], 'Xmb3";
2093 break;
2094 case NEON_LD3_h_post:
2095 case NEON_ST3_h_post:
2096 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3";
2097 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns], 'Xmb6";
2098 break;
2099 case NEON_LD3_s_post:
2100 case NEON_ST3_s_post:
2101 mnemonic = (instr->LdStXLoad() == 1) ? "ld3" : "st3";
2102 if ((instr->NEONLSSize() & 1) == 0)
2103 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns], 'Xmb12";
2104 else
2105 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns], 'Xmr3";
2106 break;
2107 case NEON_LD3R_post:
2108 mnemonic = "ld3r";
2109 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns], 'Xmz3";
2110 break;
2111 case NEON_LD4_b_post:
2112 case NEON_ST4_b_post:
2113 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4";
2114 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns], 'Xmb4";
2115 break;
2116 case NEON_LD4_h_post:
2117 case NEON_ST4_h_post:
2118 mnemonic = (instr->LdStXLoad()) == 1 ? "ld4" : "st4";
2119 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns], 'Xmb8";
2120 break;
2121 case NEON_LD4_s_post:
2122 case NEON_ST4_s_post:
2123 mnemonic = (instr->LdStXLoad() == 1) ? "ld4" : "st4";
2124 if ((instr->NEONLSSize() & 1) == 0)
2125 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns], 'Xmb16";
2126 else
2127 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns], 'Xmb32";
2128 break;
2129 case NEON_LD4R_post:
2130 mnemonic = "ld4r";
2131 form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmz4";
2132 break;
2133 default: break;
2134 }
2135
2136 Format(instr, mnemonic, nfd.Substitute(form));
2137 }
2138
2139
VisitNEONModifiedImmediate(const Instruction * instr)2140 void Disassembler::VisitNEONModifiedImmediate(const Instruction* instr) {
2141 const char *mnemonic = "unimplemented";
2142 const char *form = "'Vt.%s, 'IVMIImm8, lsl 'IVMIShiftAmt1";
2143
2144 int cmode = instr->NEONCmode();
2145 int cmode_3 = (cmode >> 3) & 1;
2146 int cmode_2 = (cmode >> 2) & 1;
2147 int cmode_1 = (cmode >> 1) & 1;
2148 int cmode_0 = cmode & 1;
2149 int q = instr->NEONQ();
2150 int op = instr->NEONModImmOp();
2151
2152 static const NEONFormatMap map_b = { {30}, {NF_8B, NF_16B} };
2153 static const NEONFormatMap map_h = { {30}, {NF_4H, NF_8H} };
2154 static const NEONFormatMap map_s = { {30}, {NF_2S, NF_4S} };
2155 NEONFormatDecoder nfd(instr, &map_b);
2156
2157 if (cmode_3 == 0) {
2158 if (cmode_0 == 0) {
2159 mnemonic = (op == 1) ? "mvni" : "movi";
2160 } else { // cmode<0> == '1'.
2161 mnemonic = (op == 1) ? "bic" : "orr";
2162 }
2163 nfd.SetFormatMap(0, &map_s);
2164 } else { // cmode<3> == '1'.
2165 if (cmode_2 == 0) {
2166 if (cmode_0 == 0) {
2167 mnemonic = (op == 1) ? "mvni" : "movi";
2168 } else { // cmode<0> == '1'.
2169 mnemonic = (op == 1) ? "bic" : "orr";
2170 }
2171 nfd.SetFormatMap(0, &map_h);
2172 } else { // cmode<2> == '1'.
2173 if (cmode_1 == 0) {
2174 mnemonic = (op == 1) ? "mvni" : "movi";
2175 form = "'Vt.%s, 'IVMIImm8, msl 'IVMIShiftAmt2";
2176 nfd.SetFormatMap(0, &map_s);
2177 } else { // cmode<1> == '1'.
2178 if (cmode_0 == 0) {
2179 mnemonic = "movi";
2180 if (op == 0) {
2181 form = "'Vt.%s, 'IVMIImm8";
2182 } else {
2183 form = (q == 0) ? "'Dd, 'IVMIImm" : "'Vt.2d, 'IVMIImm";
2184 }
2185 } else { // cmode<0> == '1'
2186 mnemonic = "fmov";
2187 if (op == 0) {
2188 form = "'Vt.%s, 'IVMIImmFPSingle";
2189 nfd.SetFormatMap(0, &map_s);
2190 } else {
2191 if (q == 1) {
2192 form = "'Vt.2d, 'IVMIImmFPDouble";
2193 }
2194 }
2195 }
2196 }
2197 }
2198 }
2199 Format(instr, mnemonic, nfd.Substitute(form));
2200 }
2201
2202
VisitNEONScalar2RegMisc(const Instruction * instr)2203 void Disassembler::VisitNEONScalar2RegMisc(const Instruction* instr) {
2204 const char *mnemonic = "unimplemented";
2205 const char *form = "%sd, %sn";
2206 const char *form_0 = "%sd, %sn, #0";
2207 const char *form_fp0 = "%sd, %sn, #0.0";
2208
2209 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
2210
2211 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) {
2212 // These instructions all use a two bit size field, except NOT and RBIT,
2213 // which use the field to encode the operation.
2214 switch (instr->Mask(NEONScalar2RegMiscMask)) {
2215 case NEON_CMGT_zero_scalar: mnemonic = "cmgt"; form = form_0; break;
2216 case NEON_CMGE_zero_scalar: mnemonic = "cmge"; form = form_0; break;
2217 case NEON_CMLE_zero_scalar: mnemonic = "cmle"; form = form_0; break;
2218 case NEON_CMLT_zero_scalar: mnemonic = "cmlt"; form = form_0; break;
2219 case NEON_CMEQ_zero_scalar: mnemonic = "cmeq"; form = form_0; break;
2220 case NEON_NEG_scalar: mnemonic = "neg"; break;
2221 case NEON_SQNEG_scalar: mnemonic = "sqneg"; break;
2222 case NEON_ABS_scalar: mnemonic = "abs"; break;
2223 case NEON_SQABS_scalar: mnemonic = "sqabs"; break;
2224 case NEON_SUQADD_scalar: mnemonic = "suqadd"; break;
2225 case NEON_USQADD_scalar: mnemonic = "usqadd"; break;
2226 default: form = "(NEONScalar2RegMisc)";
2227 }
2228 } else {
2229 // These instructions all use a one bit size field, except SQXTUN, SQXTN
2230 // and UQXTN, which use a two bit size field.
2231 nfd.SetFormatMaps(nfd.FPScalarFormatMap());
2232 switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
2233 case NEON_FRSQRTE_scalar: mnemonic = "frsqrte"; break;
2234 case NEON_FRECPE_scalar: mnemonic = "frecpe"; break;
2235 case NEON_SCVTF_scalar: mnemonic = "scvtf"; break;
2236 case NEON_UCVTF_scalar: mnemonic = "ucvtf"; break;
2237 case NEON_FCMGT_zero_scalar: mnemonic = "fcmgt"; form = form_fp0; break;
2238 case NEON_FCMGE_zero_scalar: mnemonic = "fcmge"; form = form_fp0; break;
2239 case NEON_FCMLE_zero_scalar: mnemonic = "fcmle"; form = form_fp0; break;
2240 case NEON_FCMLT_zero_scalar: mnemonic = "fcmlt"; form = form_fp0; break;
2241 case NEON_FCMEQ_zero_scalar: mnemonic = "fcmeq"; form = form_fp0; break;
2242 case NEON_FRECPX_scalar: mnemonic = "frecpx"; break;
2243 case NEON_FCVTNS_scalar: mnemonic = "fcvtns"; break;
2244 case NEON_FCVTNU_scalar: mnemonic = "fcvtnu"; break;
2245 case NEON_FCVTPS_scalar: mnemonic = "fcvtps"; break;
2246 case NEON_FCVTPU_scalar: mnemonic = "fcvtpu"; break;
2247 case NEON_FCVTMS_scalar: mnemonic = "fcvtms"; break;
2248 case NEON_FCVTMU_scalar: mnemonic = "fcvtmu"; break;
2249 case NEON_FCVTZS_scalar: mnemonic = "fcvtzs"; break;
2250 case NEON_FCVTZU_scalar: mnemonic = "fcvtzu"; break;
2251 case NEON_FCVTAS_scalar: mnemonic = "fcvtas"; break;
2252 case NEON_FCVTAU_scalar: mnemonic = "fcvtau"; break;
2253 case NEON_FCVTXN_scalar:
2254 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
2255 mnemonic = "fcvtxn";
2256 break;
2257 default:
2258 nfd.SetFormatMap(0, nfd.ScalarFormatMap());
2259 nfd.SetFormatMap(1, nfd.LongScalarFormatMap());
2260 switch (instr->Mask(NEONScalar2RegMiscMask)) {
2261 case NEON_SQXTN_scalar: mnemonic = "sqxtn"; break;
2262 case NEON_UQXTN_scalar: mnemonic = "uqxtn"; break;
2263 case NEON_SQXTUN_scalar: mnemonic = "sqxtun"; break;
2264 default: form = "(NEONScalar2RegMisc)";
2265 }
2266 }
2267 }
2268 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
2269 }
2270
2271
VisitNEONScalar3Diff(const Instruction * instr)2272 void Disassembler::VisitNEONScalar3Diff(const Instruction* instr) {
2273 const char *mnemonic = "unimplemented";
2274 const char *form = "%sd, %sn, %sm";
2275 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap(),
2276 NEONFormatDecoder::ScalarFormatMap());
2277
2278 switch (instr->Mask(NEONScalar3DiffMask)) {
2279 case NEON_SQDMLAL_scalar : mnemonic = "sqdmlal"; break;
2280 case NEON_SQDMLSL_scalar : mnemonic = "sqdmlsl"; break;
2281 case NEON_SQDMULL_scalar : mnemonic = "sqdmull"; break;
2282 default: form = "(NEONScalar3Diff)";
2283 }
2284 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
2285 }
2286
2287
VisitNEONScalar3Same(const Instruction * instr)2288 void Disassembler::VisitNEONScalar3Same(const Instruction* instr) {
2289 const char *mnemonic = "unimplemented";
2290 const char *form = "%sd, %sn, %sm";
2291 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
2292
2293 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
2294 nfd.SetFormatMaps(nfd.FPScalarFormatMap());
2295 switch (instr->Mask(NEONScalar3SameFPMask)) {
2296 case NEON_FACGE_scalar: mnemonic = "facge"; break;
2297 case NEON_FACGT_scalar: mnemonic = "facgt"; break;
2298 case NEON_FCMEQ_scalar: mnemonic = "fcmeq"; break;
2299 case NEON_FCMGE_scalar: mnemonic = "fcmge"; break;
2300 case NEON_FCMGT_scalar: mnemonic = "fcmgt"; break;
2301 case NEON_FMULX_scalar: mnemonic = "fmulx"; break;
2302 case NEON_FRECPS_scalar: mnemonic = "frecps"; break;
2303 case NEON_FRSQRTS_scalar: mnemonic = "frsqrts"; break;
2304 case NEON_FABD_scalar: mnemonic = "fabd"; break;
2305 default: form = "(NEONScalar3Same)";
2306 }
2307 } else {
2308 switch (instr->Mask(NEONScalar3SameMask)) {
2309 case NEON_ADD_scalar: mnemonic = "add"; break;
2310 case NEON_SUB_scalar: mnemonic = "sub"; break;
2311 case NEON_CMEQ_scalar: mnemonic = "cmeq"; break;
2312 case NEON_CMGE_scalar: mnemonic = "cmge"; break;
2313 case NEON_CMGT_scalar: mnemonic = "cmgt"; break;
2314 case NEON_CMHI_scalar: mnemonic = "cmhi"; break;
2315 case NEON_CMHS_scalar: mnemonic = "cmhs"; break;
2316 case NEON_CMTST_scalar: mnemonic = "cmtst"; break;
2317 case NEON_UQADD_scalar: mnemonic = "uqadd"; break;
2318 case NEON_SQADD_scalar: mnemonic = "sqadd"; break;
2319 case NEON_UQSUB_scalar: mnemonic = "uqsub"; break;
2320 case NEON_SQSUB_scalar: mnemonic = "sqsub"; break;
2321 case NEON_USHL_scalar: mnemonic = "ushl"; break;
2322 case NEON_SSHL_scalar: mnemonic = "sshl"; break;
2323 case NEON_UQSHL_scalar: mnemonic = "uqshl"; break;
2324 case NEON_SQSHL_scalar: mnemonic = "sqshl"; break;
2325 case NEON_URSHL_scalar: mnemonic = "urshl"; break;
2326 case NEON_SRSHL_scalar: mnemonic = "srshl"; break;
2327 case NEON_UQRSHL_scalar: mnemonic = "uqrshl"; break;
2328 case NEON_SQRSHL_scalar: mnemonic = "sqrshl"; break;
2329 case NEON_SQDMULH_scalar: mnemonic = "sqdmulh"; break;
2330 case NEON_SQRDMULH_scalar: mnemonic = "sqrdmulh"; break;
2331 default: form = "(NEONScalar3Same)";
2332 }
2333 }
2334 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
2335 }
2336
2337
VisitNEONScalarByIndexedElement(const Instruction * instr)2338 void Disassembler::VisitNEONScalarByIndexedElement(const Instruction* instr) {
2339 const char *mnemonic = "unimplemented";
2340 const char *form = "%sd, %sn, 'Ve.%s['IVByElemIndex]";
2341 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
2342 bool long_instr = false;
2343
2344 switch (instr->Mask(NEONScalarByIndexedElementMask)) {
2345 case NEON_SQDMULL_byelement_scalar:
2346 mnemonic = "sqdmull";
2347 long_instr = true;
2348 break;
2349 case NEON_SQDMLAL_byelement_scalar:
2350 mnemonic = "sqdmlal";
2351 long_instr = true;
2352 break;
2353 case NEON_SQDMLSL_byelement_scalar:
2354 mnemonic = "sqdmlsl";
2355 long_instr = true;
2356 break;
2357 case NEON_SQDMULH_byelement_scalar:
2358 mnemonic = "sqdmulh";
2359 break;
2360 case NEON_SQRDMULH_byelement_scalar:
2361 mnemonic = "sqrdmulh";
2362 break;
2363 default:
2364 nfd.SetFormatMap(0, nfd.FPScalarFormatMap());
2365 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
2366 case NEON_FMUL_byelement_scalar: mnemonic = "fmul"; break;
2367 case NEON_FMLA_byelement_scalar: mnemonic = "fmla"; break;
2368 case NEON_FMLS_byelement_scalar: mnemonic = "fmls"; break;
2369 case NEON_FMULX_byelement_scalar: mnemonic = "fmulx"; break;
2370 default: form = "(NEONScalarByIndexedElement)";
2371 }
2372 }
2373
2374 if (long_instr) {
2375 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
2376 }
2377
2378 Format(instr, mnemonic, nfd.Substitute(
2379 form, nfd.kPlaceholder, nfd.kPlaceholder, nfd.kFormat));
2380 }
2381
2382
VisitNEONScalarCopy(const Instruction * instr)2383 void Disassembler::VisitNEONScalarCopy(const Instruction* instr) {
2384 const char *mnemonic = "unimplemented";
2385 const char *form = "(NEONScalarCopy)";
2386
2387 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());
2388
2389 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) {
2390 mnemonic = "mov";
2391 form = "%sd, 'Vn.%s['IVInsIndex1]";
2392 }
2393
2394 Format(instr, mnemonic, nfd.Substitute(form, nfd.kPlaceholder, nfd.kFormat));
2395 }
2396
2397
VisitNEONScalarPairwise(const Instruction * instr)2398 void Disassembler::VisitNEONScalarPairwise(const Instruction* instr) {
2399 const char *mnemonic = "unimplemented";
2400 const char *form = "%sd, 'Vn.%s";
2401 NEONFormatMap map = { {22}, {NF_2S, NF_2D} };
2402 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap(), &map);
2403
2404 switch (instr->Mask(NEONScalarPairwiseMask)) {
2405 case NEON_ADDP_scalar: mnemonic = "addp"; break;
2406 case NEON_FADDP_scalar: mnemonic = "faddp"; break;
2407 case NEON_FMAXP_scalar: mnemonic = "fmaxp"; break;
2408 case NEON_FMAXNMP_scalar: mnemonic = "fmaxnmp"; break;
2409 case NEON_FMINP_scalar: mnemonic = "fminp"; break;
2410 case NEON_FMINNMP_scalar: mnemonic = "fminnmp"; break;
2411 default: form = "(NEONScalarPairwise)";
2412 }
2413 Format(instr, mnemonic, nfd.Substitute(form,
2414 NEONFormatDecoder::kPlaceholder, NEONFormatDecoder::kFormat));
2415 }
2416
2417
VisitNEONScalarShiftImmediate(const Instruction * instr)2418 void Disassembler::VisitNEONScalarShiftImmediate(const Instruction* instr) {
2419 const char *mnemonic = "unimplemented";
2420 const char *form = "%sd, %sn, 'Is1";
2421 const char *form_2 = "%sd, %sn, 'Is2";
2422
2423 static const NEONFormatMap map_shift = {
2424 {22, 21, 20, 19},
2425 {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S,
2426 NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D}
2427 };
2428 static const NEONFormatMap map_shift_narrow = {
2429 {21, 20, 19},
2430 {NF_UNDEF, NF_H, NF_S, NF_S, NF_D, NF_D, NF_D, NF_D}
2431 };
2432 NEONFormatDecoder nfd(instr, &map_shift);
2433
2434 if (instr->ImmNEONImmh()) { // immh has to be non-zero.
2435 switch (instr->Mask(NEONScalarShiftImmediateMask)) {
2436 case NEON_FCVTZU_imm_scalar: mnemonic = "fcvtzu"; break;
2437 case NEON_FCVTZS_imm_scalar: mnemonic = "fcvtzs"; break;
2438 case NEON_SCVTF_imm_scalar: mnemonic = "scvtf"; break;
2439 case NEON_UCVTF_imm_scalar: mnemonic = "ucvtf"; break;
2440 case NEON_SRI_scalar: mnemonic = "sri"; break;
2441 case NEON_SSHR_scalar: mnemonic = "sshr"; break;
2442 case NEON_USHR_scalar: mnemonic = "ushr"; break;
2443 case NEON_SRSHR_scalar: mnemonic = "srshr"; break;
2444 case NEON_URSHR_scalar: mnemonic = "urshr"; break;
2445 case NEON_SSRA_scalar: mnemonic = "ssra"; break;
2446 case NEON_USRA_scalar: mnemonic = "usra"; break;
2447 case NEON_SRSRA_scalar: mnemonic = "srsra"; break;
2448 case NEON_URSRA_scalar: mnemonic = "ursra"; break;
2449 case NEON_SHL_scalar: mnemonic = "shl"; form = form_2; break;
2450 case NEON_SLI_scalar: mnemonic = "sli"; form = form_2; break;
2451 case NEON_SQSHLU_scalar: mnemonic = "sqshlu"; form = form_2; break;
2452 case NEON_SQSHL_imm_scalar: mnemonic = "sqshl"; form = form_2; break;
2453 case NEON_UQSHL_imm_scalar: mnemonic = "uqshl"; form = form_2; break;
2454 case NEON_UQSHRN_scalar:
2455 mnemonic = "uqshrn";
2456 nfd.SetFormatMap(1, &map_shift_narrow);
2457 break;
2458 case NEON_UQRSHRN_scalar:
2459 mnemonic = "uqrshrn";
2460 nfd.SetFormatMap(1, &map_shift_narrow);
2461 break;
2462 case NEON_SQSHRN_scalar:
2463 mnemonic = "sqshrn";
2464 nfd.SetFormatMap(1, &map_shift_narrow);
2465 break;
2466 case NEON_SQRSHRN_scalar:
2467 mnemonic = "sqrshrn";
2468 nfd.SetFormatMap(1, &map_shift_narrow);
2469 break;
2470 case NEON_SQSHRUN_scalar:
2471 mnemonic = "sqshrun";
2472 nfd.SetFormatMap(1, &map_shift_narrow);
2473 break;
2474 case NEON_SQRSHRUN_scalar:
2475 mnemonic = "sqrshrun";
2476 nfd.SetFormatMap(1, &map_shift_narrow);
2477 break;
2478 default:
2479 form = "(NEONScalarShiftImmediate)";
2480 }
2481 } else {
2482 form = "(NEONScalarShiftImmediate)";
2483 }
2484 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
2485 }
2486
2487
VisitNEONShiftImmediate(const Instruction * instr)2488 void Disassembler::VisitNEONShiftImmediate(const Instruction* instr) {
2489 const char *mnemonic = "unimplemented";
2490 const char *form = "'Vd.%s, 'Vn.%s, 'Is1";
2491 const char *form_shift_2 = "'Vd.%s, 'Vn.%s, 'Is2";
2492 const char *form_xtl = "'Vd.%s, 'Vn.%s";
2493
2494 // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
2495 static const NEONFormatMap map_shift_ta = {
2496 {22, 21, 20, 19},
2497 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}
2498 };
2499
2500 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
2501 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
2502 static const NEONFormatMap map_shift_tb = {
2503 {22, 21, 20, 19, 30},
2504 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H, NF_8H,
2505 NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S,
2506 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
2507 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}
2508 };
2509
2510 NEONFormatDecoder nfd(instr, &map_shift_tb);
2511
2512 if (instr->ImmNEONImmh()) { // immh has to be non-zero.
2513 switch (instr->Mask(NEONShiftImmediateMask)) {
2514 case NEON_SQSHLU: mnemonic = "sqshlu"; form = form_shift_2; break;
2515 case NEON_SQSHL_imm: mnemonic = "sqshl"; form = form_shift_2; break;
2516 case NEON_UQSHL_imm: mnemonic = "uqshl"; form = form_shift_2; break;
2517 case NEON_SHL: mnemonic = "shl"; form = form_shift_2; break;
2518 case NEON_SLI: mnemonic = "sli"; form = form_shift_2; break;
2519 case NEON_SCVTF_imm: mnemonic = "scvtf"; break;
2520 case NEON_UCVTF_imm: mnemonic = "ucvtf"; break;
2521 case NEON_FCVTZU_imm: mnemonic = "fcvtzu"; break;
2522 case NEON_FCVTZS_imm: mnemonic = "fcvtzs"; break;
2523 case NEON_SRI: mnemonic = "sri"; break;
2524 case NEON_SSHR: mnemonic = "sshr"; break;
2525 case NEON_USHR: mnemonic = "ushr"; break;
2526 case NEON_SRSHR: mnemonic = "srshr"; break;
2527 case NEON_URSHR: mnemonic = "urshr"; break;
2528 case NEON_SSRA: mnemonic = "ssra"; break;
2529 case NEON_USRA: mnemonic = "usra"; break;
2530 case NEON_SRSRA: mnemonic = "srsra"; break;
2531 case NEON_URSRA: mnemonic = "ursra"; break;
2532 case NEON_SHRN:
2533 mnemonic = instr->Mask(NEON_Q) ? "shrn2" : "shrn";
2534 nfd.SetFormatMap(1, &map_shift_ta);
2535 break;
2536 case NEON_RSHRN:
2537 mnemonic = instr->Mask(NEON_Q) ? "rshrn2" : "rshrn";
2538 nfd.SetFormatMap(1, &map_shift_ta);
2539 break;
2540 case NEON_UQSHRN:
2541 mnemonic = instr->Mask(NEON_Q) ? "uqshrn2" : "uqshrn";
2542 nfd.SetFormatMap(1, &map_shift_ta);
2543 break;
2544 case NEON_UQRSHRN:
2545 mnemonic = instr->Mask(NEON_Q) ? "uqrshrn2" : "uqrshrn";
2546 nfd.SetFormatMap(1, &map_shift_ta);
2547 break;
2548 case NEON_SQSHRN:
2549 mnemonic = instr->Mask(NEON_Q) ? "sqshrn2" : "sqshrn";
2550 nfd.SetFormatMap(1, &map_shift_ta);
2551 break;
2552 case NEON_SQRSHRN:
2553 mnemonic = instr->Mask(NEON_Q) ? "sqrshrn2" : "sqrshrn";
2554 nfd.SetFormatMap(1, &map_shift_ta);
2555 break;
2556 case NEON_SQSHRUN:
2557 mnemonic = instr->Mask(NEON_Q) ? "sqshrun2" : "sqshrun";
2558 nfd.SetFormatMap(1, &map_shift_ta);
2559 break;
2560 case NEON_SQRSHRUN:
2561 mnemonic = instr->Mask(NEON_Q) ? "sqrshrun2" : "sqrshrun";
2562 nfd.SetFormatMap(1, &map_shift_ta);
2563 break;
2564 case NEON_SSHLL:
2565 nfd.SetFormatMap(0, &map_shift_ta);
2566 if (instr->ImmNEONImmb() == 0 &&
2567 CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // sxtl variant.
2568 form = form_xtl;
2569 mnemonic = instr->Mask(NEON_Q) ? "sxtl2" : "sxtl";
2570 } else { // sshll variant.
2571 form = form_shift_2;
2572 mnemonic = instr->Mask(NEON_Q) ? "sshll2" : "sshll";
2573 }
2574 break;
2575 case NEON_USHLL:
2576 nfd.SetFormatMap(0, &map_shift_ta);
2577 if (instr->ImmNEONImmb() == 0 &&
2578 CountSetBits(instr->ImmNEONImmh(), 32) == 1) { // uxtl variant.
2579 form = form_xtl;
2580 mnemonic = instr->Mask(NEON_Q) ? "uxtl2" : "uxtl";
2581 } else { // ushll variant.
2582 form = form_shift_2;
2583 mnemonic = instr->Mask(NEON_Q) ? "ushll2" : "ushll";
2584 }
2585 break;
2586 default: form = "(NEONShiftImmediate)";
2587 }
2588 } else {
2589 form = "(NEONShiftImmediate)";
2590 }
2591 Format(instr, mnemonic, nfd.Substitute(form));
2592 }
2593
2594
VisitNEONTable(const Instruction * instr)2595 void Disassembler::VisitNEONTable(const Instruction* instr) {
2596 const char *mnemonic = "unimplemented";
2597 const char *form = "(NEONTable)";
2598 const char form_1v[] = "'Vd.%%s, {'Vn.16b}, 'Vm.%%s";
2599 const char form_2v[] = "'Vd.%%s, {'Vn.16b, v%d.16b}, 'Vm.%%s";
2600 const char form_3v[] = "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b}, 'Vm.%%s";
2601 const char form_4v[] =
2602 "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b, v%d.16b}, 'Vm.%%s";
2603 static const NEONFormatMap map_b = { {30}, {NF_8B, NF_16B} };
2604 NEONFormatDecoder nfd(instr, &map_b);
2605
2606 switch (instr->Mask(NEONTableMask)) {
2607 case NEON_TBL_1v: mnemonic = "tbl"; form = form_1v; break;
2608 case NEON_TBL_2v: mnemonic = "tbl"; form = form_2v; break;
2609 case NEON_TBL_3v: mnemonic = "tbl"; form = form_3v; break;
2610 case NEON_TBL_4v: mnemonic = "tbl"; form = form_4v; break;
2611 case NEON_TBX_1v: mnemonic = "tbx"; form = form_1v; break;
2612 case NEON_TBX_2v: mnemonic = "tbx"; form = form_2v; break;
2613 case NEON_TBX_3v: mnemonic = "tbx"; form = form_3v; break;
2614 case NEON_TBX_4v: mnemonic = "tbx"; form = form_4v; break;
2615 default: break;
2616 }
2617
2618 char re_form[sizeof(form_4v) + 6];
2619 int reg_num = instr->Rn();
2620 SprintfLiteral(re_form, form,
2621 (reg_num + 1) % kNumberOfVRegisters,
2622 (reg_num + 2) % kNumberOfVRegisters,
2623 (reg_num + 3) % kNumberOfVRegisters);
2624
2625 Format(instr, mnemonic, nfd.Substitute(re_form));
2626 }
2627
2628
VisitNEONPerm(const Instruction * instr)2629 void Disassembler::VisitNEONPerm(const Instruction* instr) {
2630 const char *mnemonic = "unimplemented";
2631 const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
2632 NEONFormatDecoder nfd(instr);
2633
2634 switch (instr->Mask(NEONPermMask)) {
2635 case NEON_TRN1: mnemonic = "trn1"; break;
2636 case NEON_TRN2: mnemonic = "trn2"; break;
2637 case NEON_UZP1: mnemonic = "uzp1"; break;
2638 case NEON_UZP2: mnemonic = "uzp2"; break;
2639 case NEON_ZIP1: mnemonic = "zip1"; break;
2640 case NEON_ZIP2: mnemonic = "zip2"; break;
2641 default: form = "(NEONPerm)";
2642 }
2643 Format(instr, mnemonic, nfd.Substitute(form));
2644 }
2645
2646
VisitUnimplemented(const Instruction * instr)2647 void Disassembler::VisitUnimplemented(const Instruction* instr) {
2648 Format(instr, "unimplemented", "(Unimplemented)");
2649 }
2650
2651
VisitUnallocated(const Instruction * instr)2652 void Disassembler::VisitUnallocated(const Instruction* instr) {
2653 Format(instr, "unallocated", "(Unallocated)");
2654 }
2655
2656
ProcessOutput(const Instruction *)2657 void Disassembler::ProcessOutput(const Instruction* /*instr*/) {
2658 // The base disasm does nothing more than disassembling into a buffer.
2659 }
2660
2661
AppendRegisterNameToOutput(const Instruction * instr,const CPURegister & reg)2662 void Disassembler::AppendRegisterNameToOutput(const Instruction* instr,
2663 const CPURegister& reg) {
2664 USE(instr);
2665 VIXL_ASSERT(reg.IsValid());
2666 char reg_char;
2667
2668 if (reg.IsRegister()) {
2669 reg_char = reg.Is64Bits() ? 'x' : 'w';
2670 } else {
2671 VIXL_ASSERT(reg.IsVRegister());
2672 switch (reg.SizeInBits()) {
2673 case kBRegSize: reg_char = 'b'; break;
2674 case kHRegSize: reg_char = 'h'; break;
2675 case kSRegSize: reg_char = 's'; break;
2676 case kDRegSize: reg_char = 'd'; break;
2677 default:
2678 VIXL_ASSERT(reg.Is128Bits());
2679 reg_char = 'q';
2680 }
2681 }
2682
2683 if (reg.IsVRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) {
2684 // A core or scalar/vector register: [wx]0 - 30, [bhsdq]0 - 31.
2685 AppendToOutput("%c%d", reg_char, reg.code());
2686 } else if (reg.Aliases(sp)) {
2687 // Disassemble w31/x31 as stack pointer wsp/sp.
2688 AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp");
2689 } else {
2690 // Disassemble w31/x31 as zero register wzr/xzr.
2691 AppendToOutput("%czr", reg_char);
2692 }
2693 }
2694
2695
AppendPCRelativeOffsetToOutput(const Instruction * instr,int64_t offset)2696 void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr,
2697 int64_t offset) {
2698 USE(instr);
2699 char sign = (offset < 0) ? '-' : '+';
2700 AppendToOutput("#%c0x%" PRIx64, sign, std::abs(offset));
2701 }
2702
2703
AppendAddressToOutput(const Instruction * instr,const void * addr)2704 void Disassembler::AppendAddressToOutput(const Instruction* instr,
2705 const void* addr) {
2706 USE(instr);
2707 AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast<uintptr_t>(addr));
2708 }
2709
2710
AppendCodeAddressToOutput(const Instruction * instr,const void * addr)2711 void Disassembler::AppendCodeAddressToOutput(const Instruction* instr,
2712 const void* addr) {
2713 AppendAddressToOutput(instr, addr);
2714 }
2715
2716
AppendDataAddressToOutput(const Instruction * instr,const void * addr)2717 void Disassembler::AppendDataAddressToOutput(const Instruction* instr,
2718 const void* addr) {
2719 AppendAddressToOutput(instr, addr);
2720 }
2721
2722
AppendCodeRelativeAddressToOutput(const Instruction * instr,const void * addr)2723 void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction* instr,
2724 const void* addr) {
2725 USE(instr);
2726 int64_t rel_addr = CodeRelativeAddress(addr);
2727 if (rel_addr >= 0) {
2728 AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr);
2729 } else {
2730 AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr);
2731 }
2732 }
2733
2734
AppendCodeRelativeCodeAddressToOutput(const Instruction * instr,const void * addr)2735 void Disassembler::AppendCodeRelativeCodeAddressToOutput(
2736 const Instruction* instr, const void* addr) {
2737 AppendCodeRelativeAddressToOutput(instr, addr);
2738 }
2739
2740
AppendCodeRelativeDataAddressToOutput(const Instruction * instr,const void * addr)2741 void Disassembler::AppendCodeRelativeDataAddressToOutput(
2742 const Instruction* instr, const void* addr) {
2743 AppendCodeRelativeAddressToOutput(instr, addr);
2744 }
2745
2746
MapCodeAddress(int64_t base_address,const Instruction * instr_address)2747 void Disassembler::MapCodeAddress(int64_t base_address,
2748 const Instruction* instr_address) {
2749 set_code_address_offset(
2750 base_address - reinterpret_cast<intptr_t>(instr_address));
2751 }
CodeRelativeAddress(const void * addr)2752 int64_t Disassembler::CodeRelativeAddress(const void* addr) {
2753 return reinterpret_cast<intptr_t>(addr) + code_address_offset();
2754 }
2755
2756
Format(const Instruction * instr,const char * mnemonic,const char * format)2757 void Disassembler::Format(const Instruction* instr, const char* mnemonic,
2758 const char* format) {
2759 VIXL_ASSERT(mnemonic != NULL);
2760 ResetOutput();
2761 uint32_t pos = buffer_pos_;
2762 Substitute(instr, mnemonic);
2763 if (format != NULL) {
2764 uint32_t spaces = buffer_pos_ - pos < 8 ? 8 - (buffer_pos_ - pos) : 1;
2765 while (spaces--) {
2766 VIXL_ASSERT(buffer_pos_ < buffer_size_);
2767 buffer_[buffer_pos_++] = ' ';
2768 }
2769 Substitute(instr, format);
2770 }
2771 VIXL_ASSERT(buffer_pos_ < buffer_size_);
2772 buffer_[buffer_pos_] = 0;
2773 ProcessOutput(instr);
2774 }
2775
2776
Substitute(const Instruction * instr,const char * string)2777 void Disassembler::Substitute(const Instruction* instr, const char* string) {
2778 char chr = *string++;
2779 while (chr != '\0') {
2780 if (chr == '\'') {
2781 string += SubstituteField(instr, string);
2782 } else {
2783 VIXL_ASSERT(buffer_pos_ < buffer_size_);
2784 buffer_[buffer_pos_++] = chr;
2785 }
2786 chr = *string++;
2787 }
2788 }
2789
2790
SubstituteField(const Instruction * instr,const char * format)2791 int Disassembler::SubstituteField(const Instruction* instr,
2792 const char* format) {
2793 switch (format[0]) {
2794 // NB. The remaining substitution prefix characters are: GJKUZ.
2795 case 'R': // Register. X or W, selected by sf bit.
2796 case 'F': // FP register. S or D, selected by type field.
2797 case 'V': // Vector register, V, vector format.
2798 case 'W':
2799 case 'X':
2800 case 'B':
2801 case 'H':
2802 case 'S':
2803 case 'D':
2804 case 'Q': return SubstituteRegisterField(instr, format);
2805 case 'I': return SubstituteImmediateField(instr, format);
2806 case 'L': return SubstituteLiteralField(instr, format);
2807 case 'N': return SubstituteShiftField(instr, format);
2808 case 'P': return SubstitutePrefetchField(instr, format);
2809 case 'C': return SubstituteConditionField(instr, format);
2810 case 'E': return SubstituteExtendField(instr, format);
2811 case 'A': return SubstitutePCRelAddressField(instr, format);
2812 case 'T': return SubstituteBranchTargetField(instr, format);
2813 case 'O': return SubstituteLSRegOffsetField(instr, format);
2814 case 'M': return SubstituteBarrierField(instr, format);
2815 case 'K': return SubstituteCrField(instr, format);
2816 case 'G': return SubstituteSysOpField(instr, format);
2817 default: {
2818 VIXL_UNREACHABLE();
2819 return 1;
2820 }
2821 }
2822 }
2823
2824
SubstituteRegisterField(const Instruction * instr,const char * format)2825 int Disassembler::SubstituteRegisterField(const Instruction* instr,
2826 const char* format) {
2827 char reg_prefix = format[0];
2828 unsigned reg_num = 0;
2829 unsigned field_len = 2;
2830
2831 switch (format[1]) {
2832 case 'd':
2833 reg_num = instr->Rd();
2834 if (format[2] == 'q') {
2835 reg_prefix = instr->NEONQ() ? 'X' : 'W';
2836 field_len = 3;
2837 }
2838 break;
2839 case 'n': reg_num = instr->Rn(); break;
2840 case 'm':
2841 reg_num = instr->Rm();
2842 switch (format[2]) {
2843 // Handle registers tagged with b (bytes), z (instruction), or
2844 // r (registers), used for address updates in
2845 // NEON load/store instructions.
2846 case 'r':
2847 case 'b':
2848 case 'z': {
2849 field_len = 3;
2850 char* eimm;
2851 int imm = static_cast<int>(strtol(&format[3], &eimm, 10));
2852 field_len += eimm - &format[3];
2853 if (reg_num == 31) {
2854 switch (format[2]) {
2855 case 'z':
2856 imm *= (1 << instr->NEONLSSize());
2857 break;
2858 case 'r':
2859 imm *= (instr->NEONQ() == 0) ? kDRegSizeInBytes
2860 : kQRegSizeInBytes;
2861 break;
2862 case 'b':
2863 break;
2864 }
2865 AppendToOutput("#%d", imm);
2866 return field_len;
2867 }
2868 break;
2869 }
2870 }
2871 break;
2872 case 'e':
2873 // This is register Rm, but using a 4-bit specifier. Used in NEON
2874 // by-element instructions.
2875 reg_num = (instr->Rm() & 0xf);
2876 break;
2877 case 'a': reg_num = instr->Ra(); break;
2878 case 's': reg_num = instr->Rs(); break;
2879 case 't':
2880 reg_num = instr->Rt();
2881 if (format[0] == 'V') {
2882 if ((format[2] >= '2') && (format[2] <= '4')) {
2883 // Handle consecutive vector register specifiers Vt2, Vt3 and Vt4.
2884 reg_num = (reg_num + format[2] - '1') % 32;
2885 field_len = 3;
2886 }
2887 } else {
2888 if (format[2] == '2') {
2889 // Handle register specifier Rt2.
2890 reg_num = instr->Rt2();
2891 field_len = 3;
2892 }
2893 }
2894 break;
2895 default: VIXL_UNREACHABLE();
2896 }
2897
2898 // Increase field length for registers tagged as stack.
2899 if (format[2] == 's') {
2900 field_len = 3;
2901 }
2902
2903 CPURegister::RegisterType reg_type = CPURegister::kRegister;
2904 unsigned reg_size = kXRegSize;
2905
2906 if (reg_prefix == 'R') {
2907 reg_prefix = instr->SixtyFourBits() ? 'X' : 'W';
2908 } else if (reg_prefix == 'F') {
2909 reg_prefix = ((instr->FPType() & 1) == 0) ? 'S' : 'D';
2910 }
2911
2912 switch (reg_prefix) {
2913 case 'W':
2914 reg_type = CPURegister::kRegister; reg_size = kWRegSize; break;
2915 case 'X':
2916 reg_type = CPURegister::kRegister; reg_size = kXRegSize; break;
2917 case 'B':
2918 reg_type = CPURegister::kVRegister; reg_size = kBRegSize; break;
2919 case 'H':
2920 reg_type = CPURegister::kVRegister; reg_size = kHRegSize; break;
2921 case 'S':
2922 reg_type = CPURegister::kVRegister; reg_size = kSRegSize; break;
2923 case 'D':
2924 reg_type = CPURegister::kVRegister; reg_size = kDRegSize; break;
2925 case 'Q':
2926 reg_type = CPURegister::kVRegister; reg_size = kQRegSize; break;
2927 case 'V':
2928 AppendToOutput("v%d", reg_num);
2929 return field_len;
2930 default:
2931 VIXL_UNREACHABLE();
2932 }
2933
2934 if ((reg_type == CPURegister::kRegister) &&
2935 (reg_num == kZeroRegCode) && (format[2] == 's')) {
2936 reg_num = kSPRegInternalCode;
2937 }
2938
2939 AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type));
2940
2941 return field_len;
2942 }
2943
2944
SubstituteImmediateField(const Instruction * instr,const char * format)2945 int Disassembler::SubstituteImmediateField(const Instruction* instr,
2946 const char* format) {
2947 VIXL_ASSERT(format[0] == 'I');
2948
2949 switch (format[1]) {
2950 case 'M': { // IMoveImm, IMoveNeg or IMoveLSL.
2951 if (format[5] == 'L') {
2952 AppendToOutput("#0x%" PRIx32, instr->ImmMoveWide());
2953 if (instr->ShiftMoveWide() > 0) {
2954 AppendToOutput(", lsl #%" PRId32, 16 * instr->ShiftMoveWide());
2955 }
2956 } else {
2957 VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N'));
2958 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide()) <<
2959 (16 * instr->ShiftMoveWide());
2960 if (format[5] == 'N')
2961 imm = ~imm;
2962 if (!instr->SixtyFourBits())
2963 imm &= UINT64_C(0xffffffff);
2964 AppendToOutput("#0x%" PRIx64, imm);
2965 }
2966 return 8;
2967 }
2968 case 'L': {
2969 switch (format[2]) {
2970 case 'L': { // ILLiteral - Immediate Load Literal.
2971 AppendToOutput("pc%+" PRId32,
2972 instr->ImmLLiteral() << kLiteralEntrySizeLog2);
2973 return 9;
2974 }
2975 case 'S': { // ILS - Immediate Load/Store.
2976 if (instr->ImmLS() != 0) {
2977 AppendToOutput(", #%" PRId32, instr->ImmLS());
2978 }
2979 return 3;
2980 }
2981 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
2982 if (instr->ImmLSPair() != 0) {
2983 // format[3] is the scale value. Convert to a number.
2984 int scale = 1 << (format[3] - '0');
2985 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale);
2986 }
2987 return 4;
2988 }
2989 case 'U': { // ILU - Immediate Load/Store Unsigned.
2990 if (instr->ImmLSUnsigned() != 0) {
2991 int shift = instr->SizeLS();
2992 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() << shift);
2993 }
2994 return 3;
2995 }
2996 default: {
2997 VIXL_UNIMPLEMENTED();
2998 return 0;
2999 }
3000 }
3001 }
3002 case 'C': { // ICondB - Immediate Conditional Branch.
3003 int64_t offset = instr->ImmCondBranch() << 2;
3004 AppendPCRelativeOffsetToOutput(instr, offset);
3005 return 6;
3006 }
3007 case 'A': { // IAddSub.
3008 VIXL_ASSERT(instr->ShiftAddSub() <= 1);
3009 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
3010 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
3011 return 7;
3012 }
3013 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
3014 if (format[3] == 'F') { // IFPFbits.
3015 AppendToOutput("#%" PRId32, 64 - instr->FPScale());
3016 return 8;
3017 } else {
3018 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmFP(),
3019 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
3020 return 9;
3021 }
3022 }
3023 case 'T': { // ITri - Immediate Triangular Encoded.
3024 AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
3025 return 4;
3026 }
3027 case 'N': { // INzcv.
3028 int nzcv = (instr->Nzcv() << Flags_offset);
3029 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
3030 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
3031 ((nzcv & CFlag) == 0) ? 'c' : 'C',
3032 ((nzcv & VFlag) == 0) ? 'v' : 'V');
3033 return 5;
3034 }
3035 case 'P': { // IP - Conditional compare.
3036 AppendToOutput("#%" PRId32, instr->ImmCondCmp());
3037 return 2;
3038 }
3039 case 'B': { // Bitfields.
3040 return SubstituteBitfieldImmediateField(instr, format);
3041 }
3042 case 'E': { // IExtract.
3043 AppendToOutput("#%" PRId32, instr->ImmS());
3044 return 8;
3045 }
3046 case 'S': { // IS - Test and branch bit.
3047 AppendToOutput("#%" PRId32, (instr->ImmTestBranchBit5() << 5) |
3048 instr->ImmTestBranchBit40());
3049 return 2;
3050 }
3051 case 's': { // Is - Shift (immediate).
3052 switch (format[2]) {
3053 case '1': { // Is1 - SSHR.
3054 int shift = 16 << HighestSetBitPosition(instr->ImmNEONImmh());
3055 shift -= instr->ImmNEONImmhImmb();
3056 AppendToOutput("#%d", shift);
3057 return 3;
3058 }
3059 case '2': { // Is2 - SLI.
3060 int shift = instr->ImmNEONImmhImmb();
3061 shift -= 8 << HighestSetBitPosition(instr->ImmNEONImmh());
3062 AppendToOutput("#%d", shift);
3063 return 3;
3064 }
3065 default: {
3066 VIXL_UNIMPLEMENTED();
3067 return 0;
3068 }
3069 }
3070 }
3071 case 'D': { // IDebug - HLT and BRK instructions.
3072 AppendToOutput("#0x%" PRIx32, instr->ImmException());
3073 return 6;
3074 }
3075 case 'V': { // Immediate Vector.
3076 switch (format[2]) {
3077 case 'E': { // IVExtract.
3078 AppendToOutput("#%" PRId32, instr->ImmNEONExt());
3079 return 9;
3080 }
3081 case 'B': { // IVByElemIndex.
3082 int vm_index = (instr->NEONH() << 1) | instr->NEONL();
3083 if (instr->NEONSize() == 1) {
3084 vm_index = (vm_index << 1) | instr->NEONM();
3085 }
3086 AppendToOutput("%d", vm_index);
3087 return strlen("IVByElemIndex");
3088 }
3089 case 'I': { // INS element.
3090 if (strncmp(format, "IVInsIndex", strlen("IVInsIndex")) == 0) {
3091 int rd_index, rn_index;
3092 int imm5 = instr->ImmNEON5();
3093 int imm4 = instr->ImmNEON4();
3094 int tz = CountTrailingZeros(imm5, 32);
3095 rd_index = imm5 >> (tz + 1);
3096 rn_index = imm4 >> tz;
3097 if (strncmp(format, "IVInsIndex1", strlen("IVInsIndex1")) == 0) {
3098 AppendToOutput("%d", rd_index);
3099 return strlen("IVInsIndex1");
3100 } else if (strncmp(format, "IVInsIndex2",
3101 strlen("IVInsIndex2")) == 0) {
3102 AppendToOutput("%d", rn_index);
3103 return strlen("IVInsIndex2");
3104 } else {
3105 VIXL_UNIMPLEMENTED();
3106 return 0;
3107 }
3108 }
3109 VIXL_FALLTHROUGH();
3110 }
3111 case 'L': { // IVLSLane[0123] - suffix indicates access size shift.
3112 AppendToOutput("%d", instr->NEONLSIndex(format[8] - '0'));
3113 return 9;
3114 }
3115 case 'M': { // Modified Immediate cases.
3116 if (strncmp(format,
3117 "IVMIImmFPSingle",
3118 strlen("IVMIImmFPSingle")) == 0) {
3119 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(),
3120 instr->ImmNEONFP32());
3121 return strlen("IVMIImmFPSingle");
3122 } else if (strncmp(format,
3123 "IVMIImmFPDouble",
3124 strlen("IVMIImmFPDouble")) == 0) {
3125 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(),
3126 instr->ImmNEONFP64());
3127 return strlen("IVMIImmFPDouble");
3128 } else if (strncmp(format, "IVMIImm8", strlen("IVMIImm8")) == 0) {
3129 uint64_t imm8 = instr->ImmNEONabcdefgh();
3130 AppendToOutput("#0x%" PRIx64, imm8);
3131 return strlen("IVMIImm8");
3132 } else if (strncmp(format, "IVMIImm", strlen("IVMIImm")) == 0) {
3133 uint64_t imm8 = instr->ImmNEONabcdefgh();
3134 uint64_t imm = 0;
3135 for (int i = 0; i < 8; ++i) {
3136 if (imm8 & (1ULL << i)) {
3137 imm |= (UINT64_C(0xff) << (8 * i));
3138 }
3139 }
3140 AppendToOutput("#0x%" PRIx64, imm);
3141 return strlen("IVMIImm");
3142 } else if (strncmp(format, "IVMIShiftAmt1",
3143 strlen("IVMIShiftAmt1")) == 0) {
3144 int cmode = instr->NEONCmode();
3145 int shift_amount = 8 * ((cmode >> 1) & 3);
3146 AppendToOutput("#%d", shift_amount);
3147 return strlen("IVMIShiftAmt1");
3148 } else if (strncmp(format, "IVMIShiftAmt2",
3149 strlen("IVMIShiftAmt2")) == 0) {
3150 int cmode = instr->NEONCmode();
3151 int shift_amount = 8 << (cmode & 1);
3152 AppendToOutput("#%d", shift_amount);
3153 return strlen("IVMIShiftAmt2");
3154 } else {
3155 VIXL_UNIMPLEMENTED();
3156 return 0;
3157 }
3158 }
3159 default: {
3160 VIXL_UNIMPLEMENTED();
3161 return 0;
3162 }
3163 }
3164 }
3165 case 'X': { // IX - CLREX instruction.
3166 AppendToOutput("#0x%" PRIx32, instr->CRm());
3167 return 2;
3168 }
3169 default: {
3170 VIXL_UNIMPLEMENTED();
3171 return 0;
3172 }
3173 }
3174 }
3175
3176
SubstituteBitfieldImmediateField(const Instruction * instr,const char * format)3177 int Disassembler::SubstituteBitfieldImmediateField(const Instruction* instr,
3178 const char* format) {
3179 VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
3180 unsigned r = instr->ImmR();
3181 unsigned s = instr->ImmS();
3182
3183 switch (format[2]) {
3184 case 'r': { // IBr.
3185 AppendToOutput("#%d", r);
3186 return 3;
3187 }
3188 case 's': { // IBs+1 or IBs-r+1.
3189 if (format[3] == '+') {
3190 AppendToOutput("#%d", s + 1);
3191 return 5;
3192 } else {
3193 VIXL_ASSERT(format[3] == '-');
3194 AppendToOutput("#%d", s - r + 1);
3195 return 7;
3196 }
3197 }
3198 case 'Z': { // IBZ-r.
3199 VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));
3200 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
3201 AppendToOutput("#%d", reg_size - r);
3202 return 5;
3203 }
3204 default: {
3205 VIXL_UNREACHABLE();
3206 return 0;
3207 }
3208 }
3209 }
3210
3211
SubstituteLiteralField(const Instruction * instr,const char * format)3212 int Disassembler::SubstituteLiteralField(const Instruction* instr,
3213 const char* format) {
3214 VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
3215 USE(format);
3216
3217 const void * address = instr->LiteralAddress<const void *>();
3218 switch (instr->Mask(LoadLiteralMask)) {
3219 case LDR_w_lit:
3220 case LDR_x_lit:
3221 case LDRSW_x_lit:
3222 case LDR_s_lit:
3223 case LDR_d_lit:
3224 case LDR_q_lit:
3225 AppendCodeRelativeDataAddressToOutput(instr, address);
3226 break;
3227 case PRFM_lit: {
3228 // Use the prefetch hint to decide how to print the address.
3229 switch (instr->PrefetchHint()) {
3230 case 0x0: // PLD: prefetch for load.
3231 case 0x2: // PST: prepare for store.
3232 AppendCodeRelativeDataAddressToOutput(instr, address);
3233 break;
3234 case 0x1: // PLI: preload instructions.
3235 AppendCodeRelativeCodeAddressToOutput(instr, address);
3236 break;
3237 case 0x3: // Unallocated hint.
3238 AppendCodeRelativeAddressToOutput(instr, address);
3239 break;
3240 }
3241 break;
3242 }
3243 default:
3244 VIXL_UNREACHABLE();
3245 }
3246
3247 return 6;
3248 }
3249
3250
SubstituteShiftField(const Instruction * instr,const char * format)3251 int Disassembler::SubstituteShiftField(const Instruction* instr,
3252 const char* format) {
3253 VIXL_ASSERT(format[0] == 'N');
3254 VIXL_ASSERT(instr->ShiftDP() <= 0x3);
3255
3256 switch (format[1]) {
3257 case 'D': { // HDP.
3258 VIXL_ASSERT(instr->ShiftDP() != ROR);
3259 VIXL_FALLTHROUGH();
3260 }
3261 case 'L': { // HLo.
3262 if (instr->ImmDPShift() != 0) {
3263 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
3264 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()],
3265 instr->ImmDPShift());
3266 }
3267 return 3;
3268 }
3269 default:
3270 VIXL_UNIMPLEMENTED();
3271 return 0;
3272 }
3273 }
3274
3275
SubstituteConditionField(const Instruction * instr,const char * format)3276 int Disassembler::SubstituteConditionField(const Instruction* instr,
3277 const char* format) {
3278 VIXL_ASSERT(format[0] == 'C');
3279 const char* condition_code[] = { "eq", "ne", "hs", "lo",
3280 "mi", "pl", "vs", "vc",
3281 "hi", "ls", "ge", "lt",
3282 "gt", "le", "al", "nv" };
3283 int cond;
3284 switch (format[1]) {
3285 case 'B': cond = instr->ConditionBranch(); break;
3286 case 'I': {
3287 cond = InvertCondition(static_cast<Condition>(instr->Condition()));
3288 break;
3289 }
3290 default: cond = instr->Condition();
3291 }
3292 AppendToOutput("%s", condition_code[cond]);
3293 return 4;
3294 }
3295
3296
SubstitutePCRelAddressField(const Instruction * instr,const char * format)3297 int Disassembler::SubstitutePCRelAddressField(const Instruction* instr,
3298 const char* format) {
3299 VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`.
3300 (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.
3301
3302 int64_t offset = instr->ImmPCRel();
3303
3304 // Compute the target address based on the effective address (after applying
3305 // code_address_offset). This is required for correct behaviour of adrp.
3306 const Instruction* base = instr + code_address_offset();
3307 if (format[9] == 'P') {
3308 offset *= kPageSize;
3309 base = AlignDown(base, kPageSize);
3310 }
3311 // Strip code_address_offset before printing, so we can use the
3312 // semantically-correct AppendCodeRelativeAddressToOutput.
3313 const void* target =
3314 reinterpret_cast<const void*>(base + offset - code_address_offset());
3315
3316 AppendPCRelativeOffsetToOutput(instr, offset);
3317 AppendToOutput(" ");
3318 AppendCodeRelativeAddressToOutput(instr, target);
3319 return 13;
3320 }
3321
3322
SubstituteBranchTargetField(const Instruction * instr,const char * format)3323 int Disassembler::SubstituteBranchTargetField(const Instruction* instr,
3324 const char* format) {
3325 VIXL_ASSERT(strncmp(format, "TImm", 4) == 0);
3326
3327 int64_t offset = 0;
3328 switch (format[5]) {
3329 // BImmUncn - unconditional branch immediate.
3330 case 'n': offset = instr->ImmUncondBranch(); break;
3331 // BImmCond - conditional branch immediate.
3332 case 'o': offset = instr->ImmCondBranch(); break;
3333 // BImmCmpa - compare and branch immediate.
3334 case 'm': offset = instr->ImmCmpBranch(); break;
3335 // BImmTest - test and branch immediate.
3336 case 'e': offset = instr->ImmTestBranch(); break;
3337 default: VIXL_UNIMPLEMENTED();
3338 }
3339 offset <<= kInstructionSizeLog2;
3340 const void* target_address = reinterpret_cast<const void*>(instr + offset);
3341 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
3342
3343 AppendPCRelativeOffsetToOutput(instr, offset);
3344 AppendToOutput(" ");
3345 AppendCodeRelativeCodeAddressToOutput(instr, target_address);
3346
3347 return 8;
3348 }
3349
3350
SubstituteExtendField(const Instruction * instr,const char * format)3351 int Disassembler::SubstituteExtendField(const Instruction* instr,
3352 const char* format) {
3353 VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
3354 VIXL_ASSERT(instr->ExtendMode() <= 7);
3355 USE(format);
3356
3357 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
3358 "sxtb", "sxth", "sxtw", "sxtx" };
3359
3360 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
3361 // registers becomes lsl.
3362 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
3363 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
3364 (instr->ExtendMode() == UXTX))) {
3365 if (instr->ImmExtendShift() > 0) {
3366 AppendToOutput(", lsl #%" PRId32, instr->ImmExtendShift());
3367 }
3368 } else {
3369 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
3370 if (instr->ImmExtendShift() > 0) {
3371 AppendToOutput(" #%" PRId32, instr->ImmExtendShift());
3372 }
3373 }
3374 return 3;
3375 }
3376
3377
SubstituteLSRegOffsetField(const Instruction * instr,const char * format)3378 int Disassembler::SubstituteLSRegOffsetField(const Instruction* instr,
3379 const char* format) {
3380 VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
3381 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
3382 "undefined", "undefined", "sxtw", "sxtx" };
3383 USE(format);
3384
3385 unsigned shift = instr->ImmShiftLS();
3386 Extend ext = static_cast<Extend>(instr->ExtendMode());
3387 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
3388
3389 unsigned rm = instr->Rm();
3390 if (rm == kZeroRegCode) {
3391 AppendToOutput("%czr", reg_type);
3392 } else {
3393 AppendToOutput("%c%d", reg_type, rm);
3394 }
3395
3396 // Extend mode UXTX is an alias for shift mode LSL here.
3397 if (!((ext == UXTX) && (shift == 0))) {
3398 AppendToOutput(", %s", extend_mode[ext]);
3399 if (shift != 0) {
3400 AppendToOutput(" #%d", instr->SizeLS());
3401 }
3402 }
3403 return 9;
3404 }
3405
3406
SubstitutePrefetchField(const Instruction * instr,const char * format)3407 int Disassembler::SubstitutePrefetchField(const Instruction* instr,
3408 const char* format) {
3409 VIXL_ASSERT(format[0] == 'P');
3410 USE(format);
3411
3412 static const char* hints[] = {"ld", "li", "st"};
3413 static const char* stream_options[] = {"keep", "strm"};
3414
3415 unsigned hint = instr->PrefetchHint();
3416 unsigned target = instr->PrefetchTarget() + 1;
3417 unsigned stream = instr->PrefetchStream();
3418
3419 if ((hint >= (sizeof(hints) / sizeof(hints[0]))) || (target > 3)) {
3420 // Unallocated prefetch operations.
3421 int prefetch_mode = instr->ImmPrefetchOperation();
3422 AppendToOutput("#0b%c%c%c%c%c",
3423 (prefetch_mode & (1 << 4)) ? '1' : '0',
3424 (prefetch_mode & (1 << 3)) ? '1' : '0',
3425 (prefetch_mode & (1 << 2)) ? '1' : '0',
3426 (prefetch_mode & (1 << 1)) ? '1' : '0',
3427 (prefetch_mode & (1 << 0)) ? '1' : '0');
3428 } else {
3429 VIXL_ASSERT(stream < (sizeof(stream_options) / sizeof(stream_options[0])));
3430 AppendToOutput("p%sl%d%s", hints[hint], target, stream_options[stream]);
3431 }
3432 return 6;
3433 }
3434
SubstituteBarrierField(const Instruction * instr,const char * format)3435 int Disassembler::SubstituteBarrierField(const Instruction* instr,
3436 const char* format) {
3437 VIXL_ASSERT(format[0] == 'M');
3438 USE(format);
3439
3440 static const char* options[4][4] = {
3441 { "sy (0b0000)", "oshld", "oshst", "osh" },
3442 { "sy (0b0100)", "nshld", "nshst", "nsh" },
3443 { "sy (0b1000)", "ishld", "ishst", "ish" },
3444 { "sy (0b1100)", "ld", "st", "sy" }
3445 };
3446 int domain = instr->ImmBarrierDomain();
3447 int type = instr->ImmBarrierType();
3448
3449 AppendToOutput("%s", options[domain][type]);
3450 return 1;
3451 }
3452
SubstituteSysOpField(const Instruction * instr,const char * format)3453 int Disassembler::SubstituteSysOpField(const Instruction* instr,
3454 const char* format) {
3455 VIXL_ASSERT(format[0] == 'G');
3456 int op = -1;
3457 switch (format[1]) {
3458 case '1': op = instr->SysOp1(); break;
3459 case '2': op = instr->SysOp2(); break;
3460 default:
3461 VIXL_UNREACHABLE();
3462 }
3463 AppendToOutput("#%d", op);
3464 return 2;
3465 }
3466
SubstituteCrField(const Instruction * instr,const char * format)3467 int Disassembler::SubstituteCrField(const Instruction* instr,
3468 const char* format) {
3469 VIXL_ASSERT(format[0] == 'K');
3470 int cr = -1;
3471 switch (format[1]) {
3472 case 'n': cr = instr->CRn(); break;
3473 case 'm': cr = instr->CRm(); break;
3474 default:
3475 VIXL_UNREACHABLE();
3476 }
3477 AppendToOutput("C%d", cr);
3478 return 2;
3479 }
3480
ResetOutput()3481 void Disassembler::ResetOutput() {
3482 buffer_pos_ = 0;
3483 buffer_[buffer_pos_] = 0;
3484 }
3485
3486
AppendToOutput(const char * format,...)3487 void Disassembler::AppendToOutput(const char* format, ...) {
3488 va_list args;
3489 va_start(args, format);
3490 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_ - buffer_pos_,
3491 format, args);
3492 va_end(args);
3493 }
3494
3495
ProcessOutput(const Instruction * instr)3496 void PrintDisassembler::ProcessOutput(const Instruction* instr) {
3497 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
3498 reinterpret_cast<uint64_t>(instr),
3499 instr->InstructionBits(),
3500 GetOutput());
3501 }
3502
DisassembleInstruction(char * buffer,size_t bufsize,const Instruction * instr)3503 void DisassembleInstruction(char* buffer, size_t bufsize, const Instruction* instr)
3504 {
3505 vixl::Disassembler disasm(buffer, bufsize-1);
3506 vixl::Decoder decoder;
3507 decoder.AppendVisitor(&disasm);
3508 decoder.Decode(instr);
3509 buffer[bufsize-1] = 0; // Just to be safe
3510 }
3511
GdbDisassembleInstruction(const Instruction * instr)3512 char* GdbDisassembleInstruction(const Instruction* instr)
3513 {
3514 static char buffer[1024];
3515 DisassembleInstruction(buffer, sizeof(buffer), instr);
3516 return buffer;
3517 }
3518
3519 } // namespace vixl
3520