1 // Copyright 2015, VIXL authors
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 <cstdlib>
28
29 #include "disasm-aarch64.h"
30
31 namespace vixl {
32 namespace aarch64 {
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() { return buffer_; }
60
61
VisitAddSubImmediate(const Instruction * instr)62 void Disassembler::VisitAddSubImmediate(const Instruction *instr) {
63 bool rd_is_zr = RdIsZROrSP(instr);
64 bool stack_op =
65 (rd_is_zr || RnIsZROrSP(instr)) && (instr->GetImmAddSub() == 0) ? true
66 : false;
67 const char *mnemonic = "";
68 const char *form = "'Rds, 'Rns, 'IAddSub";
69 const char *form_cmp = "'Rns, 'IAddSub";
70 const char *form_mov = "'Rds, 'Rns";
71
72 switch (instr->Mask(AddSubImmediateMask)) {
73 case ADD_w_imm:
74 case ADD_x_imm: {
75 mnemonic = "add";
76 if (stack_op) {
77 mnemonic = "mov";
78 form = form_mov;
79 }
80 break;
81 }
82 case ADDS_w_imm:
83 case ADDS_x_imm: {
84 mnemonic = "adds";
85 if (rd_is_zr) {
86 mnemonic = "cmn";
87 form = form_cmp;
88 }
89 break;
90 }
91 case SUB_w_imm:
92 case SUB_x_imm:
93 mnemonic = "sub";
94 break;
95 case SUBS_w_imm:
96 case SUBS_x_imm: {
97 mnemonic = "subs";
98 if (rd_is_zr) {
99 mnemonic = "cmp";
100 form = form_cmp;
101 }
102 break;
103 }
104 default:
105 VIXL_UNREACHABLE();
106 }
107 Format(instr, mnemonic, form);
108 }
109
110
VisitAddSubShifted(const Instruction * instr)111 void Disassembler::VisitAddSubShifted(const Instruction *instr) {
112 bool rd_is_zr = RdIsZROrSP(instr);
113 bool rn_is_zr = RnIsZROrSP(instr);
114 const char *mnemonic = "";
115 const char *form = "'Rd, 'Rn, 'Rm'NDP";
116 const char *form_cmp = "'Rn, 'Rm'NDP";
117 const char *form_neg = "'Rd, 'Rm'NDP";
118
119 switch (instr->Mask(AddSubShiftedMask)) {
120 case ADD_w_shift:
121 case ADD_x_shift:
122 mnemonic = "add";
123 break;
124 case ADDS_w_shift:
125 case ADDS_x_shift: {
126 mnemonic = "adds";
127 if (rd_is_zr) {
128 mnemonic = "cmn";
129 form = form_cmp;
130 }
131 break;
132 }
133 case SUB_w_shift:
134 case SUB_x_shift: {
135 mnemonic = "sub";
136 if (rn_is_zr) {
137 mnemonic = "neg";
138 form = form_neg;
139 }
140 break;
141 }
142 case SUBS_w_shift:
143 case SUBS_x_shift: {
144 mnemonic = "subs";
145 if (rd_is_zr) {
146 mnemonic = "cmp";
147 form = form_cmp;
148 } else if (rn_is_zr) {
149 mnemonic = "negs";
150 form = form_neg;
151 }
152 break;
153 }
154 default:
155 VIXL_UNREACHABLE();
156 }
157 Format(instr, mnemonic, form);
158 }
159
160
VisitAddSubExtended(const Instruction * instr)161 void Disassembler::VisitAddSubExtended(const Instruction *instr) {
162 bool rd_is_zr = RdIsZROrSP(instr);
163 const char *mnemonic = "";
164 Extend mode = static_cast<Extend>(instr->GetExtendMode());
165 const char *form = ((mode == UXTX) || (mode == SXTX)) ? "'Rds, 'Rns, 'Xm'Ext"
166 : "'Rds, 'Rns, 'Wm'Ext";
167 const char *form_cmp =
168 ((mode == UXTX) || (mode == SXTX)) ? "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
169
170 switch (instr->Mask(AddSubExtendedMask)) {
171 case ADD_w_ext:
172 case ADD_x_ext:
173 mnemonic = "add";
174 break;
175 case ADDS_w_ext:
176 case ADDS_x_ext: {
177 mnemonic = "adds";
178 if (rd_is_zr) {
179 mnemonic = "cmn";
180 form = form_cmp;
181 }
182 break;
183 }
184 case SUB_w_ext:
185 case SUB_x_ext:
186 mnemonic = "sub";
187 break;
188 case SUBS_w_ext:
189 case SUBS_x_ext: {
190 mnemonic = "subs";
191 if (rd_is_zr) {
192 mnemonic = "cmp";
193 form = form_cmp;
194 }
195 break;
196 }
197 default:
198 VIXL_UNREACHABLE();
199 }
200 Format(instr, mnemonic, form);
201 }
202
203
VisitAddSubWithCarry(const Instruction * instr)204 void Disassembler::VisitAddSubWithCarry(const Instruction *instr) {
205 bool rn_is_zr = RnIsZROrSP(instr);
206 const char *mnemonic = "";
207 const char *form = "'Rd, 'Rn, 'Rm";
208 const char *form_neg = "'Rd, 'Rm";
209
210 switch (instr->Mask(AddSubWithCarryMask)) {
211 case ADC_w:
212 case ADC_x:
213 mnemonic = "adc";
214 break;
215 case ADCS_w:
216 case ADCS_x:
217 mnemonic = "adcs";
218 break;
219 case SBC_w:
220 case SBC_x: {
221 mnemonic = "sbc";
222 if (rn_is_zr) {
223 mnemonic = "ngc";
224 form = form_neg;
225 }
226 break;
227 }
228 case SBCS_w:
229 case SBCS_x: {
230 mnemonic = "sbcs";
231 if (rn_is_zr) {
232 mnemonic = "ngcs";
233 form = form_neg;
234 }
235 break;
236 }
237 default:
238 VIXL_UNREACHABLE();
239 }
240 Format(instr, mnemonic, form);
241 }
242
243
VisitLogicalImmediate(const Instruction * instr)244 void Disassembler::VisitLogicalImmediate(const Instruction *instr) {
245 bool rd_is_zr = RdIsZROrSP(instr);
246 bool rn_is_zr = RnIsZROrSP(instr);
247 const char *mnemonic = "";
248 const char *form = "'Rds, 'Rn, 'ITri";
249
250 if (instr->GetImmLogical() == 0) {
251 // The immediate encoded in the instruction is not in the expected format.
252 Format(instr, "unallocated", "(LogicalImmediate)");
253 return;
254 }
255
256 switch (instr->Mask(LogicalImmediateMask)) {
257 case AND_w_imm:
258 case AND_x_imm:
259 mnemonic = "and";
260 break;
261 case ORR_w_imm:
262 case ORR_x_imm: {
263 mnemonic = "orr";
264 unsigned reg_size =
265 (instr->GetSixtyFourBits() == 1) ? kXRegSize : kWRegSize;
266 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->GetImmLogical())) {
267 mnemonic = "mov";
268 form = "'Rds, 'ITri";
269 }
270 break;
271 }
272 case EOR_w_imm:
273 case EOR_x_imm:
274 mnemonic = "eor";
275 break;
276 case ANDS_w_imm:
277 case ANDS_x_imm: {
278 mnemonic = "ands";
279 if (rd_is_zr) {
280 mnemonic = "tst";
281 form = "'Rn, 'ITri";
282 }
283 break;
284 }
285 default:
286 VIXL_UNREACHABLE();
287 }
288 Format(instr, mnemonic, form);
289 }
290
291
IsMovzMovnImm(unsigned reg_size,uint64_t value)292 bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
293 VIXL_ASSERT((reg_size == kXRegSize) ||
294 ((reg_size == kWRegSize) && (value <= 0xffffffff)));
295
296 // Test for movz: 16 bits set at positions 0, 16, 32 or 48.
297 if (((value & UINT64_C(0xffffffffffff0000)) == 0) ||
298 ((value & UINT64_C(0xffffffff0000ffff)) == 0) ||
299 ((value & UINT64_C(0xffff0000ffffffff)) == 0) ||
300 ((value & UINT64_C(0x0000ffffffffffff)) == 0)) {
301 return true;
302 }
303
304 // Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
305 if ((reg_size == kXRegSize) &&
306 (((~value & UINT64_C(0xffffffffffff0000)) == 0) ||
307 ((~value & UINT64_C(0xffffffff0000ffff)) == 0) ||
308 ((~value & UINT64_C(0xffff0000ffffffff)) == 0) ||
309 ((~value & UINT64_C(0x0000ffffffffffff)) == 0))) {
310 return true;
311 }
312 if ((reg_size == kWRegSize) && (((value & 0xffff0000) == 0xffff0000) ||
313 ((value & 0x0000ffff) == 0x0000ffff))) {
314 return true;
315 }
316 return false;
317 }
318
319
VisitLogicalShifted(const Instruction * instr)320 void Disassembler::VisitLogicalShifted(const Instruction *instr) {
321 bool rd_is_zr = RdIsZROrSP(instr);
322 bool rn_is_zr = RnIsZROrSP(instr);
323 const char *mnemonic = "";
324 const char *form = "'Rd, 'Rn, 'Rm'NLo";
325
326 switch (instr->Mask(LogicalShiftedMask)) {
327 case AND_w:
328 case AND_x:
329 mnemonic = "and";
330 break;
331 case BIC_w:
332 case BIC_x:
333 mnemonic = "bic";
334 break;
335 case EOR_w:
336 case EOR_x:
337 mnemonic = "eor";
338 break;
339 case EON_w:
340 case EON_x:
341 mnemonic = "eon";
342 break;
343 case BICS_w:
344 case BICS_x:
345 mnemonic = "bics";
346 break;
347 case ANDS_w:
348 case ANDS_x: {
349 mnemonic = "ands";
350 if (rd_is_zr) {
351 mnemonic = "tst";
352 form = "'Rn, 'Rm'NLo";
353 }
354 break;
355 }
356 case ORR_w:
357 case ORR_x: {
358 mnemonic = "orr";
359 if (rn_is_zr && (instr->GetImmDPShift() == 0) &&
360 (instr->GetShiftDP() == LSL)) {
361 mnemonic = "mov";
362 form = "'Rd, 'Rm";
363 }
364 break;
365 }
366 case ORN_w:
367 case ORN_x: {
368 mnemonic = "orn";
369 if (rn_is_zr) {
370 mnemonic = "mvn";
371 form = "'Rd, 'Rm'NLo";
372 }
373 break;
374 }
375 default:
376 VIXL_UNREACHABLE();
377 }
378
379 Format(instr, mnemonic, form);
380 }
381
382
VisitConditionalCompareRegister(const Instruction * instr)383 void Disassembler::VisitConditionalCompareRegister(const Instruction *instr) {
384 const char *mnemonic = "";
385 const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
386
387 switch (instr->Mask(ConditionalCompareRegisterMask)) {
388 case CCMN_w:
389 case CCMN_x:
390 mnemonic = "ccmn";
391 break;
392 case CCMP_w:
393 case CCMP_x:
394 mnemonic = "ccmp";
395 break;
396 default:
397 VIXL_UNREACHABLE();
398 }
399 Format(instr, mnemonic, form);
400 }
401
402
VisitConditionalCompareImmediate(const Instruction * instr)403 void Disassembler::VisitConditionalCompareImmediate(const Instruction *instr) {
404 const char *mnemonic = "";
405 const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
406
407 switch (instr->Mask(ConditionalCompareImmediateMask)) {
408 case CCMN_w_imm:
409 case CCMN_x_imm:
410 mnemonic = "ccmn";
411 break;
412 case CCMP_w_imm:
413 case CCMP_x_imm:
414 mnemonic = "ccmp";
415 break;
416 default:
417 VIXL_UNREACHABLE();
418 }
419 Format(instr, mnemonic, form);
420 }
421
422
VisitConditionalSelect(const Instruction * instr)423 void Disassembler::VisitConditionalSelect(const Instruction *instr) {
424 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
425 bool rn_is_rm = (instr->GetRn() == instr->GetRm());
426 const char *mnemonic = "";
427 const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
428 const char *form_test = "'Rd, 'CInv";
429 const char *form_update = "'Rd, 'Rn, 'CInv";
430
431 Condition cond = static_cast<Condition>(instr->GetCondition());
432 bool invertible_cond = (cond != al) && (cond != nv);
433
434 switch (instr->Mask(ConditionalSelectMask)) {
435 case CSEL_w:
436 case CSEL_x:
437 mnemonic = "csel";
438 break;
439 case CSINC_w:
440 case CSINC_x: {
441 mnemonic = "csinc";
442 if (rnm_is_zr && invertible_cond) {
443 mnemonic = "cset";
444 form = form_test;
445 } else if (rn_is_rm && invertible_cond) {
446 mnemonic = "cinc";
447 form = form_update;
448 }
449 break;
450 }
451 case CSINV_w:
452 case CSINV_x: {
453 mnemonic = "csinv";
454 if (rnm_is_zr && invertible_cond) {
455 mnemonic = "csetm";
456 form = form_test;
457 } else if (rn_is_rm && invertible_cond) {
458 mnemonic = "cinv";
459 form = form_update;
460 }
461 break;
462 }
463 case CSNEG_w:
464 case CSNEG_x: {
465 mnemonic = "csneg";
466 if (rn_is_rm && invertible_cond) {
467 mnemonic = "cneg";
468 form = form_update;
469 }
470 break;
471 }
472 default:
473 VIXL_UNREACHABLE();
474 }
475 Format(instr, mnemonic, form);
476 }
477
478
VisitBitfield(const Instruction * instr)479 void Disassembler::VisitBitfield(const Instruction *instr) {
480 unsigned s = instr->GetImmS();
481 unsigned r = instr->GetImmR();
482 unsigned rd_size_minus_1 =
483 ((instr->GetSixtyFourBits() == 1) ? kXRegSize : kWRegSize) - 1;
484 const char *mnemonic = "";
485 const char *form = "";
486 const char *form_shift_right = "'Rd, 'Rn, 'IBr";
487 const char *form_extend = "'Rd, 'Wn";
488 const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
489 const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
490 const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
491
492 switch (instr->Mask(BitfieldMask)) {
493 case SBFM_w:
494 case SBFM_x: {
495 mnemonic = "sbfx";
496 form = form_bfx;
497 if (r == 0) {
498 form = form_extend;
499 if (s == 7) {
500 mnemonic = "sxtb";
501 } else if (s == 15) {
502 mnemonic = "sxth";
503 } else if ((s == 31) && (instr->GetSixtyFourBits() == 1)) {
504 mnemonic = "sxtw";
505 } else {
506 form = form_bfx;
507 }
508 } else if (s == rd_size_minus_1) {
509 mnemonic = "asr";
510 form = form_shift_right;
511 } else if (s < r) {
512 mnemonic = "sbfiz";
513 form = form_bfiz;
514 }
515 break;
516 }
517 case UBFM_w:
518 case UBFM_x: {
519 mnemonic = "ubfx";
520 form = form_bfx;
521 if (r == 0) {
522 form = form_extend;
523 if (s == 7) {
524 mnemonic = "uxtb";
525 } else if (s == 15) {
526 mnemonic = "uxth";
527 } else {
528 form = form_bfx;
529 }
530 }
531 if (s == rd_size_minus_1) {
532 mnemonic = "lsr";
533 form = form_shift_right;
534 } else if (r == s + 1) {
535 mnemonic = "lsl";
536 form = form_lsl;
537 } else if (s < r) {
538 mnemonic = "ubfiz";
539 form = form_bfiz;
540 }
541 break;
542 }
543 case BFM_w:
544 case BFM_x: {
545 mnemonic = "bfxil";
546 form = form_bfx;
547 if (s < r) {
548 mnemonic = "bfi";
549 form = form_bfiz;
550 }
551 }
552 }
553 Format(instr, mnemonic, form);
554 }
555
556
VisitExtract(const Instruction * instr)557 void Disassembler::VisitExtract(const Instruction *instr) {
558 const char *mnemonic = "";
559 const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
560
561 switch (instr->Mask(ExtractMask)) {
562 case EXTR_w:
563 case EXTR_x: {
564 if (instr->GetRn() == instr->GetRm()) {
565 mnemonic = "ror";
566 form = "'Rd, 'Rn, 'IExtract";
567 } else {
568 mnemonic = "extr";
569 }
570 break;
571 }
572 default:
573 VIXL_UNREACHABLE();
574 }
575 Format(instr, mnemonic, form);
576 }
577
578
VisitPCRelAddressing(const Instruction * instr)579 void Disassembler::VisitPCRelAddressing(const Instruction *instr) {
580 switch (instr->Mask(PCRelAddressingMask)) {
581 case ADR:
582 Format(instr, "adr", "'Xd, 'AddrPCRelByte");
583 break;
584 case ADRP:
585 Format(instr, "adrp", "'Xd, 'AddrPCRelPage");
586 break;
587 default:
588 Format(instr, "unimplemented", "(PCRelAddressing)");
589 }
590 }
591
592
VisitConditionalBranch(const Instruction * instr)593 void Disassembler::VisitConditionalBranch(const Instruction *instr) {
594 switch (instr->Mask(ConditionalBranchMask)) {
595 case B_cond:
596 Format(instr, "b.'CBrn", "'TImmCond");
597 break;
598 default:
599 VIXL_UNREACHABLE();
600 }
601 }
602
603
VisitUnconditionalBranchToRegister(const Instruction * instr)604 void Disassembler::VisitUnconditionalBranchToRegister(
605 const Instruction *instr) {
606 const char *mnemonic = "unimplemented";
607 const char *form = "'Xn";
608
609 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
610 case BR:
611 mnemonic = "br";
612 break;
613 case BLR:
614 mnemonic = "blr";
615 break;
616 case RET: {
617 mnemonic = "ret";
618 if (instr->GetRn() == kLinkRegCode) {
619 form = NULL;
620 }
621 break;
622 }
623 default:
624 form = "(UnconditionalBranchToRegister)";
625 }
626 Format(instr, mnemonic, form);
627 }
628
629
VisitUnconditionalBranch(const Instruction * instr)630 void Disassembler::VisitUnconditionalBranch(const Instruction *instr) {
631 const char *mnemonic = "";
632 const char *form = "'TImmUncn";
633
634 switch (instr->Mask(UnconditionalBranchMask)) {
635 case B:
636 mnemonic = "b";
637 break;
638 case BL:
639 mnemonic = "bl";
640 break;
641 default:
642 VIXL_UNREACHABLE();
643 }
644 Format(instr, mnemonic, form);
645 }
646
647
VisitDataProcessing1Source(const Instruction * instr)648 void Disassembler::VisitDataProcessing1Source(const Instruction *instr) {
649 const char *mnemonic = "";
650 const char *form = "'Rd, 'Rn";
651
652 switch (instr->Mask(DataProcessing1SourceMask)) {
653 #define FORMAT(A, B) \
654 case A##_w: \
655 case A##_x: \
656 mnemonic = B; \
657 break;
658 FORMAT(RBIT, "rbit");
659 FORMAT(REV16, "rev16");
660 FORMAT(REV, "rev");
661 FORMAT(CLZ, "clz");
662 FORMAT(CLS, "cls");
663 #undef FORMAT
664 case REV32_x:
665 mnemonic = "rev32";
666 break;
667 default:
668 VIXL_UNREACHABLE();
669 }
670 Format(instr, mnemonic, form);
671 }
672
673
VisitDataProcessing2Source(const Instruction * instr)674 void Disassembler::VisitDataProcessing2Source(const Instruction *instr) {
675 const char *mnemonic = "unimplemented";
676 const char *form = "'Rd, 'Rn, 'Rm";
677 const char *form_wwx = "'Wd, 'Wn, 'Xm";
678
679 switch (instr->Mask(DataProcessing2SourceMask)) {
680 #define FORMAT(A, B) \
681 case A##_w: \
682 case A##_x: \
683 mnemonic = B; \
684 break;
685 FORMAT(UDIV, "udiv");
686 FORMAT(SDIV, "sdiv");
687 FORMAT(LSLV, "lsl");
688 FORMAT(LSRV, "lsr");
689 FORMAT(ASRV, "asr");
690 FORMAT(RORV, "ror");
691 #undef FORMAT
692 case CRC32B:
693 mnemonic = "crc32b";
694 break;
695 case CRC32H:
696 mnemonic = "crc32h";
697 break;
698 case CRC32W:
699 mnemonic = "crc32w";
700 break;
701 case CRC32X:
702 mnemonic = "crc32x";
703 form = form_wwx;
704 break;
705 case CRC32CB:
706 mnemonic = "crc32cb";
707 break;
708 case CRC32CH:
709 mnemonic = "crc32ch";
710 break;
711 case CRC32CW:
712 mnemonic = "crc32cw";
713 break;
714 case CRC32CX:
715 mnemonic = "crc32cx";
716 form = form_wwx;
717 break;
718 default:
719 form = "(DataProcessing2Source)";
720 }
721 Format(instr, mnemonic, form);
722 }
723
724
VisitDataProcessing3Source(const Instruction * instr)725 void Disassembler::VisitDataProcessing3Source(const Instruction *instr) {
726 bool ra_is_zr = RaIsZROrSP(instr);
727 const char *mnemonic = "";
728 const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
729 const char *form_rrr = "'Rd, 'Rn, 'Rm";
730 const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
731 const char *form_xww = "'Xd, 'Wn, 'Wm";
732 const char *form_xxx = "'Xd, 'Xn, 'Xm";
733
734 switch (instr->Mask(DataProcessing3SourceMask)) {
735 case MADD_w:
736 case MADD_x: {
737 mnemonic = "madd";
738 form = form_rrrr;
739 if (ra_is_zr) {
740 mnemonic = "mul";
741 form = form_rrr;
742 }
743 break;
744 }
745 case MSUB_w:
746 case MSUB_x: {
747 mnemonic = "msub";
748 form = form_rrrr;
749 if (ra_is_zr) {
750 mnemonic = "mneg";
751 form = form_rrr;
752 }
753 break;
754 }
755 case SMADDL_x: {
756 mnemonic = "smaddl";
757 if (ra_is_zr) {
758 mnemonic = "smull";
759 form = form_xww;
760 }
761 break;
762 }
763 case SMSUBL_x: {
764 mnemonic = "smsubl";
765 if (ra_is_zr) {
766 mnemonic = "smnegl";
767 form = form_xww;
768 }
769 break;
770 }
771 case UMADDL_x: {
772 mnemonic = "umaddl";
773 if (ra_is_zr) {
774 mnemonic = "umull";
775 form = form_xww;
776 }
777 break;
778 }
779 case UMSUBL_x: {
780 mnemonic = "umsubl";
781 if (ra_is_zr) {
782 mnemonic = "umnegl";
783 form = form_xww;
784 }
785 break;
786 }
787 case SMULH_x: {
788 mnemonic = "smulh";
789 form = form_xxx;
790 break;
791 }
792 case UMULH_x: {
793 mnemonic = "umulh";
794 form = form_xxx;
795 break;
796 }
797 default:
798 VIXL_UNREACHABLE();
799 }
800 Format(instr, mnemonic, form);
801 }
802
803
VisitCompareBranch(const Instruction * instr)804 void Disassembler::VisitCompareBranch(const Instruction *instr) {
805 const char *mnemonic = "";
806 const char *form = "'Rt, 'TImmCmpa";
807
808 switch (instr->Mask(CompareBranchMask)) {
809 case CBZ_w:
810 case CBZ_x:
811 mnemonic = "cbz";
812 break;
813 case CBNZ_w:
814 case CBNZ_x:
815 mnemonic = "cbnz";
816 break;
817 default:
818 VIXL_UNREACHABLE();
819 }
820 Format(instr, mnemonic, form);
821 }
822
823
VisitTestBranch(const Instruction * instr)824 void Disassembler::VisitTestBranch(const Instruction *instr) {
825 const char *mnemonic = "";
826 // If the top bit of the immediate is clear, the tested register is
827 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
828 // encoded in bit 31 of the instruction, we can reuse the Rt form, which
829 // uses bit 31 (normally "sf") to choose the register size.
830 const char *form = "'Rt, 'IS, 'TImmTest";
831
832 switch (instr->Mask(TestBranchMask)) {
833 case TBZ:
834 mnemonic = "tbz";
835 break;
836 case TBNZ:
837 mnemonic = "tbnz";
838 break;
839 default:
840 VIXL_UNREACHABLE();
841 }
842 Format(instr, mnemonic, form);
843 }
844
845
VisitMoveWideImmediate(const Instruction * instr)846 void Disassembler::VisitMoveWideImmediate(const Instruction *instr) {
847 const char *mnemonic = "";
848 const char *form = "'Rd, 'IMoveImm";
849
850 // Print the shift separately for movk, to make it clear which half word will
851 // be overwritten. Movn and movz print the computed immediate, which includes
852 // shift calculation.
853 switch (instr->Mask(MoveWideImmediateMask)) {
854 case MOVN_w:
855 case MOVN_x:
856 if ((instr->GetImmMoveWide()) || (instr->GetShiftMoveWide() == 0)) {
857 if ((instr->GetSixtyFourBits() == 0) &&
858 (instr->GetImmMoveWide() == 0xffff)) {
859 mnemonic = "movn";
860 } else {
861 mnemonic = "mov";
862 form = "'Rd, 'IMoveNeg";
863 }
864 } else {
865 mnemonic = "movn";
866 }
867 break;
868 case MOVZ_w:
869 case MOVZ_x:
870 if ((instr->GetImmMoveWide()) || (instr->GetShiftMoveWide() == 0))
871 mnemonic = "mov";
872 else
873 mnemonic = "movz";
874 break;
875 case MOVK_w:
876 case MOVK_x:
877 mnemonic = "movk";
878 form = "'Rd, 'IMoveLSL";
879 break;
880 default:
881 VIXL_UNREACHABLE();
882 }
883 Format(instr, mnemonic, form);
884 }
885
886
887 #define LOAD_STORE_LIST(V) \
888 V(STRB_w, "strb", "'Wt") \
889 V(STRH_w, "strh", "'Wt") \
890 V(STR_w, "str", "'Wt") \
891 V(STR_x, "str", "'Xt") \
892 V(LDRB_w, "ldrb", "'Wt") \
893 V(LDRH_w, "ldrh", "'Wt") \
894 V(LDR_w, "ldr", "'Wt") \
895 V(LDR_x, "ldr", "'Xt") \
896 V(LDRSB_x, "ldrsb", "'Xt") \
897 V(LDRSH_x, "ldrsh", "'Xt") \
898 V(LDRSW_x, "ldrsw", "'Xt") \
899 V(LDRSB_w, "ldrsb", "'Wt") \
900 V(LDRSH_w, "ldrsh", "'Wt") \
901 V(STR_b, "str", "'Bt") \
902 V(STR_h, "str", "'Ht") \
903 V(STR_s, "str", "'St") \
904 V(STR_d, "str", "'Dt") \
905 V(LDR_b, "ldr", "'Bt") \
906 V(LDR_h, "ldr", "'Ht") \
907 V(LDR_s, "ldr", "'St") \
908 V(LDR_d, "ldr", "'Dt") \
909 V(STR_q, "str", "'Qt") \
910 V(LDR_q, "ldr", "'Qt")
911
VisitLoadStorePreIndex(const Instruction * instr)912 void Disassembler::VisitLoadStorePreIndex(const Instruction *instr) {
913 const char *mnemonic = "unimplemented";
914 const char *form = "(LoadStorePreIndex)";
915
916 switch (instr->Mask(LoadStorePreIndexMask)) {
917 #define LS_PREINDEX(A, B, C) \
918 case A##_pre: \
919 mnemonic = B; \
920 form = C ", ['Xns'ILS]!"; \
921 break;
922 LOAD_STORE_LIST(LS_PREINDEX)
923 #undef LS_PREINDEX
924 }
925 Format(instr, mnemonic, form);
926 }
927
928
VisitLoadStorePostIndex(const Instruction * instr)929 void Disassembler::VisitLoadStorePostIndex(const Instruction *instr) {
930 const char *mnemonic = "unimplemented";
931 const char *form = "(LoadStorePostIndex)";
932
933 switch (instr->Mask(LoadStorePostIndexMask)) {
934 #define LS_POSTINDEX(A, B, C) \
935 case A##_post: \
936 mnemonic = B; \
937 form = C ", ['Xns]'ILS"; \
938 break;
939 LOAD_STORE_LIST(LS_POSTINDEX)
940 #undef LS_POSTINDEX
941 }
942 Format(instr, mnemonic, form);
943 }
944
945
VisitLoadStoreUnsignedOffset(const Instruction * instr)946 void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction *instr) {
947 const char *mnemonic = "unimplemented";
948 const char *form = "(LoadStoreUnsignedOffset)";
949
950 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
951 #define LS_UNSIGNEDOFFSET(A, B, C) \
952 case A##_unsigned: \
953 mnemonic = B; \
954 form = C ", ['Xns'ILU]"; \
955 break;
956 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
957 #undef LS_UNSIGNEDOFFSET
958 case PRFM_unsigned:
959 mnemonic = "prfm";
960 form = "'PrefOp, ['Xns'ILU]";
961 }
962 Format(instr, mnemonic, form);
963 }
964
965
VisitLoadStoreRegisterOffset(const Instruction * instr)966 void Disassembler::VisitLoadStoreRegisterOffset(const Instruction *instr) {
967 const char *mnemonic = "unimplemented";
968 const char *form = "(LoadStoreRegisterOffset)";
969
970 switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
971 #define LS_REGISTEROFFSET(A, B, C) \
972 case A##_reg: \
973 mnemonic = B; \
974 form = C ", ['Xns, 'Offsetreg]"; \
975 break;
976 LOAD_STORE_LIST(LS_REGISTEROFFSET)
977 #undef LS_REGISTEROFFSET
978 case PRFM_reg:
979 mnemonic = "prfm";
980 form = "'PrefOp, ['Xns, 'Offsetreg]";
981 }
982 Format(instr, mnemonic, form);
983 }
984
985
VisitLoadStoreUnscaledOffset(const Instruction * instr)986 void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction *instr) {
987 const char *mnemonic = "unimplemented";
988 const char *form = "'Wt, ['Xns'ILS]";
989 const char *form_x = "'Xt, ['Xns'ILS]";
990 const char *form_b = "'Bt, ['Xns'ILS]";
991 const char *form_h = "'Ht, ['Xns'ILS]";
992 const char *form_s = "'St, ['Xns'ILS]";
993 const char *form_d = "'Dt, ['Xns'ILS]";
994 const char *form_q = "'Qt, ['Xns'ILS]";
995 const char *form_prefetch = "'PrefOp, ['Xns'ILS]";
996
997 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
998 case STURB_w:
999 mnemonic = "sturb";
1000 break;
1001 case STURH_w:
1002 mnemonic = "sturh";
1003 break;
1004 case STUR_w:
1005 mnemonic = "stur";
1006 break;
1007 case STUR_x:
1008 mnemonic = "stur";
1009 form = form_x;
1010 break;
1011 case STUR_b:
1012 mnemonic = "stur";
1013 form = form_b;
1014 break;
1015 case STUR_h:
1016 mnemonic = "stur";
1017 form = form_h;
1018 break;
1019 case STUR_s:
1020 mnemonic = "stur";
1021 form = form_s;
1022 break;
1023 case STUR_d:
1024 mnemonic = "stur";
1025 form = form_d;
1026 break;
1027 case STUR_q:
1028 mnemonic = "stur";
1029 form = form_q;
1030 break;
1031 case LDURB_w:
1032 mnemonic = "ldurb";
1033 break;
1034 case LDURH_w:
1035 mnemonic = "ldurh";
1036 break;
1037 case LDUR_w:
1038 mnemonic = "ldur";
1039 break;
1040 case LDUR_x:
1041 mnemonic = "ldur";
1042 form = form_x;
1043 break;
1044 case LDUR_b:
1045 mnemonic = "ldur";
1046 form = form_b;
1047 break;
1048 case LDUR_h:
1049 mnemonic = "ldur";
1050 form = form_h;
1051 break;
1052 case LDUR_s:
1053 mnemonic = "ldur";
1054 form = form_s;
1055 break;
1056 case LDUR_d:
1057 mnemonic = "ldur";
1058 form = form_d;
1059 break;
1060 case LDUR_q:
1061 mnemonic = "ldur";
1062 form = form_q;
1063 break;
1064 case LDURSB_x:
1065 form = form_x;
1066 VIXL_FALLTHROUGH();
1067 case LDURSB_w:
1068 mnemonic = "ldursb";
1069 break;
1070 case LDURSH_x:
1071 form = form_x;
1072 VIXL_FALLTHROUGH();
1073 case LDURSH_w:
1074 mnemonic = "ldursh";
1075 break;
1076 case LDURSW_x:
1077 mnemonic = "ldursw";
1078 form = form_x;
1079 break;
1080 case PRFUM:
1081 mnemonic = "prfum";
1082 form = form_prefetch;
1083 break;
1084 default:
1085 form = "(LoadStoreUnscaledOffset)";
1086 }
1087 Format(instr, mnemonic, form);
1088 }
1089
1090
VisitLoadLiteral(const Instruction * instr)1091 void Disassembler::VisitLoadLiteral(const Instruction *instr) {
1092 const char *mnemonic = "ldr";
1093 const char *form = "(LoadLiteral)";
1094
1095 switch (instr->Mask(LoadLiteralMask)) {
1096 case LDR_w_lit:
1097 form = "'Wt, 'ILLiteral 'LValue";
1098 break;
1099 case LDR_x_lit:
1100 form = "'Xt, 'ILLiteral 'LValue";
1101 break;
1102 case LDR_s_lit:
1103 form = "'St, 'ILLiteral 'LValue";
1104 break;
1105 case LDR_d_lit:
1106 form = "'Dt, 'ILLiteral 'LValue";
1107 break;
1108 case LDR_q_lit:
1109 form = "'Qt, 'ILLiteral 'LValue";
1110 break;
1111 case LDRSW_x_lit: {
1112 mnemonic = "ldrsw";
1113 form = "'Xt, 'ILLiteral 'LValue";
1114 break;
1115 }
1116 case PRFM_lit: {
1117 mnemonic = "prfm";
1118 form = "'PrefOp, 'ILLiteral 'LValue";
1119 break;
1120 }
1121 default:
1122 mnemonic = "unimplemented";
1123 }
1124 Format(instr, mnemonic, form);
1125 }
1126
1127
1128 #define LOAD_STORE_PAIR_LIST(V) \
1129 V(STP_w, "stp", "'Wt, 'Wt2", "2") \
1130 V(LDP_w, "ldp", "'Wt, 'Wt2", "2") \
1131 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "2") \
1132 V(STP_x, "stp", "'Xt, 'Xt2", "3") \
1133 V(LDP_x, "ldp", "'Xt, 'Xt2", "3") \
1134 V(STP_s, "stp", "'St, 'St2", "2") \
1135 V(LDP_s, "ldp", "'St, 'St2", "2") \
1136 V(STP_d, "stp", "'Dt, 'Dt2", "3") \
1137 V(LDP_d, "ldp", "'Dt, 'Dt2", "3") \
1138 V(LDP_q, "ldp", "'Qt, 'Qt2", "4") \
1139 V(STP_q, "stp", "'Qt, 'Qt2", "4")
1140
VisitLoadStorePairPostIndex(const Instruction * instr)1141 void Disassembler::VisitLoadStorePairPostIndex(const Instruction *instr) {
1142 const char *mnemonic = "unimplemented";
1143 const char *form = "(LoadStorePairPostIndex)";
1144
1145 switch (instr->Mask(LoadStorePairPostIndexMask)) {
1146 #define LSP_POSTINDEX(A, B, C, D) \
1147 case A##_post: \
1148 mnemonic = B; \
1149 form = C ", ['Xns]'ILP" D; \
1150 break;
1151 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
1152 #undef LSP_POSTINDEX
1153 }
1154 Format(instr, mnemonic, form);
1155 }
1156
1157
VisitLoadStorePairPreIndex(const Instruction * instr)1158 void Disassembler::VisitLoadStorePairPreIndex(const Instruction *instr) {
1159 const char *mnemonic = "unimplemented";
1160 const char *form = "(LoadStorePairPreIndex)";
1161
1162 switch (instr->Mask(LoadStorePairPreIndexMask)) {
1163 #define LSP_PREINDEX(A, B, C, D) \
1164 case A##_pre: \
1165 mnemonic = B; \
1166 form = C ", ['Xns'ILP" D "]!"; \
1167 break;
1168 LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
1169 #undef LSP_PREINDEX
1170 }
1171 Format(instr, mnemonic, form);
1172 }
1173
1174
VisitLoadStorePairOffset(const Instruction * instr)1175 void Disassembler::VisitLoadStorePairOffset(const Instruction *instr) {
1176 const char *mnemonic = "unimplemented";
1177 const char *form = "(LoadStorePairOffset)";
1178
1179 switch (instr->Mask(LoadStorePairOffsetMask)) {
1180 #define LSP_OFFSET(A, B, C, D) \
1181 case A##_off: \
1182 mnemonic = B; \
1183 form = C ", ['Xns'ILP" D "]"; \
1184 break;
1185 LOAD_STORE_PAIR_LIST(LSP_OFFSET)
1186 #undef LSP_OFFSET
1187 }
1188 Format(instr, mnemonic, form);
1189 }
1190
1191
VisitLoadStorePairNonTemporal(const Instruction * instr)1192 void Disassembler::VisitLoadStorePairNonTemporal(const Instruction *instr) {
1193 const char *mnemonic = "unimplemented";
1194 const char *form;
1195
1196 switch (instr->Mask(LoadStorePairNonTemporalMask)) {
1197 case STNP_w:
1198 mnemonic = "stnp";
1199 form = "'Wt, 'Wt2, ['Xns'ILP2]";
1200 break;
1201 case LDNP_w:
1202 mnemonic = "ldnp";
1203 form = "'Wt, 'Wt2, ['Xns'ILP2]";
1204 break;
1205 case STNP_x:
1206 mnemonic = "stnp";
1207 form = "'Xt, 'Xt2, ['Xns'ILP3]";
1208 break;
1209 case LDNP_x:
1210 mnemonic = "ldnp";
1211 form = "'Xt, 'Xt2, ['Xns'ILP3]";
1212 break;
1213 case STNP_s:
1214 mnemonic = "stnp";
1215 form = "'St, 'St2, ['Xns'ILP2]";
1216 break;
1217 case LDNP_s:
1218 mnemonic = "ldnp";
1219 form = "'St, 'St2, ['Xns'ILP2]";
1220 break;
1221 case STNP_d:
1222 mnemonic = "stnp";
1223 form = "'Dt, 'Dt2, ['Xns'ILP3]";
1224 break;
1225 case LDNP_d:
1226 mnemonic = "ldnp";
1227 form = "'Dt, 'Dt2, ['Xns'ILP3]";
1228 break;
1229 case STNP_q:
1230 mnemonic = "stnp";
1231 form = "'Qt, 'Qt2, ['Xns'ILP4]";
1232 break;
1233 case LDNP_q:
1234 mnemonic = "ldnp";
1235 form = "'Qt, 'Qt2, ['Xns'ILP4]";
1236 break;
1237 default:
1238 form = "(LoadStorePairNonTemporal)";
1239 }
1240 Format(instr, mnemonic, form);
1241 }
1242
1243
VisitLoadStoreExclusive(const Instruction * instr)1244 void Disassembler::VisitLoadStoreExclusive(const Instruction *instr) {
1245 const char *mnemonic = "unimplemented";
1246 const char *form;
1247
1248 switch (instr->Mask(LoadStoreExclusiveMask)) {
1249 case STXRB_w:
1250 mnemonic = "stxrb";
1251 form = "'Ws, 'Wt, ['Xns]";
1252 break;
1253 case STXRH_w:
1254 mnemonic = "stxrh";
1255 form = "'Ws, 'Wt, ['Xns]";
1256 break;
1257 case STXR_w:
1258 mnemonic = "stxr";
1259 form = "'Ws, 'Wt, ['Xns]";
1260 break;
1261 case STXR_x:
1262 mnemonic = "stxr";
1263 form = "'Ws, 'Xt, ['Xns]";
1264 break;
1265 case LDXRB_w:
1266 mnemonic = "ldxrb";
1267 form = "'Wt, ['Xns]";
1268 break;
1269 case LDXRH_w:
1270 mnemonic = "ldxrh";
1271 form = "'Wt, ['Xns]";
1272 break;
1273 case LDXR_w:
1274 mnemonic = "ldxr";
1275 form = "'Wt, ['Xns]";
1276 break;
1277 case LDXR_x:
1278 mnemonic = "ldxr";
1279 form = "'Xt, ['Xns]";
1280 break;
1281 case STXP_w:
1282 mnemonic = "stxp";
1283 form = "'Ws, 'Wt, 'Wt2, ['Xns]";
1284 break;
1285 case STXP_x:
1286 mnemonic = "stxp";
1287 form = "'Ws, 'Xt, 'Xt2, ['Xns]";
1288 break;
1289 case LDXP_w:
1290 mnemonic = "ldxp";
1291 form = "'Wt, 'Wt2, ['Xns]";
1292 break;
1293 case LDXP_x:
1294 mnemonic = "ldxp";
1295 form = "'Xt, 'Xt2, ['Xns]";
1296 break;
1297 case STLXRB_w:
1298 mnemonic = "stlxrb";
1299 form = "'Ws, 'Wt, ['Xns]";
1300 break;
1301 case STLXRH_w:
1302 mnemonic = "stlxrh";
1303 form = "'Ws, 'Wt, ['Xns]";
1304 break;
1305 case STLXR_w:
1306 mnemonic = "stlxr";
1307 form = "'Ws, 'Wt, ['Xns]";
1308 break;
1309 case STLXR_x:
1310 mnemonic = "stlxr";
1311 form = "'Ws, 'Xt, ['Xns]";
1312 break;
1313 case LDAXRB_w:
1314 mnemonic = "ldaxrb";
1315 form = "'Wt, ['Xns]";
1316 break;
1317 case LDAXRH_w:
1318 mnemonic = "ldaxrh";
1319 form = "'Wt, ['Xns]";
1320 break;
1321 case LDAXR_w:
1322 mnemonic = "ldaxr";
1323 form = "'Wt, ['Xns]";
1324 break;
1325 case LDAXR_x:
1326 mnemonic = "ldaxr";
1327 form = "'Xt, ['Xns]";
1328 break;
1329 case STLXP_w:
1330 mnemonic = "stlxp";
1331 form = "'Ws, 'Wt, 'Wt2, ['Xns]";
1332 break;
1333 case STLXP_x:
1334 mnemonic = "stlxp";
1335 form = "'Ws, 'Xt, 'Xt2, ['Xns]";
1336 break;
1337 case LDAXP_w:
1338 mnemonic = "ldaxp";
1339 form = "'Wt, 'Wt2, ['Xns]";
1340 break;
1341 case LDAXP_x:
1342 mnemonic = "ldaxp";
1343 form = "'Xt, 'Xt2, ['Xns]";
1344 break;
1345 case STLRB_w:
1346 mnemonic = "stlrb";
1347 form = "'Wt, ['Xns]";
1348 break;
1349 case STLRH_w:
1350 mnemonic = "stlrh";
1351 form = "'Wt, ['Xns]";
1352 break;
1353 case STLR_w:
1354 mnemonic = "stlr";
1355 form = "'Wt, ['Xns]";
1356 break;
1357 case STLR_x:
1358 mnemonic = "stlr";
1359 form = "'Xt, ['Xns]";
1360 break;
1361 case LDARB_w:
1362 mnemonic = "ldarb";
1363 form = "'Wt, ['Xns]";
1364 break;
1365 case LDARH_w:
1366 mnemonic = "ldarh";
1367 form = "'Wt, ['Xns]";
1368 break;
1369 case LDAR_w:
1370 mnemonic = "ldar";
1371 form = "'Wt, ['Xns]";
1372 break;
1373 case LDAR_x:
1374 mnemonic = "ldar";
1375 form = "'Xt, ['Xns]";
1376 break;
1377 default:
1378 form = "(LoadStoreExclusive)";
1379 }
1380 Format(instr, mnemonic, form);
1381 }
1382
1383
VisitFPCompare(const Instruction * instr)1384 void Disassembler::VisitFPCompare(const Instruction *instr) {
1385 const char *mnemonic = "unimplemented";
1386 const char *form = "'Fn, 'Fm";
1387 const char *form_zero = "'Fn, #0.0";
1388
1389 switch (instr->Mask(FPCompareMask)) {
1390 case FCMP_s_zero:
1391 case FCMP_d_zero:
1392 form = form_zero;
1393 VIXL_FALLTHROUGH();
1394 case FCMP_s:
1395 case FCMP_d:
1396 mnemonic = "fcmp";
1397 break;
1398 case FCMPE_s_zero:
1399 case FCMPE_d_zero:
1400 form = form_zero;
1401 VIXL_FALLTHROUGH();
1402 case FCMPE_s:
1403 case FCMPE_d:
1404 mnemonic = "fcmpe";
1405 break;
1406 default:
1407 form = "(FPCompare)";
1408 }
1409 Format(instr, mnemonic, form);
1410 }
1411
1412
VisitFPConditionalCompare(const Instruction * instr)1413 void Disassembler::VisitFPConditionalCompare(const Instruction *instr) {
1414 const char *mnemonic = "unmplemented";
1415 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
1416
1417 switch (instr->Mask(FPConditionalCompareMask)) {
1418 case FCCMP_s:
1419 case FCCMP_d:
1420 mnemonic = "fccmp";
1421 break;
1422 case FCCMPE_s:
1423 case FCCMPE_d:
1424 mnemonic = "fccmpe";
1425 break;
1426 default:
1427 form = "(FPConditionalCompare)";
1428 }
1429 Format(instr, mnemonic, form);
1430 }
1431
1432
VisitFPConditionalSelect(const Instruction * instr)1433 void Disassembler::VisitFPConditionalSelect(const Instruction *instr) {
1434 const char *mnemonic = "";
1435 const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
1436
1437 switch (instr->Mask(FPConditionalSelectMask)) {
1438 case FCSEL_s:
1439 case FCSEL_d:
1440 mnemonic = "fcsel";
1441 break;
1442 default:
1443 VIXL_UNREACHABLE();
1444 }
1445 Format(instr, mnemonic, form);
1446 }
1447
1448
VisitFPDataProcessing1Source(const Instruction * instr)1449 void Disassembler::VisitFPDataProcessing1Source(const Instruction *instr) {
1450 const char *mnemonic = "unimplemented";
1451 const char *form = "'Fd, 'Fn";
1452
1453 switch (instr->Mask(FPDataProcessing1SourceMask)) {
1454 #define FORMAT(A, B) \
1455 case A##_s: \
1456 case A##_d: \
1457 mnemonic = B; \
1458 break;
1459 FORMAT(FMOV, "fmov");
1460 FORMAT(FABS, "fabs");
1461 FORMAT(FNEG, "fneg");
1462 FORMAT(FSQRT, "fsqrt");
1463 FORMAT(FRINTN, "frintn");
1464 FORMAT(FRINTP, "frintp");
1465 FORMAT(FRINTM, "frintm");
1466 FORMAT(FRINTZ, "frintz");
1467 FORMAT(FRINTA, "frinta");
1468 FORMAT(FRINTX, "frintx");
1469 FORMAT(FRINTI, "frinti");
1470 #undef FORMAT
1471 case FCVT_ds:
1472 mnemonic = "fcvt";
1473 form = "'Dd, 'Sn";
1474 break;
1475 case FCVT_sd:
1476 mnemonic = "fcvt";
1477 form = "'Sd, 'Dn";
1478 break;
1479 case FCVT_hs:
1480 mnemonic = "fcvt";
1481 form = "'Hd, 'Sn";
1482 break;
1483 case FCVT_sh:
1484 mnemonic = "fcvt";
1485 form = "'Sd, 'Hn";
1486 break;
1487 case FCVT_dh:
1488 mnemonic = "fcvt";
1489 form = "'Dd, 'Hn";
1490 break;
1491 case FCVT_hd:
1492 mnemonic = "fcvt";
1493 form = "'Hd, 'Dn";
1494 break;
1495 default:
1496 form = "(FPDataProcessing1Source)";
1497 }
1498 Format(instr, mnemonic, form);
1499 }
1500
1501
VisitFPDataProcessing2Source(const Instruction * instr)1502 void Disassembler::VisitFPDataProcessing2Source(const Instruction *instr) {
1503 const char *mnemonic = "";
1504 const char *form = "'Fd, 'Fn, 'Fm";
1505
1506 switch (instr->Mask(FPDataProcessing2SourceMask)) {
1507 #define FORMAT(A, B) \
1508 case A##_s: \
1509 case A##_d: \
1510 mnemonic = B; \
1511 break;
1512 FORMAT(FMUL, "fmul");
1513 FORMAT(FDIV, "fdiv");
1514 FORMAT(FADD, "fadd");
1515 FORMAT(FSUB, "fsub");
1516 FORMAT(FMAX, "fmax");
1517 FORMAT(FMIN, "fmin");
1518 FORMAT(FMAXNM, "fmaxnm");
1519 FORMAT(FMINNM, "fminnm");
1520 FORMAT(FNMUL, "fnmul");
1521 #undef FORMAT
1522 default:
1523 VIXL_UNREACHABLE();
1524 }
1525 Format(instr, mnemonic, form);
1526 }
1527
1528
VisitFPDataProcessing3Source(const Instruction * instr)1529 void Disassembler::VisitFPDataProcessing3Source(const Instruction *instr) {
1530 const char *mnemonic = "";
1531 const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1532
1533 switch (instr->Mask(FPDataProcessing3SourceMask)) {
1534 #define FORMAT(A, B) \
1535 case A##_s: \
1536 case A##_d: \
1537 mnemonic = B; \
1538 break;
1539 FORMAT(FMADD, "fmadd");
1540 FORMAT(FMSUB, "fmsub");
1541 FORMAT(FNMADD, "fnmadd");
1542 FORMAT(FNMSUB, "fnmsub");
1543 #undef FORMAT
1544 default:
1545 VIXL_UNREACHABLE();
1546 }
1547 Format(instr, mnemonic, form);
1548 }
1549
1550
VisitFPImmediate(const Instruction * instr)1551 void Disassembler::VisitFPImmediate(const Instruction *instr) {
1552 const char *mnemonic = "";
1553 const char *form = "(FPImmediate)";
1554
1555 switch (instr->Mask(FPImmediateMask)) {
1556 case FMOV_s_imm:
1557 mnemonic = "fmov";
1558 form = "'Sd, 'IFPSingle";
1559 break;
1560 case FMOV_d_imm:
1561 mnemonic = "fmov";
1562 form = "'Dd, 'IFPDouble";
1563 break;
1564 default:
1565 VIXL_UNREACHABLE();
1566 }
1567 Format(instr, mnemonic, form);
1568 }
1569
1570
VisitFPIntegerConvert(const Instruction * instr)1571 void Disassembler::VisitFPIntegerConvert(const Instruction *instr) {
1572 const char *mnemonic = "unimplemented";
1573 const char *form = "(FPIntegerConvert)";
1574 const char *form_rf = "'Rd, 'Fn";
1575 const char *form_fr = "'Fd, 'Rn";
1576
1577 switch (instr->Mask(FPIntegerConvertMask)) {
1578 case FMOV_ws:
1579 case FMOV_xd:
1580 mnemonic = "fmov";
1581 form = form_rf;
1582 break;
1583 case FMOV_sw:
1584 case FMOV_dx:
1585 mnemonic = "fmov";
1586 form = form_fr;
1587 break;
1588 case FMOV_d1_x:
1589 mnemonic = "fmov";
1590 form = "'Vd.D[1], 'Rn";
1591 break;
1592 case FMOV_x_d1:
1593 mnemonic = "fmov";
1594 form = "'Rd, 'Vn.D[1]";
1595 break;
1596 case FCVTAS_ws:
1597 case FCVTAS_xs:
1598 case FCVTAS_wd:
1599 case FCVTAS_xd:
1600 mnemonic = "fcvtas";
1601 form = form_rf;
1602 break;
1603 case FCVTAU_ws:
1604 case FCVTAU_xs:
1605 case FCVTAU_wd:
1606 case FCVTAU_xd:
1607 mnemonic = "fcvtau";
1608 form = form_rf;
1609 break;
1610 case FCVTMS_ws:
1611 case FCVTMS_xs:
1612 case FCVTMS_wd:
1613 case FCVTMS_xd:
1614 mnemonic = "fcvtms";
1615 form = form_rf;
1616 break;
1617 case FCVTMU_ws:
1618 case FCVTMU_xs:
1619 case FCVTMU_wd:
1620 case FCVTMU_xd:
1621 mnemonic = "fcvtmu";
1622 form = form_rf;
1623 break;
1624 case FCVTNS_ws:
1625 case FCVTNS_xs:
1626 case FCVTNS_wd:
1627 case FCVTNS_xd:
1628 mnemonic = "fcvtns";
1629 form = form_rf;
1630 break;
1631 case FCVTNU_ws:
1632 case FCVTNU_xs:
1633 case FCVTNU_wd:
1634 case FCVTNU_xd:
1635 mnemonic = "fcvtnu";
1636 form = form_rf;
1637 break;
1638 case FCVTZU_xd:
1639 case FCVTZU_ws:
1640 case FCVTZU_wd:
1641 case FCVTZU_xs:
1642 mnemonic = "fcvtzu";
1643 form = form_rf;
1644 break;
1645 case FCVTZS_xd:
1646 case FCVTZS_wd:
1647 case FCVTZS_xs:
1648 case FCVTZS_ws:
1649 mnemonic = "fcvtzs";
1650 form = form_rf;
1651 break;
1652 case FCVTPU_xd:
1653 case FCVTPU_ws:
1654 case FCVTPU_wd:
1655 case FCVTPU_xs:
1656 mnemonic = "fcvtpu";
1657 form = form_rf;
1658 break;
1659 case FCVTPS_xd:
1660 case FCVTPS_wd:
1661 case FCVTPS_xs:
1662 case FCVTPS_ws:
1663 mnemonic = "fcvtps";
1664 form = form_rf;
1665 break;
1666 case SCVTF_sw:
1667 case SCVTF_sx:
1668 case SCVTF_dw:
1669 case SCVTF_dx:
1670 mnemonic = "scvtf";
1671 form = form_fr;
1672 break;
1673 case UCVTF_sw:
1674 case UCVTF_sx:
1675 case UCVTF_dw:
1676 case UCVTF_dx:
1677 mnemonic = "ucvtf";
1678 form = form_fr;
1679 break;
1680 }
1681 Format(instr, mnemonic, form);
1682 }
1683
1684
VisitFPFixedPointConvert(const Instruction * instr)1685 void Disassembler::VisitFPFixedPointConvert(const Instruction *instr) {
1686 const char *mnemonic = "";
1687 const char *form = "'Rd, 'Fn, 'IFPFBits";
1688 const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1689
1690 switch (instr->Mask(FPFixedPointConvertMask)) {
1691 case FCVTZS_ws_fixed:
1692 case FCVTZS_xs_fixed:
1693 case FCVTZS_wd_fixed:
1694 case FCVTZS_xd_fixed:
1695 mnemonic = "fcvtzs";
1696 break;
1697 case FCVTZU_ws_fixed:
1698 case FCVTZU_xs_fixed:
1699 case FCVTZU_wd_fixed:
1700 case FCVTZU_xd_fixed:
1701 mnemonic = "fcvtzu";
1702 break;
1703 case SCVTF_sw_fixed:
1704 case SCVTF_sx_fixed:
1705 case SCVTF_dw_fixed:
1706 case SCVTF_dx_fixed:
1707 mnemonic = "scvtf";
1708 form = form_fr;
1709 break;
1710 case UCVTF_sw_fixed:
1711 case UCVTF_sx_fixed:
1712 case UCVTF_dw_fixed:
1713 case UCVTF_dx_fixed:
1714 mnemonic = "ucvtf";
1715 form = form_fr;
1716 break;
1717 default:
1718 VIXL_UNREACHABLE();
1719 }
1720 Format(instr, mnemonic, form);
1721 }
1722
1723
VisitSystem(const Instruction * instr)1724 void Disassembler::VisitSystem(const Instruction *instr) {
1725 // Some system instructions hijack their Op and Cp fields to represent a
1726 // range of immediates instead of indicating a different instruction. This
1727 // makes the decoding tricky.
1728 const char *mnemonic = "unimplemented";
1729 const char *form = "(System)";
1730
1731 if (instr->Mask(SystemExclusiveMonitorFMask) == SystemExclusiveMonitorFixed) {
1732 switch (instr->Mask(SystemExclusiveMonitorMask)) {
1733 case CLREX: {
1734 mnemonic = "clrex";
1735 form = (instr->GetCRm() == 0xf) ? NULL : "'IX";
1736 break;
1737 }
1738 }
1739 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1740 switch (instr->Mask(SystemSysRegMask)) {
1741 case MRS: {
1742 mnemonic = "mrs";
1743 form = "'Xt, 'IY";
1744 break;
1745 }
1746 case MSR: {
1747 mnemonic = "msr";
1748 form = "'IY, 'Xt";
1749 break;
1750 }
1751 }
1752 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1753 switch (instr->GetImmHint()) {
1754 case NOP: {
1755 mnemonic = "nop";
1756 form = NULL;
1757 break;
1758 }
1759 }
1760 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1761 switch (instr->Mask(MemBarrierMask)) {
1762 case DMB: {
1763 mnemonic = "dmb";
1764 form = "'M";
1765 break;
1766 }
1767 case DSB: {
1768 mnemonic = "dsb";
1769 form = "'M";
1770 break;
1771 }
1772 case ISB: {
1773 mnemonic = "isb";
1774 form = NULL;
1775 break;
1776 }
1777 }
1778 } else if (instr->Mask(SystemSysFMask) == SystemSysFixed) {
1779 switch (instr->GetSysOp()) {
1780 case IVAU:
1781 mnemonic = "ic";
1782 form = "ivau, 'Xt";
1783 break;
1784 case CVAC:
1785 mnemonic = "dc";
1786 form = "cvac, 'Xt";
1787 break;
1788 case CVAU:
1789 mnemonic = "dc";
1790 form = "cvau, 'Xt";
1791 break;
1792 case CIVAC:
1793 mnemonic = "dc";
1794 form = "civac, 'Xt";
1795 break;
1796 case ZVA:
1797 mnemonic = "dc";
1798 form = "zva, 'Xt";
1799 break;
1800 default:
1801 mnemonic = "sys";
1802 if (instr->GetRt() == 31) {
1803 form = "'G1, 'Kn, 'Km, 'G2";
1804 } else {
1805 form = "'G1, 'Kn, 'Km, 'G2, 'Xt";
1806 }
1807 break;
1808 }
1809 }
1810 Format(instr, mnemonic, form);
1811 }
1812
1813
VisitException(const Instruction * instr)1814 void Disassembler::VisitException(const Instruction *instr) {
1815 const char *mnemonic = "unimplemented";
1816 const char *form = "'IDebug";
1817
1818 switch (instr->Mask(ExceptionMask)) {
1819 case HLT:
1820 mnemonic = "hlt";
1821 break;
1822 case BRK:
1823 mnemonic = "brk";
1824 break;
1825 case SVC:
1826 mnemonic = "svc";
1827 break;
1828 case HVC:
1829 mnemonic = "hvc";
1830 break;
1831 case SMC:
1832 mnemonic = "smc";
1833 break;
1834 case DCPS1:
1835 mnemonic = "dcps1";
1836 form = "{'IDebug}";
1837 break;
1838 case DCPS2:
1839 mnemonic = "dcps2";
1840 form = "{'IDebug}";
1841 break;
1842 case DCPS3:
1843 mnemonic = "dcps3";
1844 form = "{'IDebug}";
1845 break;
1846 default:
1847 form = "(Exception)";
1848 }
1849 Format(instr, mnemonic, form);
1850 }
1851
1852
VisitCrypto2RegSHA(const Instruction * instr)1853 void Disassembler::VisitCrypto2RegSHA(const Instruction *instr) {
1854 VisitUnimplemented(instr);
1855 }
1856
1857
VisitCrypto3RegSHA(const Instruction * instr)1858 void Disassembler::VisitCrypto3RegSHA(const Instruction *instr) {
1859 VisitUnimplemented(instr);
1860 }
1861
1862
VisitCryptoAES(const Instruction * instr)1863 void Disassembler::VisitCryptoAES(const Instruction *instr) {
1864 VisitUnimplemented(instr);
1865 }
1866
1867
VisitNEON2RegMisc(const Instruction * instr)1868 void Disassembler::VisitNEON2RegMisc(const Instruction *instr) {
1869 const char *mnemonic = "unimplemented";
1870 const char *form = "'Vd.%s, 'Vn.%s";
1871 const char *form_cmp_zero = "'Vd.%s, 'Vn.%s, #0";
1872 const char *form_fcmp_zero = "'Vd.%s, 'Vn.%s, #0.0";
1873 NEONFormatDecoder nfd(instr);
1874
1875 static const NEONFormatMap map_lp_ta =
1876 {{23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}};
1877
1878 static const NEONFormatMap map_cvt_ta = {{22}, {NF_4S, NF_2D}};
1879
1880 static const NEONFormatMap map_cvt_tb = {{22, 30},
1881 {NF_4H, NF_8H, NF_2S, NF_4S}};
1882
1883 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) {
1884 // These instructions all use a two bit size field, except NOT and RBIT,
1885 // which use the field to encode the operation.
1886 switch (instr->Mask(NEON2RegMiscMask)) {
1887 case NEON_REV64:
1888 mnemonic = "rev64";
1889 break;
1890 case NEON_REV32:
1891 mnemonic = "rev32";
1892 break;
1893 case NEON_REV16:
1894 mnemonic = "rev16";
1895 break;
1896 case NEON_SADDLP:
1897 mnemonic = "saddlp";
1898 nfd.SetFormatMap(0, &map_lp_ta);
1899 break;
1900 case NEON_UADDLP:
1901 mnemonic = "uaddlp";
1902 nfd.SetFormatMap(0, &map_lp_ta);
1903 break;
1904 case NEON_SUQADD:
1905 mnemonic = "suqadd";
1906 break;
1907 case NEON_USQADD:
1908 mnemonic = "usqadd";
1909 break;
1910 case NEON_CLS:
1911 mnemonic = "cls";
1912 break;
1913 case NEON_CLZ:
1914 mnemonic = "clz";
1915 break;
1916 case NEON_CNT:
1917 mnemonic = "cnt";
1918 break;
1919 case NEON_SADALP:
1920 mnemonic = "sadalp";
1921 nfd.SetFormatMap(0, &map_lp_ta);
1922 break;
1923 case NEON_UADALP:
1924 mnemonic = "uadalp";
1925 nfd.SetFormatMap(0, &map_lp_ta);
1926 break;
1927 case NEON_SQABS:
1928 mnemonic = "sqabs";
1929 break;
1930 case NEON_SQNEG:
1931 mnemonic = "sqneg";
1932 break;
1933 case NEON_CMGT_zero:
1934 mnemonic = "cmgt";
1935 form = form_cmp_zero;
1936 break;
1937 case NEON_CMGE_zero:
1938 mnemonic = "cmge";
1939 form = form_cmp_zero;
1940 break;
1941 case NEON_CMEQ_zero:
1942 mnemonic = "cmeq";
1943 form = form_cmp_zero;
1944 break;
1945 case NEON_CMLE_zero:
1946 mnemonic = "cmle";
1947 form = form_cmp_zero;
1948 break;
1949 case NEON_CMLT_zero:
1950 mnemonic = "cmlt";
1951 form = form_cmp_zero;
1952 break;
1953 case NEON_ABS:
1954 mnemonic = "abs";
1955 break;
1956 case NEON_NEG:
1957 mnemonic = "neg";
1958 break;
1959 case NEON_RBIT_NOT:
1960 switch (instr->GetFPType()) {
1961 case 0:
1962 mnemonic = "mvn";
1963 break;
1964 case 1:
1965 mnemonic = "rbit";
1966 break;
1967 default:
1968 form = "(NEON2RegMisc)";
1969 }
1970 nfd.SetFormatMaps(nfd.LogicalFormatMap());
1971 break;
1972 }
1973 } else {
1974 // These instructions all use a one bit size field, except XTN, SQXTUN,
1975 // SHLL, SQXTN and UQXTN, which use a two bit size field.
1976 nfd.SetFormatMaps(nfd.FPFormatMap());
1977 switch (instr->Mask(NEON2RegMiscFPMask)) {
1978 case NEON_FABS:
1979 mnemonic = "fabs";
1980 break;
1981 case NEON_FNEG:
1982 mnemonic = "fneg";
1983 break;
1984 case NEON_FCVTN:
1985 mnemonic = instr->Mask(NEON_Q) ? "fcvtn2" : "fcvtn";
1986 nfd.SetFormatMap(0, &map_cvt_tb);
1987 nfd.SetFormatMap(1, &map_cvt_ta);
1988 break;
1989 case NEON_FCVTXN:
1990 mnemonic = instr->Mask(NEON_Q) ? "fcvtxn2" : "fcvtxn";
1991 nfd.SetFormatMap(0, &map_cvt_tb);
1992 nfd.SetFormatMap(1, &map_cvt_ta);
1993 break;
1994 case NEON_FCVTL:
1995 mnemonic = instr->Mask(NEON_Q) ? "fcvtl2" : "fcvtl";
1996 nfd.SetFormatMap(0, &map_cvt_ta);
1997 nfd.SetFormatMap(1, &map_cvt_tb);
1998 break;
1999 case NEON_FRINTN:
2000 mnemonic = "frintn";
2001 break;
2002 case NEON_FRINTA:
2003 mnemonic = "frinta";
2004 break;
2005 case NEON_FRINTP:
2006 mnemonic = "frintp";
2007 break;
2008 case NEON_FRINTM:
2009 mnemonic = "frintm";
2010 break;
2011 case NEON_FRINTX:
2012 mnemonic = "frintx";
2013 break;
2014 case NEON_FRINTZ:
2015 mnemonic = "frintz";
2016 break;
2017 case NEON_FRINTI:
2018 mnemonic = "frinti";
2019 break;
2020 case NEON_FCVTNS:
2021 mnemonic = "fcvtns";
2022 break;
2023 case NEON_FCVTNU:
2024 mnemonic = "fcvtnu";
2025 break;
2026 case NEON_FCVTPS:
2027 mnemonic = "fcvtps";
2028 break;
2029 case NEON_FCVTPU:
2030 mnemonic = "fcvtpu";
2031 break;
2032 case NEON_FCVTMS:
2033 mnemonic = "fcvtms";
2034 break;
2035 case NEON_FCVTMU:
2036 mnemonic = "fcvtmu";
2037 break;
2038 case NEON_FCVTZS:
2039 mnemonic = "fcvtzs";
2040 break;
2041 case NEON_FCVTZU:
2042 mnemonic = "fcvtzu";
2043 break;
2044 case NEON_FCVTAS:
2045 mnemonic = "fcvtas";
2046 break;
2047 case NEON_FCVTAU:
2048 mnemonic = "fcvtau";
2049 break;
2050 case NEON_FSQRT:
2051 mnemonic = "fsqrt";
2052 break;
2053 case NEON_SCVTF:
2054 mnemonic = "scvtf";
2055 break;
2056 case NEON_UCVTF:
2057 mnemonic = "ucvtf";
2058 break;
2059 case NEON_URSQRTE:
2060 mnemonic = "ursqrte";
2061 break;
2062 case NEON_URECPE:
2063 mnemonic = "urecpe";
2064 break;
2065 case NEON_FRSQRTE:
2066 mnemonic = "frsqrte";
2067 break;
2068 case NEON_FRECPE:
2069 mnemonic = "frecpe";
2070 break;
2071 case NEON_FCMGT_zero:
2072 mnemonic = "fcmgt";
2073 form = form_fcmp_zero;
2074 break;
2075 case NEON_FCMGE_zero:
2076 mnemonic = "fcmge";
2077 form = form_fcmp_zero;
2078 break;
2079 case NEON_FCMEQ_zero:
2080 mnemonic = "fcmeq";
2081 form = form_fcmp_zero;
2082 break;
2083 case NEON_FCMLE_zero:
2084 mnemonic = "fcmle";
2085 form = form_fcmp_zero;
2086 break;
2087 case NEON_FCMLT_zero:
2088 mnemonic = "fcmlt";
2089 form = form_fcmp_zero;
2090 break;
2091 default:
2092 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) &&
2093 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) {
2094 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2095 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2096
2097 switch (instr->Mask(NEON2RegMiscMask)) {
2098 case NEON_XTN:
2099 mnemonic = "xtn";
2100 break;
2101 case NEON_SQXTN:
2102 mnemonic = "sqxtn";
2103 break;
2104 case NEON_UQXTN:
2105 mnemonic = "uqxtn";
2106 break;
2107 case NEON_SQXTUN:
2108 mnemonic = "sqxtun";
2109 break;
2110 case NEON_SHLL:
2111 mnemonic = "shll";
2112 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap());
2113 nfd.SetFormatMap(1, nfd.IntegerFormatMap());
2114 switch (instr->GetNEONSize()) {
2115 case 0:
2116 form = "'Vd.%s, 'Vn.%s, #8";
2117 break;
2118 case 1:
2119 form = "'Vd.%s, 'Vn.%s, #16";
2120 break;
2121 case 2:
2122 form = "'Vd.%s, 'Vn.%s, #32";
2123 break;
2124 default:
2125 Format(instr, "unallocated", "(NEON2RegMisc)");
2126 return;
2127 }
2128 }
2129 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));
2130 return;
2131 } else {
2132 form = "(NEON2RegMisc)";
2133 }
2134 }
2135 }
2136 Format(instr, mnemonic, nfd.Substitute(form));
2137 }
2138
2139
VisitNEON3Same(const Instruction * instr)2140 void Disassembler::VisitNEON3Same(const Instruction *instr) {
2141 const char *mnemonic = "unimplemented";
2142 const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
2143 NEONFormatDecoder nfd(instr);
2144
2145 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) {
2146 switch (instr->Mask(NEON3SameLogicalMask)) {
2147 case NEON_AND:
2148 mnemonic = "and";
2149 break;
2150 case NEON_ORR:
2151 mnemonic = "orr";
2152 if (instr->GetRm() == instr->GetRn()) {
2153 mnemonic = "mov";
2154 form = "'Vd.%s, 'Vn.%s";
2155 }
2156 break;
2157 case NEON_ORN:
2158 mnemonic = "orn";
2159 break;
2160 case NEON_EOR:
2161 mnemonic = "eor";
2162 break;
2163 case NEON_BIC:
2164 mnemonic = "bic";
2165 break;
2166 case NEON_BIF:
2167 mnemonic = "bif";
2168 break;
2169 case NEON_BIT:
2170 mnemonic = "bit";
2171 break;
2172 case NEON_BSL:
2173 mnemonic = "bsl";
2174 break;
2175 default:
2176 form = "(NEON3Same)";
2177 }
2178 nfd.SetFormatMaps(nfd.LogicalFormatMap());
2179 } else {
2180 static const char *mnemonics[] = {"shadd",
2181 "uhadd",
2182 "shadd",
2183 "uhadd",
2184 "sqadd",
2185 "uqadd",
2186 "sqadd",
2187 "uqadd",
2188 "srhadd",
2189 "urhadd",
2190 "srhadd",
2191 "urhadd",
2192 // Handled by logical cases above.
2193 NULL,
2194 NULL,
2195 NULL,
2196 NULL,
2197 "shsub",
2198 "uhsub",
2199 "shsub",
2200 "uhsub",
2201 "sqsub",
2202 "uqsub",
2203 "sqsub",
2204 "uqsub",
2205 "cmgt",
2206 "cmhi",
2207 "cmgt",
2208 "cmhi",
2209 "cmge",
2210 "cmhs",
2211 "cmge",
2212 "cmhs",
2213 "sshl",
2214 "ushl",
2215 "sshl",
2216 "ushl",
2217 "sqshl",
2218 "uqshl",
2219 "sqshl",
2220 "uqshl",
2221 "srshl",
2222 "urshl",
2223 "srshl",
2224 "urshl",
2225 "sqrshl",
2226 "uqrshl",
2227 "sqrshl",
2228 "uqrshl",
2229 "smax",
2230 "umax",
2231 "smax",
2232 "umax",
2233 "smin",
2234 "umin",
2235 "smin",
2236 "umin",
2237 "sabd",
2238 "uabd",
2239 "sabd",
2240 "uabd",
2241 "saba",
2242 "uaba",
2243 "saba",
2244 "uaba",
2245 "add",
2246 "sub",
2247 "add",
2248 "sub",
2249 "cmtst",
2250 "cmeq",
2251 "cmtst",
2252 "cmeq",
2253 "mla",
2254 "mls",
2255 "mla",
2256 "mls",
2257 "mul",
2258 "pmul",
2259 "mul",
2260 "pmul",
2261 "smaxp",
2262 "umaxp",
2263 "smaxp",
2264 "umaxp",
2265 "sminp",
2266 "uminp",
2267 "sminp",
2268 "uminp",
2269 "sqdmulh",
2270 "sqrdmulh",
2271 "sqdmulh",
2272 "sqrdmulh",
2273 "addp",
2274 "unallocated",
2275 "addp",
2276 "unallocated",
2277 "fmaxnm",
2278 "fmaxnmp",
2279 "fminnm",
2280 "fminnmp",
2281 "fmla",
2282 "unallocated",
2283 "fmls",
2284 "unallocated",
2285 "fadd",
2286 "faddp",
2287 "fsub",
2288 "fabd",
2289 "fmulx",
2290 "fmul",
2291 "unallocated",
2292 "unallocated",
2293 "fcmeq",
2294 "fcmge",
2295 "unallocated",
2296 "fcmgt",
2297 "unallocated",
2298 "facge",
2299 "unallocated",
2300 "facgt",
2301 "fmax",
2302 "fmaxp",
2303 "fmin",
2304 "fminp",
2305 "frecps",
2306 "fdiv",
2307 "frsqrts",
2308 "unallocated"};
2309
2310 // Operation is determined by the opcode bits (15-11), the top bit of
2311 // size (23) and the U bit (29).
2312 unsigned index = (instr->ExtractBits(15, 11) << 2) |
2313 (instr->ExtractBit(23) << 1) | instr->ExtractBit(29);
2314 VIXL_ASSERT(index < (sizeof(mnemonics) / sizeof(mnemonics[0])));
2315 mnemonic = mnemonics[index];
2316 // Assert that index is not one of the previously handled logical
2317 // instructions.
2318 VIXL_ASSERT(mnemonic != NULL);
2319
2320 if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
2321 nfd.SetFormatMaps(nfd.FPFormatMap());
2322 }
2323 }
2324 Format(instr, mnemonic, nfd.Substitute(form));
2325 }
2326
2327
VisitNEON3Different(const Instruction * instr)2328 void Disassembler::VisitNEON3Different(const Instruction *instr) {
2329 const char *mnemonic = "unimplemented";
2330 const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
2331
2332 NEONFormatDecoder nfd(instr);
2333 nfd.SetFormatMap(0, nfd.LongIntegerFormatMap());
2334
2335 // Ignore the Q bit. Appending a "2" suffix is handled later.
2336 switch (instr->Mask(NEON3DifferentMask) & ~NEON_Q) {
2337 case NEON_PMULL:
2338 mnemonic = "pmull";
2339 break;
2340 case NEON_SABAL:
2341 mnemonic = "sabal";
2342 break;
2343 case NEON_SABDL:
2344 mnemonic = "sabdl";
2345 break;
2346 case NEON_SADDL:
2347 mnemonic = "saddl";
2348 break;
2349 case NEON_SMLAL:
2350 mnemonic = "smlal";
2351 break;
2352 case NEON_SMLSL:
2353 mnemonic = "smlsl";
2354 break;
2355 case NEON_SMULL:
2356 mnemonic = "smull";
2357 break;
2358 case NEON_SSUBL:
2359 mnemonic = "ssubl";
2360 break;
2361 case NEON_SQDMLAL:
2362 mnemonic = "sqdmlal";
2363 break;
2364 case NEON_SQDMLSL:
2365 mnemonic = "sqdmlsl";
2366 break;
2367 case NEON_SQDMULL:
2368 mnemonic = "sqdmull";
2369 break;
2370 case NEON_UABAL:
2371 mnemonic = "uabal";
2372 break;
2373 case NEON_UABDL:
2374 mnemonic = "uabdl";
2375 break;
2376 case NEON_UADDL:
2377 mnemonic = "uaddl";
2378 break;
2379 case NEON_UMLAL:
2380 mnemonic = "umlal";
2381 break;
2382 case NEON_UMLSL:
2383 mnemonic = "umlsl";
2384 break;
2385 case NEON_UMULL:
2386 mnemonic = "umull";
2387 break;
2388 case NEON_USUBL:
2389 mnemonic = "usubl";
2390 break;
2391 case NEON_SADDW:
2392 mnemonic = "saddw";
2393 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2394 break;
2395 case NEON_SSUBW:
2396 mnemonic = "ssubw";
2397 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2398 break;
2399 case NEON_UADDW:
2400 mnemonic = "uaddw";
2401 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2402 break;
2403 case NEON_USUBW:
2404 mnemonic = "usubw";
2405 nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());
2406 break;
2407 case NEON_ADDHN:
2408 mnemonic = "addhn";
2409 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
2410 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2411 break;
2412 case NEON_RADDHN:
2413 mnemonic = "raddhn";
2414 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
2415 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2416 break;
2417 case NEON_RSUBHN:
2418 mnemonic = "rsubhn";
2419 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
2420 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2421 break;
2422 case NEON_SUBHN:
2423 mnemonic = "subhn";
2424 nfd.SetFormatMaps(nfd.LongIntegerFormatMap());
2425 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2426 break;
2427 default:
2428 form = "(NEON3Different)";
2429 }
2430 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));
2431 }
2432
2433
VisitNEONAcrossLanes(const Instruction * instr)2434 void Disassembler::VisitNEONAcrossLanes(const Instruction *instr) {
2435 const char *mnemonic = "unimplemented";
2436 const char *form = "%sd, 'Vn.%s";
2437
2438 NEONFormatDecoder nfd(instr,
2439 NEONFormatDecoder::ScalarFormatMap(),
2440 NEONFormatDecoder::IntegerFormatMap());
2441
2442 if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
2443 nfd.SetFormatMap(0, nfd.FPScalarFormatMap());
2444 nfd.SetFormatMap(1, nfd.FPFormatMap());
2445 switch (instr->Mask(NEONAcrossLanesFPMask)) {
2446 case NEON_FMAXV:
2447 mnemonic = "fmaxv";
2448 break;
2449 case NEON_FMINV:
2450 mnemonic = "fminv";
2451 break;
2452 case NEON_FMAXNMV:
2453 mnemonic = "fmaxnmv";
2454 break;
2455 case NEON_FMINNMV:
2456 mnemonic = "fminnmv";
2457 break;
2458 default:
2459 form = "(NEONAcrossLanes)";
2460 break;
2461 }
2462 } else if (instr->Mask(NEONAcrossLanesFMask) == NEONAcrossLanesFixed) {
2463 switch (instr->Mask(NEONAcrossLanesMask)) {
2464 case NEON_ADDV:
2465 mnemonic = "addv";
2466 break;
2467 case NEON_SMAXV:
2468 mnemonic = "smaxv";
2469 break;
2470 case NEON_SMINV:
2471 mnemonic = "sminv";
2472 break;
2473 case NEON_UMAXV:
2474 mnemonic = "umaxv";
2475 break;
2476 case NEON_UMINV:
2477 mnemonic = "uminv";
2478 break;
2479 case NEON_SADDLV:
2480 mnemonic = "saddlv";
2481 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
2482 break;
2483 case NEON_UADDLV:
2484 mnemonic = "uaddlv";
2485 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
2486 break;
2487 default:
2488 form = "(NEONAcrossLanes)";
2489 break;
2490 }
2491 }
2492 Format(instr,
2493 mnemonic,
2494 nfd.Substitute(form,
2495 NEONFormatDecoder::kPlaceholder,
2496 NEONFormatDecoder::kFormat));
2497 }
2498
2499
VisitNEONByIndexedElement(const Instruction * instr)2500 void Disassembler::VisitNEONByIndexedElement(const Instruction *instr) {
2501 const char *mnemonic = "unimplemented";
2502 bool l_instr = false;
2503 bool fp_instr = false;
2504
2505 const char *form = "'Vd.%s, 'Vn.%s, 'Ve.%s['IVByElemIndex]";
2506
2507 static const NEONFormatMap map_ta = {{23, 22}, {NF_UNDEF, NF_4S, NF_2D}};
2508 NEONFormatDecoder nfd(instr,
2509 &map_ta,
2510 NEONFormatDecoder::IntegerFormatMap(),
2511 NEONFormatDecoder::ScalarFormatMap());
2512
2513 switch (instr->Mask(NEONByIndexedElementMask)) {
2514 case NEON_SMULL_byelement:
2515 mnemonic = "smull";
2516 l_instr = true;
2517 break;
2518 case NEON_UMULL_byelement:
2519 mnemonic = "umull";
2520 l_instr = true;
2521 break;
2522 case NEON_SMLAL_byelement:
2523 mnemonic = "smlal";
2524 l_instr = true;
2525 break;
2526 case NEON_UMLAL_byelement:
2527 mnemonic = "umlal";
2528 l_instr = true;
2529 break;
2530 case NEON_SMLSL_byelement:
2531 mnemonic = "smlsl";
2532 l_instr = true;
2533 break;
2534 case NEON_UMLSL_byelement:
2535 mnemonic = "umlsl";
2536 l_instr = true;
2537 break;
2538 case NEON_SQDMULL_byelement:
2539 mnemonic = "sqdmull";
2540 l_instr = true;
2541 break;
2542 case NEON_SQDMLAL_byelement:
2543 mnemonic = "sqdmlal";
2544 l_instr = true;
2545 break;
2546 case NEON_SQDMLSL_byelement:
2547 mnemonic = "sqdmlsl";
2548 l_instr = true;
2549 break;
2550 case NEON_MUL_byelement:
2551 mnemonic = "mul";
2552 break;
2553 case NEON_MLA_byelement:
2554 mnemonic = "mla";
2555 break;
2556 case NEON_MLS_byelement:
2557 mnemonic = "mls";
2558 break;
2559 case NEON_SQDMULH_byelement:
2560 mnemonic = "sqdmulh";
2561 break;
2562 case NEON_SQRDMULH_byelement:
2563 mnemonic = "sqrdmulh";
2564 break;
2565 default:
2566 switch (instr->Mask(NEONByIndexedElementFPMask)) {
2567 case NEON_FMUL_byelement:
2568 mnemonic = "fmul";
2569 fp_instr = true;
2570 break;
2571 case NEON_FMLA_byelement:
2572 mnemonic = "fmla";
2573 fp_instr = true;
2574 break;
2575 case NEON_FMLS_byelement:
2576 mnemonic = "fmls";
2577 fp_instr = true;
2578 break;
2579 case NEON_FMULX_byelement:
2580 mnemonic = "fmulx";
2581 fp_instr = true;
2582 break;
2583 }
2584 }
2585
2586 if (l_instr) {
2587 Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));
2588 } else if (fp_instr) {
2589 nfd.SetFormatMap(0, nfd.FPFormatMap());
2590 Format(instr, mnemonic, nfd.Substitute(form));
2591 } else {
2592 nfd.SetFormatMap(0, nfd.IntegerFormatMap());
2593 Format(instr, mnemonic, nfd.Substitute(form));
2594 }
2595 }
2596
2597
VisitNEONCopy(const Instruction * instr)2598 void Disassembler::VisitNEONCopy(const Instruction *instr) {
2599 const char *mnemonic = "unimplemented";
2600 const char *form = "(NEONCopy)";
2601
2602 NEONFormatDecoder nfd(instr,
2603 NEONFormatDecoder::TriangularFormatMap(),
2604 NEONFormatDecoder::TriangularScalarFormatMap());
2605
2606 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) {
2607 mnemonic = "mov";
2608 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
2609 form = "'Vd.%s['IVInsIndex1], 'Vn.%s['IVInsIndex2]";
2610 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) {
2611 mnemonic = "mov";
2612 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
2613 if (nfd.GetVectorFormat() == kFormatD) {
2614 form = "'Vd.%s['IVInsIndex1], 'Xn";
2615 } else {
2616 form = "'Vd.%s['IVInsIndex1], 'Wn";
2617 }
2618 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) {
2619 if (instr->Mask(NEON_Q) || ((instr->GetImmNEON5() & 7) == 4)) {
2620 mnemonic = "mov";
2621 } else {
2622 mnemonic = "umov";
2623 }
2624 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
2625 if (nfd.GetVectorFormat() == kFormatD) {
2626 form = "'Xd, 'Vn.%s['IVInsIndex1]";
2627 } else {
2628 form = "'Wd, 'Vn.%s['IVInsIndex1]";
2629 }
2630 } else if (instr->Mask(NEONCopySmovMask) == NEON_SMOV) {
2631 mnemonic = "smov";
2632 nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());
2633 form = "'Rdq, 'Vn.%s['IVInsIndex1]";
2634 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) {
2635 mnemonic = "dup";
2636 form = "'Vd.%s, 'Vn.%s['IVInsIndex1]";
2637 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) {
2638 mnemonic = "dup";
2639 if (nfd.GetVectorFormat() == kFormat2D) {
2640 form = "'Vd.%s, 'Xn";
2641 } else {
2642 form = "'Vd.%s, 'Wn";
2643 }
2644 }
2645 Format(instr, mnemonic, nfd.Substitute(form));
2646 }
2647
2648
VisitNEONExtract(const Instruction * instr)2649 void Disassembler::VisitNEONExtract(const Instruction *instr) {
2650 const char *mnemonic = "unimplemented";
2651 const char *form = "(NEONExtract)";
2652 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
2653 if (instr->Mask(NEONExtractMask) == NEON_EXT) {
2654 mnemonic = "ext";
2655 form = "'Vd.%s, 'Vn.%s, 'Vm.%s, 'IVExtract";
2656 }
2657 Format(instr, mnemonic, nfd.Substitute(form));
2658 }
2659
2660
VisitNEONLoadStoreMultiStruct(const Instruction * instr)2661 void Disassembler::VisitNEONLoadStoreMultiStruct(const Instruction *instr) {
2662 const char *mnemonic = NULL;
2663 const char *form = NULL;
2664 const char *form_1v = "{'Vt.%1$s}, ['Xns]";
2665 const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns]";
2666 const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns]";
2667 const char *form_4v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]";
2668 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
2669
2670 switch (instr->Mask(NEONLoadStoreMultiStructMask)) {
2671 case NEON_LD1_1v:
2672 mnemonic = "ld1";
2673 form = form_1v;
2674 break;
2675 case NEON_LD1_2v:
2676 mnemonic = "ld1";
2677 form = form_2v;
2678 break;
2679 case NEON_LD1_3v:
2680 mnemonic = "ld1";
2681 form = form_3v;
2682 break;
2683 case NEON_LD1_4v:
2684 mnemonic = "ld1";
2685 form = form_4v;
2686 break;
2687 case NEON_LD2:
2688 mnemonic = "ld2";
2689 form = form_2v;
2690 break;
2691 case NEON_LD3:
2692 mnemonic = "ld3";
2693 form = form_3v;
2694 break;
2695 case NEON_LD4:
2696 mnemonic = "ld4";
2697 form = form_4v;
2698 break;
2699 case NEON_ST1_1v:
2700 mnemonic = "st1";
2701 form = form_1v;
2702 break;
2703 case NEON_ST1_2v:
2704 mnemonic = "st1";
2705 form = form_2v;
2706 break;
2707 case NEON_ST1_3v:
2708 mnemonic = "st1";
2709 form = form_3v;
2710 break;
2711 case NEON_ST1_4v:
2712 mnemonic = "st1";
2713 form = form_4v;
2714 break;
2715 case NEON_ST2:
2716 mnemonic = "st2";
2717 form = form_2v;
2718 break;
2719 case NEON_ST3:
2720 mnemonic = "st3";
2721 form = form_3v;
2722 break;
2723 case NEON_ST4:
2724 mnemonic = "st4";
2725 form = form_4v;
2726 break;
2727 default:
2728 break;
2729 }
2730
2731 // Work out unallocated encodings.
2732 bool allocated = (mnemonic != NULL);
2733 switch (instr->Mask(NEONLoadStoreMultiStructMask)) {
2734 case NEON_LD2:
2735 case NEON_LD3:
2736 case NEON_LD4:
2737 case NEON_ST2:
2738 case NEON_ST3:
2739 case NEON_ST4:
2740 // LD[2-4] and ST[2-4] cannot use .1d format.
2741 allocated = (instr->GetNEONQ() != 0) || (instr->GetNEONLSSize() != 3);
2742 break;
2743 default:
2744 break;
2745 }
2746 if (allocated) {
2747 VIXL_ASSERT(mnemonic != NULL);
2748 VIXL_ASSERT(form != NULL);
2749 } else {
2750 mnemonic = "unallocated";
2751 form = "(NEONLoadStoreMultiStruct)";
2752 }
2753
2754 Format(instr, mnemonic, nfd.Substitute(form));
2755 }
2756
2757
VisitNEONLoadStoreMultiStructPostIndex(const Instruction * instr)2758 void Disassembler::VisitNEONLoadStoreMultiStructPostIndex(
2759 const Instruction *instr) {
2760 const char *mnemonic = NULL;
2761 const char *form = NULL;
2762 const char *form_1v = "{'Vt.%1$s}, ['Xns], 'Xmr1";
2763 const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns], 'Xmr2";
2764 const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns], 'Xmr3";
2765 const char *form_4v =
2766 "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmr4";
2767 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
2768
2769 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {
2770 case NEON_LD1_1v_post:
2771 mnemonic = "ld1";
2772 form = form_1v;
2773 break;
2774 case NEON_LD1_2v_post:
2775 mnemonic = "ld1";
2776 form = form_2v;
2777 break;
2778 case NEON_LD1_3v_post:
2779 mnemonic = "ld1";
2780 form = form_3v;
2781 break;
2782 case NEON_LD1_4v_post:
2783 mnemonic = "ld1";
2784 form = form_4v;
2785 break;
2786 case NEON_LD2_post:
2787 mnemonic = "ld2";
2788 form = form_2v;
2789 break;
2790 case NEON_LD3_post:
2791 mnemonic = "ld3";
2792 form = form_3v;
2793 break;
2794 case NEON_LD4_post:
2795 mnemonic = "ld4";
2796 form = form_4v;
2797 break;
2798 case NEON_ST1_1v_post:
2799 mnemonic = "st1";
2800 form = form_1v;
2801 break;
2802 case NEON_ST1_2v_post:
2803 mnemonic = "st1";
2804 form = form_2v;
2805 break;
2806 case NEON_ST1_3v_post:
2807 mnemonic = "st1";
2808 form = form_3v;
2809 break;
2810 case NEON_ST1_4v_post:
2811 mnemonic = "st1";
2812 form = form_4v;
2813 break;
2814 case NEON_ST2_post:
2815 mnemonic = "st2";
2816 form = form_2v;
2817 break;
2818 case NEON_ST3_post:
2819 mnemonic = "st3";
2820 form = form_3v;
2821 break;
2822 case NEON_ST4_post:
2823 mnemonic = "st4";
2824 form = form_4v;
2825 break;
2826 default:
2827 break;
2828 }
2829
2830 // Work out unallocated encodings.
2831 bool allocated = (mnemonic != NULL);
2832 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {
2833 case NEON_LD2_post:
2834 case NEON_LD3_post:
2835 case NEON_LD4_post:
2836 case NEON_ST2_post:
2837 case NEON_ST3_post:
2838 case NEON_ST4_post:
2839 // LD[2-4] and ST[2-4] cannot use .1d format.
2840 allocated = (instr->GetNEONQ() != 0) || (instr->GetNEONLSSize() != 3);
2841 break;
2842 default:
2843 break;
2844 }
2845 if (allocated) {
2846 VIXL_ASSERT(mnemonic != NULL);
2847 VIXL_ASSERT(form != NULL);
2848 } else {
2849 mnemonic = "unallocated";
2850 form = "(NEONLoadStoreMultiStructPostIndex)";
2851 }
2852
2853 Format(instr, mnemonic, nfd.Substitute(form));
2854 }
2855
2856
VisitNEONLoadStoreSingleStruct(const Instruction * instr)2857 void Disassembler::VisitNEONLoadStoreSingleStruct(const Instruction *instr) {
2858 const char *mnemonic = NULL;
2859 const char *form = NULL;
2860
2861 const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns]";
2862 const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns]";
2863 const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns]";
2864 const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns]";
2865 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
2866
2867 switch (instr->Mask(NEONLoadStoreSingleStructMask)) {
2868 case NEON_LD1_b:
2869 mnemonic = "ld1";
2870 form = form_1b;
2871 break;
2872 case NEON_LD1_h:
2873 mnemonic = "ld1";
2874 form = form_1h;
2875 break;
2876 case NEON_LD1_s:
2877 mnemonic = "ld1";
2878 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);
2879 form = ((instr->GetNEONLSSize() & 1) == 0) ? form_1s : form_1d;
2880 break;
2881 case NEON_ST1_b:
2882 mnemonic = "st1";
2883 form = form_1b;
2884 break;
2885 case NEON_ST1_h:
2886 mnemonic = "st1";
2887 form = form_1h;
2888 break;
2889 case NEON_ST1_s:
2890 mnemonic = "st1";
2891 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);
2892 form = ((instr->GetNEONLSSize() & 1) == 0) ? form_1s : form_1d;
2893 break;
2894 case NEON_LD1R:
2895 mnemonic = "ld1r";
2896 form = "{'Vt.%s}, ['Xns]";
2897 break;
2898 case NEON_LD2_b:
2899 case NEON_ST2_b:
2900 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";
2901 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns]";
2902 break;
2903 case NEON_LD2_h:
2904 case NEON_ST2_h:
2905 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";
2906 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns]";
2907 break;
2908 case NEON_LD2_s:
2909 case NEON_ST2_s:
2910 VIXL_STATIC_ASSERT((NEON_ST2_s | (1 << NEONLSSize_offset)) == NEON_ST2_d);
2911 VIXL_STATIC_ASSERT((NEON_LD2_s | (1 << NEONLSSize_offset)) == NEON_LD2_d);
2912 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";
2913 if ((instr->GetNEONLSSize() & 1) == 0) {
2914 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns]";
2915 } else {
2916 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns]";
2917 }
2918 break;
2919 case NEON_LD2R:
2920 mnemonic = "ld2r";
2921 form = "{'Vt.%s, 'Vt2.%s}, ['Xns]";
2922 break;
2923 case NEON_LD3_b:
2924 case NEON_ST3_b:
2925 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";
2926 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns]";
2927 break;
2928 case NEON_LD3_h:
2929 case NEON_ST3_h:
2930 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";
2931 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns]";
2932 break;
2933 case NEON_LD3_s:
2934 case NEON_ST3_s:
2935 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";
2936 if ((instr->GetNEONLSSize() & 1) == 0) {
2937 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns]";
2938 } else {
2939 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns]";
2940 }
2941 break;
2942 case NEON_LD3R:
2943 mnemonic = "ld3r";
2944 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns]";
2945 break;
2946 case NEON_LD4_b:
2947 case NEON_ST4_b:
2948 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";
2949 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns]";
2950 break;
2951 case NEON_LD4_h:
2952 case NEON_ST4_h:
2953 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";
2954 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns]";
2955 break;
2956 case NEON_LD4_s:
2957 case NEON_ST4_s:
2958 VIXL_STATIC_ASSERT((NEON_LD4_s | (1 << NEONLSSize_offset)) == NEON_LD4_d);
2959 VIXL_STATIC_ASSERT((NEON_ST4_s | (1 << NEONLSSize_offset)) == NEON_ST4_d);
2960 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";
2961 if ((instr->GetNEONLSSize() & 1) == 0) {
2962 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns]";
2963 } else {
2964 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns]";
2965 }
2966 break;
2967 case NEON_LD4R:
2968 mnemonic = "ld4r";
2969 form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]";
2970 break;
2971 default:
2972 break;
2973 }
2974
2975 // Work out unallocated encodings.
2976 bool allocated = (mnemonic != NULL);
2977 switch (instr->Mask(NEONLoadStoreSingleStructMask)) {
2978 case NEON_LD1_h:
2979 case NEON_LD2_h:
2980 case NEON_LD3_h:
2981 case NEON_LD4_h:
2982 case NEON_ST1_h:
2983 case NEON_ST2_h:
2984 case NEON_ST3_h:
2985 case NEON_ST4_h:
2986 VIXL_ASSERT(allocated);
2987 allocated = ((instr->GetNEONLSSize() & 1) == 0);
2988 break;
2989 case NEON_LD1_s:
2990 case NEON_LD2_s:
2991 case NEON_LD3_s:
2992 case NEON_LD4_s:
2993 case NEON_ST1_s:
2994 case NEON_ST2_s:
2995 case NEON_ST3_s:
2996 case NEON_ST4_s:
2997 VIXL_ASSERT(allocated);
2998 allocated = (instr->GetNEONLSSize() <= 1) &&
2999 ((instr->GetNEONLSSize() == 0) || (instr->GetNEONS() == 0));
3000 break;
3001 case NEON_LD1R:
3002 case NEON_LD2R:
3003 case NEON_LD3R:
3004 case NEON_LD4R:
3005 VIXL_ASSERT(allocated);
3006 allocated = (instr->GetNEONS() == 0);
3007 break;
3008 default:
3009 break;
3010 }
3011 if (allocated) {
3012 VIXL_ASSERT(mnemonic != NULL);
3013 VIXL_ASSERT(form != NULL);
3014 } else {
3015 mnemonic = "unallocated";
3016 form = "(NEONLoadStoreSingleStruct)";
3017 }
3018
3019 Format(instr, mnemonic, nfd.Substitute(form));
3020 }
3021
3022
VisitNEONLoadStoreSingleStructPostIndex(const Instruction * instr)3023 void Disassembler::VisitNEONLoadStoreSingleStructPostIndex(
3024 const Instruction *instr) {
3025 const char *mnemonic = NULL;
3026 const char *form = NULL;
3027
3028 const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns], 'Xmb1";
3029 const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns], 'Xmb2";
3030 const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns], 'Xmb4";
3031 const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns], 'Xmb8";
3032 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
3033
3034 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {
3035 case NEON_LD1_b_post:
3036 mnemonic = "ld1";
3037 form = form_1b;
3038 break;
3039 case NEON_LD1_h_post:
3040 mnemonic = "ld1";
3041 form = form_1h;
3042 break;
3043 case NEON_LD1_s_post:
3044 mnemonic = "ld1";
3045 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);
3046 form = ((instr->GetNEONLSSize() & 1) == 0) ? form_1s : form_1d;
3047 break;
3048 case NEON_ST1_b_post:
3049 mnemonic = "st1";
3050 form = form_1b;
3051 break;
3052 case NEON_ST1_h_post:
3053 mnemonic = "st1";
3054 form = form_1h;
3055 break;
3056 case NEON_ST1_s_post:
3057 mnemonic = "st1";
3058 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);
3059 form = ((instr->GetNEONLSSize() & 1) == 0) ? form_1s : form_1d;
3060 break;
3061 case NEON_LD1R_post:
3062 mnemonic = "ld1r";
3063 form = "{'Vt.%s}, ['Xns], 'Xmz1";
3064 break;
3065 case NEON_LD2_b_post:
3066 case NEON_ST2_b_post:
3067 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";
3068 form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns], 'Xmb2";
3069 break;
3070 case NEON_ST2_h_post:
3071 case NEON_LD2_h_post:
3072 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";
3073 form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns], 'Xmb4";
3074 break;
3075 case NEON_LD2_s_post:
3076 case NEON_ST2_s_post:
3077 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";
3078 if ((instr->GetNEONLSSize() & 1) == 0)
3079 form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns], 'Xmb8";
3080 else
3081 form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns], 'Xmb16";
3082 break;
3083 case NEON_LD2R_post:
3084 mnemonic = "ld2r";
3085 form = "{'Vt.%s, 'Vt2.%s}, ['Xns], 'Xmz2";
3086 break;
3087 case NEON_LD3_b_post:
3088 case NEON_ST3_b_post:
3089 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";
3090 form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns], 'Xmb3";
3091 break;
3092 case NEON_LD3_h_post:
3093 case NEON_ST3_h_post:
3094 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";
3095 form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns], 'Xmb6";
3096 break;
3097 case NEON_LD3_s_post:
3098 case NEON_ST3_s_post:
3099 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";
3100 if ((instr->GetNEONLSSize() & 1) == 0)
3101 form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns], 'Xmb12";
3102 else
3103 form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns], 'Xmb24";
3104 break;
3105 case NEON_LD3R_post:
3106 mnemonic = "ld3r";
3107 form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns], 'Xmz3";
3108 break;
3109 case NEON_LD4_b_post:
3110 case NEON_ST4_b_post:
3111 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";
3112 form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns], 'Xmb4";
3113 break;
3114 case NEON_LD4_h_post:
3115 case NEON_ST4_h_post:
3116 mnemonic = (instr->GetLdStXLoad()) == 1 ? "ld4" : "st4";
3117 form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns], 'Xmb8";
3118 break;
3119 case NEON_LD4_s_post:
3120 case NEON_ST4_s_post:
3121 mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";
3122 if ((instr->GetNEONLSSize() & 1) == 0)
3123 form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns], 'Xmb16";
3124 else
3125 form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns], 'Xmb32";
3126 break;
3127 case NEON_LD4R_post:
3128 mnemonic = "ld4r";
3129 form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmz4";
3130 break;
3131 default:
3132 break;
3133 }
3134
3135 // Work out unallocated encodings.
3136 bool allocated = (mnemonic != NULL);
3137 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {
3138 case NEON_LD1_h_post:
3139 case NEON_LD2_h_post:
3140 case NEON_LD3_h_post:
3141 case NEON_LD4_h_post:
3142 case NEON_ST1_h_post:
3143 case NEON_ST2_h_post:
3144 case NEON_ST3_h_post:
3145 case NEON_ST4_h_post:
3146 VIXL_ASSERT(allocated);
3147 allocated = ((instr->GetNEONLSSize() & 1) == 0);
3148 break;
3149 case NEON_LD1_s_post:
3150 case NEON_LD2_s_post:
3151 case NEON_LD3_s_post:
3152 case NEON_LD4_s_post:
3153 case NEON_ST1_s_post:
3154 case NEON_ST2_s_post:
3155 case NEON_ST3_s_post:
3156 case NEON_ST4_s_post:
3157 VIXL_ASSERT(allocated);
3158 allocated = (instr->GetNEONLSSize() <= 1) &&
3159 ((instr->GetNEONLSSize() == 0) || (instr->GetNEONS() == 0));
3160 break;
3161 case NEON_LD1R_post:
3162 case NEON_LD2R_post:
3163 case NEON_LD3R_post:
3164 case NEON_LD4R_post:
3165 VIXL_ASSERT(allocated);
3166 allocated = (instr->GetNEONS() == 0);
3167 break;
3168 default:
3169 break;
3170 }
3171 if (allocated) {
3172 VIXL_ASSERT(mnemonic != NULL);
3173 VIXL_ASSERT(form != NULL);
3174 } else {
3175 mnemonic = "unallocated";
3176 form = "(NEONLoadStoreSingleStructPostIndex)";
3177 }
3178
3179 Format(instr, mnemonic, nfd.Substitute(form));
3180 }
3181
3182
VisitNEONModifiedImmediate(const Instruction * instr)3183 void Disassembler::VisitNEONModifiedImmediate(const Instruction *instr) {
3184 const char *mnemonic = "unimplemented";
3185 const char *form = "'Vt.%s, 'IVMIImm8, lsl 'IVMIShiftAmt1";
3186
3187 int cmode = instr->GetNEONCmode();
3188 int cmode_3 = (cmode >> 3) & 1;
3189 int cmode_2 = (cmode >> 2) & 1;
3190 int cmode_1 = (cmode >> 1) & 1;
3191 int cmode_0 = cmode & 1;
3192 int q = instr->GetNEONQ();
3193 int op = instr->GetNEONModImmOp();
3194
3195 static const NEONFormatMap map_b = {{30}, {NF_8B, NF_16B}};
3196 static const NEONFormatMap map_h = {{30}, {NF_4H, NF_8H}};
3197 static const NEONFormatMap map_s = {{30}, {NF_2S, NF_4S}};
3198 NEONFormatDecoder nfd(instr, &map_b);
3199
3200 if (cmode_3 == 0) {
3201 if (cmode_0 == 0) {
3202 mnemonic = (op == 1) ? "mvni" : "movi";
3203 } else { // cmode<0> == '1'.
3204 mnemonic = (op == 1) ? "bic" : "orr";
3205 }
3206 nfd.SetFormatMap(0, &map_s);
3207 } else { // cmode<3> == '1'.
3208 if (cmode_2 == 0) {
3209 if (cmode_0 == 0) {
3210 mnemonic = (op == 1) ? "mvni" : "movi";
3211 } else { // cmode<0> == '1'.
3212 mnemonic = (op == 1) ? "bic" : "orr";
3213 }
3214 nfd.SetFormatMap(0, &map_h);
3215 } else { // cmode<2> == '1'.
3216 if (cmode_1 == 0) {
3217 mnemonic = (op == 1) ? "mvni" : "movi";
3218 form = "'Vt.%s, 'IVMIImm8, msl 'IVMIShiftAmt2";
3219 nfd.SetFormatMap(0, &map_s);
3220 } else { // cmode<1> == '1'.
3221 if (cmode_0 == 0) {
3222 mnemonic = "movi";
3223 if (op == 0) {
3224 form = "'Vt.%s, 'IVMIImm8";
3225 } else {
3226 form = (q == 0) ? "'Dd, 'IVMIImm" : "'Vt.2d, 'IVMIImm";
3227 }
3228 } else { // cmode<0> == '1'
3229 mnemonic = "fmov";
3230 if (op == 0) {
3231 form = "'Vt.%s, 'IVMIImmFPSingle";
3232 nfd.SetFormatMap(0, &map_s);
3233 } else {
3234 if (q == 1) {
3235 form = "'Vt.2d, 'IVMIImmFPDouble";
3236 } else {
3237 mnemonic = "unallocated";
3238 form = "(NEONModifiedImmediate)";
3239 }
3240 }
3241 }
3242 }
3243 }
3244 }
3245 Format(instr, mnemonic, nfd.Substitute(form));
3246 }
3247
3248
VisitNEONScalar2RegMisc(const Instruction * instr)3249 void Disassembler::VisitNEONScalar2RegMisc(const Instruction *instr) {
3250 const char *mnemonic = "unimplemented";
3251 const char *form = "%sd, %sn";
3252 const char *form_0 = "%sd, %sn, #0";
3253 const char *form_fp0 = "%sd, %sn, #0.0";
3254
3255 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3256
3257 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) {
3258 // These instructions all use a two bit size field, except NOT and RBIT,
3259 // which use the field to encode the operation.
3260 switch (instr->Mask(NEONScalar2RegMiscMask)) {
3261 case NEON_CMGT_zero_scalar:
3262 mnemonic = "cmgt";
3263 form = form_0;
3264 break;
3265 case NEON_CMGE_zero_scalar:
3266 mnemonic = "cmge";
3267 form = form_0;
3268 break;
3269 case NEON_CMLE_zero_scalar:
3270 mnemonic = "cmle";
3271 form = form_0;
3272 break;
3273 case NEON_CMLT_zero_scalar:
3274 mnemonic = "cmlt";
3275 form = form_0;
3276 break;
3277 case NEON_CMEQ_zero_scalar:
3278 mnemonic = "cmeq";
3279 form = form_0;
3280 break;
3281 case NEON_NEG_scalar:
3282 mnemonic = "neg";
3283 break;
3284 case NEON_SQNEG_scalar:
3285 mnemonic = "sqneg";
3286 break;
3287 case NEON_ABS_scalar:
3288 mnemonic = "abs";
3289 break;
3290 case NEON_SQABS_scalar:
3291 mnemonic = "sqabs";
3292 break;
3293 case NEON_SUQADD_scalar:
3294 mnemonic = "suqadd";
3295 break;
3296 case NEON_USQADD_scalar:
3297 mnemonic = "usqadd";
3298 break;
3299 default:
3300 form = "(NEONScalar2RegMisc)";
3301 }
3302 } else {
3303 // These instructions all use a one bit size field, except SQXTUN, SQXTN
3304 // and UQXTN, which use a two bit size field.
3305 nfd.SetFormatMaps(nfd.FPScalarFormatMap());
3306 switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
3307 case NEON_FRSQRTE_scalar:
3308 mnemonic = "frsqrte";
3309 break;
3310 case NEON_FRECPE_scalar:
3311 mnemonic = "frecpe";
3312 break;
3313 case NEON_SCVTF_scalar:
3314 mnemonic = "scvtf";
3315 break;
3316 case NEON_UCVTF_scalar:
3317 mnemonic = "ucvtf";
3318 break;
3319 case NEON_FCMGT_zero_scalar:
3320 mnemonic = "fcmgt";
3321 form = form_fp0;
3322 break;
3323 case NEON_FCMGE_zero_scalar:
3324 mnemonic = "fcmge";
3325 form = form_fp0;
3326 break;
3327 case NEON_FCMLE_zero_scalar:
3328 mnemonic = "fcmle";
3329 form = form_fp0;
3330 break;
3331 case NEON_FCMLT_zero_scalar:
3332 mnemonic = "fcmlt";
3333 form = form_fp0;
3334 break;
3335 case NEON_FCMEQ_zero_scalar:
3336 mnemonic = "fcmeq";
3337 form = form_fp0;
3338 break;
3339 case NEON_FRECPX_scalar:
3340 mnemonic = "frecpx";
3341 break;
3342 case NEON_FCVTNS_scalar:
3343 mnemonic = "fcvtns";
3344 break;
3345 case NEON_FCVTNU_scalar:
3346 mnemonic = "fcvtnu";
3347 break;
3348 case NEON_FCVTPS_scalar:
3349 mnemonic = "fcvtps";
3350 break;
3351 case NEON_FCVTPU_scalar:
3352 mnemonic = "fcvtpu";
3353 break;
3354 case NEON_FCVTMS_scalar:
3355 mnemonic = "fcvtms";
3356 break;
3357 case NEON_FCVTMU_scalar:
3358 mnemonic = "fcvtmu";
3359 break;
3360 case NEON_FCVTZS_scalar:
3361 mnemonic = "fcvtzs";
3362 break;
3363 case NEON_FCVTZU_scalar:
3364 mnemonic = "fcvtzu";
3365 break;
3366 case NEON_FCVTAS_scalar:
3367 mnemonic = "fcvtas";
3368 break;
3369 case NEON_FCVTAU_scalar:
3370 mnemonic = "fcvtau";
3371 break;
3372 case NEON_FCVTXN_scalar:
3373 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
3374 mnemonic = "fcvtxn";
3375 break;
3376 default:
3377 nfd.SetFormatMap(0, nfd.ScalarFormatMap());
3378 nfd.SetFormatMap(1, nfd.LongScalarFormatMap());
3379 switch (instr->Mask(NEONScalar2RegMiscMask)) {
3380 case NEON_SQXTN_scalar:
3381 mnemonic = "sqxtn";
3382 break;
3383 case NEON_UQXTN_scalar:
3384 mnemonic = "uqxtn";
3385 break;
3386 case NEON_SQXTUN_scalar:
3387 mnemonic = "sqxtun";
3388 break;
3389 default:
3390 form = "(NEONScalar2RegMisc)";
3391 }
3392 }
3393 }
3394 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
3395 }
3396
3397
VisitNEONScalar3Diff(const Instruction * instr)3398 void Disassembler::VisitNEONScalar3Diff(const Instruction *instr) {
3399 const char *mnemonic = "unimplemented";
3400 const char *form = "%sd, %sn, %sm";
3401 NEONFormatDecoder nfd(instr,
3402 NEONFormatDecoder::LongScalarFormatMap(),
3403 NEONFormatDecoder::ScalarFormatMap());
3404
3405 switch (instr->Mask(NEONScalar3DiffMask)) {
3406 case NEON_SQDMLAL_scalar:
3407 mnemonic = "sqdmlal";
3408 break;
3409 case NEON_SQDMLSL_scalar:
3410 mnemonic = "sqdmlsl";
3411 break;
3412 case NEON_SQDMULL_scalar:
3413 mnemonic = "sqdmull";
3414 break;
3415 default:
3416 form = "(NEONScalar3Diff)";
3417 }
3418 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
3419 }
3420
3421
VisitNEONScalar3Same(const Instruction * instr)3422 void Disassembler::VisitNEONScalar3Same(const Instruction *instr) {
3423 const char *mnemonic = "unimplemented";
3424 const char *form = "%sd, %sn, %sm";
3425 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3426
3427 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
3428 nfd.SetFormatMaps(nfd.FPScalarFormatMap());
3429 switch (instr->Mask(NEONScalar3SameFPMask)) {
3430 case NEON_FACGE_scalar:
3431 mnemonic = "facge";
3432 break;
3433 case NEON_FACGT_scalar:
3434 mnemonic = "facgt";
3435 break;
3436 case NEON_FCMEQ_scalar:
3437 mnemonic = "fcmeq";
3438 break;
3439 case NEON_FCMGE_scalar:
3440 mnemonic = "fcmge";
3441 break;
3442 case NEON_FCMGT_scalar:
3443 mnemonic = "fcmgt";
3444 break;
3445 case NEON_FMULX_scalar:
3446 mnemonic = "fmulx";
3447 break;
3448 case NEON_FRECPS_scalar:
3449 mnemonic = "frecps";
3450 break;
3451 case NEON_FRSQRTS_scalar:
3452 mnemonic = "frsqrts";
3453 break;
3454 case NEON_FABD_scalar:
3455 mnemonic = "fabd";
3456 break;
3457 default:
3458 form = "(NEONScalar3Same)";
3459 }
3460 } else {
3461 switch (instr->Mask(NEONScalar3SameMask)) {
3462 case NEON_ADD_scalar:
3463 mnemonic = "add";
3464 break;
3465 case NEON_SUB_scalar:
3466 mnemonic = "sub";
3467 break;
3468 case NEON_CMEQ_scalar:
3469 mnemonic = "cmeq";
3470 break;
3471 case NEON_CMGE_scalar:
3472 mnemonic = "cmge";
3473 break;
3474 case NEON_CMGT_scalar:
3475 mnemonic = "cmgt";
3476 break;
3477 case NEON_CMHI_scalar:
3478 mnemonic = "cmhi";
3479 break;
3480 case NEON_CMHS_scalar:
3481 mnemonic = "cmhs";
3482 break;
3483 case NEON_CMTST_scalar:
3484 mnemonic = "cmtst";
3485 break;
3486 case NEON_UQADD_scalar:
3487 mnemonic = "uqadd";
3488 break;
3489 case NEON_SQADD_scalar:
3490 mnemonic = "sqadd";
3491 break;
3492 case NEON_UQSUB_scalar:
3493 mnemonic = "uqsub";
3494 break;
3495 case NEON_SQSUB_scalar:
3496 mnemonic = "sqsub";
3497 break;
3498 case NEON_USHL_scalar:
3499 mnemonic = "ushl";
3500 break;
3501 case NEON_SSHL_scalar:
3502 mnemonic = "sshl";
3503 break;
3504 case NEON_UQSHL_scalar:
3505 mnemonic = "uqshl";
3506 break;
3507 case NEON_SQSHL_scalar:
3508 mnemonic = "sqshl";
3509 break;
3510 case NEON_URSHL_scalar:
3511 mnemonic = "urshl";
3512 break;
3513 case NEON_SRSHL_scalar:
3514 mnemonic = "srshl";
3515 break;
3516 case NEON_UQRSHL_scalar:
3517 mnemonic = "uqrshl";
3518 break;
3519 case NEON_SQRSHL_scalar:
3520 mnemonic = "sqrshl";
3521 break;
3522 case NEON_SQDMULH_scalar:
3523 mnemonic = "sqdmulh";
3524 break;
3525 case NEON_SQRDMULH_scalar:
3526 mnemonic = "sqrdmulh";
3527 break;
3528 default:
3529 form = "(NEONScalar3Same)";
3530 }
3531 }
3532 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
3533 }
3534
3535
VisitNEONScalarByIndexedElement(const Instruction * instr)3536 void Disassembler::VisitNEONScalarByIndexedElement(const Instruction *instr) {
3537 const char *mnemonic = "unimplemented";
3538 const char *form = "%sd, %sn, 'Ve.%s['IVByElemIndex]";
3539 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3540 bool long_instr = false;
3541
3542 switch (instr->Mask(NEONScalarByIndexedElementMask)) {
3543 case NEON_SQDMULL_byelement_scalar:
3544 mnemonic = "sqdmull";
3545 long_instr = true;
3546 break;
3547 case NEON_SQDMLAL_byelement_scalar:
3548 mnemonic = "sqdmlal";
3549 long_instr = true;
3550 break;
3551 case NEON_SQDMLSL_byelement_scalar:
3552 mnemonic = "sqdmlsl";
3553 long_instr = true;
3554 break;
3555 case NEON_SQDMULH_byelement_scalar:
3556 mnemonic = "sqdmulh";
3557 break;
3558 case NEON_SQRDMULH_byelement_scalar:
3559 mnemonic = "sqrdmulh";
3560 break;
3561 default:
3562 nfd.SetFormatMap(0, nfd.FPScalarFormatMap());
3563 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
3564 case NEON_FMUL_byelement_scalar:
3565 mnemonic = "fmul";
3566 break;
3567 case NEON_FMLA_byelement_scalar:
3568 mnemonic = "fmla";
3569 break;
3570 case NEON_FMLS_byelement_scalar:
3571 mnemonic = "fmls";
3572 break;
3573 case NEON_FMULX_byelement_scalar:
3574 mnemonic = "fmulx";
3575 break;
3576 default:
3577 form = "(NEONScalarByIndexedElement)";
3578 }
3579 }
3580
3581 if (long_instr) {
3582 nfd.SetFormatMap(0, nfd.LongScalarFormatMap());
3583 }
3584
3585 Format(instr,
3586 mnemonic,
3587 nfd.Substitute(form, nfd.kPlaceholder, nfd.kPlaceholder, nfd.kFormat));
3588 }
3589
3590
VisitNEONScalarCopy(const Instruction * instr)3591 void Disassembler::VisitNEONScalarCopy(const Instruction *instr) {
3592 const char *mnemonic = "unimplemented";
3593 const char *form = "(NEONScalarCopy)";
3594
3595 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());
3596
3597 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) {
3598 mnemonic = "mov";
3599 form = "%sd, 'Vn.%s['IVInsIndex1]";
3600 }
3601
3602 Format(instr, mnemonic, nfd.Substitute(form, nfd.kPlaceholder, nfd.kFormat));
3603 }
3604
3605
VisitNEONScalarPairwise(const Instruction * instr)3606 void Disassembler::VisitNEONScalarPairwise(const Instruction *instr) {
3607 const char *mnemonic = "unimplemented";
3608 const char *form = "%sd, 'Vn.%s";
3609 NEONFormatMap map = {{22}, {NF_2S, NF_2D}};
3610 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap(), &map);
3611
3612 switch (instr->Mask(NEONScalarPairwiseMask)) {
3613 case NEON_ADDP_scalar:
3614 mnemonic = "addp";
3615 break;
3616 case NEON_FADDP_scalar:
3617 mnemonic = "faddp";
3618 break;
3619 case NEON_FMAXP_scalar:
3620 mnemonic = "fmaxp";
3621 break;
3622 case NEON_FMAXNMP_scalar:
3623 mnemonic = "fmaxnmp";
3624 break;
3625 case NEON_FMINP_scalar:
3626 mnemonic = "fminp";
3627 break;
3628 case NEON_FMINNMP_scalar:
3629 mnemonic = "fminnmp";
3630 break;
3631 default:
3632 form = "(NEONScalarPairwise)";
3633 }
3634 Format(instr,
3635 mnemonic,
3636 nfd.Substitute(form,
3637 NEONFormatDecoder::kPlaceholder,
3638 NEONFormatDecoder::kFormat));
3639 }
3640
3641
VisitNEONScalarShiftImmediate(const Instruction * instr)3642 void Disassembler::VisitNEONScalarShiftImmediate(const Instruction *instr) {
3643 const char *mnemonic = "unimplemented";
3644 const char *form = "%sd, %sn, 'Is1";
3645 const char *form_2 = "%sd, %sn, 'Is2";
3646
3647 static const NEONFormatMap map_shift = {{22, 21, 20, 19},
3648 {NF_UNDEF,
3649 NF_B,
3650 NF_H,
3651 NF_H,
3652 NF_S,
3653 NF_S,
3654 NF_S,
3655 NF_S,
3656 NF_D,
3657 NF_D,
3658 NF_D,
3659 NF_D,
3660 NF_D,
3661 NF_D,
3662 NF_D,
3663 NF_D}};
3664 static const NEONFormatMap map_shift_narrow =
3665 {{21, 20, 19}, {NF_UNDEF, NF_H, NF_S, NF_S, NF_D, NF_D, NF_D, NF_D}};
3666 NEONFormatDecoder nfd(instr, &map_shift);
3667
3668 if (instr->GetImmNEONImmh()) { // immh has to be non-zero.
3669 switch (instr->Mask(NEONScalarShiftImmediateMask)) {
3670 case NEON_FCVTZU_imm_scalar:
3671 mnemonic = "fcvtzu";
3672 break;
3673 case NEON_FCVTZS_imm_scalar:
3674 mnemonic = "fcvtzs";
3675 break;
3676 case NEON_SCVTF_imm_scalar:
3677 mnemonic = "scvtf";
3678 break;
3679 case NEON_UCVTF_imm_scalar:
3680 mnemonic = "ucvtf";
3681 break;
3682 case NEON_SRI_scalar:
3683 mnemonic = "sri";
3684 break;
3685 case NEON_SSHR_scalar:
3686 mnemonic = "sshr";
3687 break;
3688 case NEON_USHR_scalar:
3689 mnemonic = "ushr";
3690 break;
3691 case NEON_SRSHR_scalar:
3692 mnemonic = "srshr";
3693 break;
3694 case NEON_URSHR_scalar:
3695 mnemonic = "urshr";
3696 break;
3697 case NEON_SSRA_scalar:
3698 mnemonic = "ssra";
3699 break;
3700 case NEON_USRA_scalar:
3701 mnemonic = "usra";
3702 break;
3703 case NEON_SRSRA_scalar:
3704 mnemonic = "srsra";
3705 break;
3706 case NEON_URSRA_scalar:
3707 mnemonic = "ursra";
3708 break;
3709 case NEON_SHL_scalar:
3710 mnemonic = "shl";
3711 form = form_2;
3712 break;
3713 case NEON_SLI_scalar:
3714 mnemonic = "sli";
3715 form = form_2;
3716 break;
3717 case NEON_SQSHLU_scalar:
3718 mnemonic = "sqshlu";
3719 form = form_2;
3720 break;
3721 case NEON_SQSHL_imm_scalar:
3722 mnemonic = "sqshl";
3723 form = form_2;
3724 break;
3725 case NEON_UQSHL_imm_scalar:
3726 mnemonic = "uqshl";
3727 form = form_2;
3728 break;
3729 case NEON_UQSHRN_scalar:
3730 mnemonic = "uqshrn";
3731 nfd.SetFormatMap(1, &map_shift_narrow);
3732 break;
3733 case NEON_UQRSHRN_scalar:
3734 mnemonic = "uqrshrn";
3735 nfd.SetFormatMap(1, &map_shift_narrow);
3736 break;
3737 case NEON_SQSHRN_scalar:
3738 mnemonic = "sqshrn";
3739 nfd.SetFormatMap(1, &map_shift_narrow);
3740 break;
3741 case NEON_SQRSHRN_scalar:
3742 mnemonic = "sqrshrn";
3743 nfd.SetFormatMap(1, &map_shift_narrow);
3744 break;
3745 case NEON_SQSHRUN_scalar:
3746 mnemonic = "sqshrun";
3747 nfd.SetFormatMap(1, &map_shift_narrow);
3748 break;
3749 case NEON_SQRSHRUN_scalar:
3750 mnemonic = "sqrshrun";
3751 nfd.SetFormatMap(1, &map_shift_narrow);
3752 break;
3753 default:
3754 form = "(NEONScalarShiftImmediate)";
3755 }
3756 } else {
3757 form = "(NEONScalarShiftImmediate)";
3758 }
3759 Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));
3760 }
3761
3762
VisitNEONShiftImmediate(const Instruction * instr)3763 void Disassembler::VisitNEONShiftImmediate(const Instruction *instr) {
3764 const char *mnemonic = "unimplemented";
3765 const char *form = "'Vd.%s, 'Vn.%s, 'Is1";
3766 const char *form_shift_2 = "'Vd.%s, 'Vn.%s, 'Is2";
3767 const char *form_xtl = "'Vd.%s, 'Vn.%s";
3768
3769 // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
3770 static const NEONFormatMap map_shift_ta =
3771 {{22, 21, 20, 19},
3772 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}};
3773
3774 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
3775 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
3776 static const NEONFormatMap map_shift_tb =
3777 {{22, 21, 20, 19, 30},
3778 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H,
3779 NF_8H, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S,
3780 NF_2S, NF_4S, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF,
3781 NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
3782 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}};
3783
3784 NEONFormatDecoder nfd(instr, &map_shift_tb);
3785
3786 if (instr->GetImmNEONImmh()) { // immh has to be non-zero.
3787 switch (instr->Mask(NEONShiftImmediateMask)) {
3788 case NEON_SQSHLU:
3789 mnemonic = "sqshlu";
3790 form = form_shift_2;
3791 break;
3792 case NEON_SQSHL_imm:
3793 mnemonic = "sqshl";
3794 form = form_shift_2;
3795 break;
3796 case NEON_UQSHL_imm:
3797 mnemonic = "uqshl";
3798 form = form_shift_2;
3799 break;
3800 case NEON_SHL:
3801 mnemonic = "shl";
3802 form = form_shift_2;
3803 break;
3804 case NEON_SLI:
3805 mnemonic = "sli";
3806 form = form_shift_2;
3807 break;
3808 case NEON_SCVTF_imm:
3809 mnemonic = "scvtf";
3810 break;
3811 case NEON_UCVTF_imm:
3812 mnemonic = "ucvtf";
3813 break;
3814 case NEON_FCVTZU_imm:
3815 mnemonic = "fcvtzu";
3816 break;
3817 case NEON_FCVTZS_imm:
3818 mnemonic = "fcvtzs";
3819 break;
3820 case NEON_SRI:
3821 mnemonic = "sri";
3822 break;
3823 case NEON_SSHR:
3824 mnemonic = "sshr";
3825 break;
3826 case NEON_USHR:
3827 mnemonic = "ushr";
3828 break;
3829 case NEON_SRSHR:
3830 mnemonic = "srshr";
3831 break;
3832 case NEON_URSHR:
3833 mnemonic = "urshr";
3834 break;
3835 case NEON_SSRA:
3836 mnemonic = "ssra";
3837 break;
3838 case NEON_USRA:
3839 mnemonic = "usra";
3840 break;
3841 case NEON_SRSRA:
3842 mnemonic = "srsra";
3843 break;
3844 case NEON_URSRA:
3845 mnemonic = "ursra";
3846 break;
3847 case NEON_SHRN:
3848 mnemonic = instr->Mask(NEON_Q) ? "shrn2" : "shrn";
3849 nfd.SetFormatMap(1, &map_shift_ta);
3850 break;
3851 case NEON_RSHRN:
3852 mnemonic = instr->Mask(NEON_Q) ? "rshrn2" : "rshrn";
3853 nfd.SetFormatMap(1, &map_shift_ta);
3854 break;
3855 case NEON_UQSHRN:
3856 mnemonic = instr->Mask(NEON_Q) ? "uqshrn2" : "uqshrn";
3857 nfd.SetFormatMap(1, &map_shift_ta);
3858 break;
3859 case NEON_UQRSHRN:
3860 mnemonic = instr->Mask(NEON_Q) ? "uqrshrn2" : "uqrshrn";
3861 nfd.SetFormatMap(1, &map_shift_ta);
3862 break;
3863 case NEON_SQSHRN:
3864 mnemonic = instr->Mask(NEON_Q) ? "sqshrn2" : "sqshrn";
3865 nfd.SetFormatMap(1, &map_shift_ta);
3866 break;
3867 case NEON_SQRSHRN:
3868 mnemonic = instr->Mask(NEON_Q) ? "sqrshrn2" : "sqrshrn";
3869 nfd.SetFormatMap(1, &map_shift_ta);
3870 break;
3871 case NEON_SQSHRUN:
3872 mnemonic = instr->Mask(NEON_Q) ? "sqshrun2" : "sqshrun";
3873 nfd.SetFormatMap(1, &map_shift_ta);
3874 break;
3875 case NEON_SQRSHRUN:
3876 mnemonic = instr->Mask(NEON_Q) ? "sqrshrun2" : "sqrshrun";
3877 nfd.SetFormatMap(1, &map_shift_ta);
3878 break;
3879 case NEON_SSHLL:
3880 nfd.SetFormatMap(0, &map_shift_ta);
3881 if (instr->GetImmNEONImmb() == 0 &&
3882 CountSetBits(instr->GetImmNEONImmh(), 32) == 1) { // sxtl variant.
3883 form = form_xtl;
3884 mnemonic = instr->Mask(NEON_Q) ? "sxtl2" : "sxtl";
3885 } else { // sshll variant.
3886 form = form_shift_2;
3887 mnemonic = instr->Mask(NEON_Q) ? "sshll2" : "sshll";
3888 }
3889 break;
3890 case NEON_USHLL:
3891 nfd.SetFormatMap(0, &map_shift_ta);
3892 if (instr->GetImmNEONImmb() == 0 &&
3893 CountSetBits(instr->GetImmNEONImmh(), 32) == 1) { // uxtl variant.
3894 form = form_xtl;
3895 mnemonic = instr->Mask(NEON_Q) ? "uxtl2" : "uxtl";
3896 } else { // ushll variant.
3897 form = form_shift_2;
3898 mnemonic = instr->Mask(NEON_Q) ? "ushll2" : "ushll";
3899 }
3900 break;
3901 default:
3902 form = "(NEONShiftImmediate)";
3903 }
3904 } else {
3905 form = "(NEONShiftImmediate)";
3906 }
3907 Format(instr, mnemonic, nfd.Substitute(form));
3908 }
3909
3910
VisitNEONTable(const Instruction * instr)3911 void Disassembler::VisitNEONTable(const Instruction *instr) {
3912 const char *mnemonic = "unimplemented";
3913 const char *form = "(NEONTable)";
3914 const char form_1v[] = "'Vd.%%s, {'Vn.16b}, 'Vm.%%s";
3915 const char form_2v[] = "'Vd.%%s, {'Vn.16b, v%d.16b}, 'Vm.%%s";
3916 const char form_3v[] = "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b}, 'Vm.%%s";
3917 const char form_4v[] =
3918 "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b, v%d.16b}, 'Vm.%%s";
3919 static const NEONFormatMap map_b = {{30}, {NF_8B, NF_16B}};
3920 NEONFormatDecoder nfd(instr, &map_b);
3921
3922 switch (instr->Mask(NEONTableMask)) {
3923 case NEON_TBL_1v:
3924 mnemonic = "tbl";
3925 form = form_1v;
3926 break;
3927 case NEON_TBL_2v:
3928 mnemonic = "tbl";
3929 form = form_2v;
3930 break;
3931 case NEON_TBL_3v:
3932 mnemonic = "tbl";
3933 form = form_3v;
3934 break;
3935 case NEON_TBL_4v:
3936 mnemonic = "tbl";
3937 form = form_4v;
3938 break;
3939 case NEON_TBX_1v:
3940 mnemonic = "tbx";
3941 form = form_1v;
3942 break;
3943 case NEON_TBX_2v:
3944 mnemonic = "tbx";
3945 form = form_2v;
3946 break;
3947 case NEON_TBX_3v:
3948 mnemonic = "tbx";
3949 form = form_3v;
3950 break;
3951 case NEON_TBX_4v:
3952 mnemonic = "tbx";
3953 form = form_4v;
3954 break;
3955 default:
3956 break;
3957 }
3958
3959 char re_form[sizeof(form_4v) + 6];
3960 int reg_num = instr->GetRn();
3961 snprintf(re_form,
3962 sizeof(re_form),
3963 form,
3964 (reg_num + 1) % kNumberOfVRegisters,
3965 (reg_num + 2) % kNumberOfVRegisters,
3966 (reg_num + 3) % kNumberOfVRegisters);
3967
3968 Format(instr, mnemonic, nfd.Substitute(re_form));
3969 }
3970
3971
VisitNEONPerm(const Instruction * instr)3972 void Disassembler::VisitNEONPerm(const Instruction *instr) {
3973 const char *mnemonic = "unimplemented";
3974 const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";
3975 NEONFormatDecoder nfd(instr);
3976
3977 switch (instr->Mask(NEONPermMask)) {
3978 case NEON_TRN1:
3979 mnemonic = "trn1";
3980 break;
3981 case NEON_TRN2:
3982 mnemonic = "trn2";
3983 break;
3984 case NEON_UZP1:
3985 mnemonic = "uzp1";
3986 break;
3987 case NEON_UZP2:
3988 mnemonic = "uzp2";
3989 break;
3990 case NEON_ZIP1:
3991 mnemonic = "zip1";
3992 break;
3993 case NEON_ZIP2:
3994 mnemonic = "zip2";
3995 break;
3996 default:
3997 form = "(NEONPerm)";
3998 }
3999 Format(instr, mnemonic, nfd.Substitute(form));
4000 }
4001
4002
VisitUnimplemented(const Instruction * instr)4003 void Disassembler::VisitUnimplemented(const Instruction *instr) {
4004 Format(instr, "unimplemented", "(Unimplemented)");
4005 }
4006
4007
VisitUnallocated(const Instruction * instr)4008 void Disassembler::VisitUnallocated(const Instruction *instr) {
4009 Format(instr, "unallocated", "(Unallocated)");
4010 }
4011
4012
ProcessOutput(const Instruction *)4013 void Disassembler::ProcessOutput(const Instruction * /*instr*/) {
4014 // The base disasm does nothing more than disassembling into a buffer.
4015 }
4016
4017
AppendRegisterNameToOutput(const Instruction * instr,const CPURegister & reg)4018 void Disassembler::AppendRegisterNameToOutput(const Instruction *instr,
4019 const CPURegister ®) {
4020 USE(instr);
4021 VIXL_ASSERT(reg.IsValid());
4022 char reg_char;
4023
4024 if (reg.IsRegister()) {
4025 reg_char = reg.Is64Bits() ? 'x' : 'w';
4026 } else {
4027 VIXL_ASSERT(reg.IsVRegister());
4028 switch (reg.GetSizeInBits()) {
4029 case kBRegSize:
4030 reg_char = 'b';
4031 break;
4032 case kHRegSize:
4033 reg_char = 'h';
4034 break;
4035 case kSRegSize:
4036 reg_char = 's';
4037 break;
4038 case kDRegSize:
4039 reg_char = 'd';
4040 break;
4041 default:
4042 VIXL_ASSERT(reg.Is128Bits());
4043 reg_char = 'q';
4044 }
4045 }
4046
4047 if (reg.IsVRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) {
4048 // A core or scalar/vector register: [wx]0 - 30, [bhsdq]0 - 31.
4049 AppendToOutput("%c%d", reg_char, reg.GetCode());
4050 } else if (reg.Aliases(sp)) {
4051 // Disassemble w31/x31 as stack pointer wsp/sp.
4052 AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp");
4053 } else {
4054 // Disassemble w31/x31 as zero register wzr/xzr.
4055 AppendToOutput("%czr", reg_char);
4056 }
4057 }
4058
4059
AppendPCRelativeOffsetToOutput(const Instruction * instr,int64_t offset)4060 void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction *instr,
4061 int64_t offset) {
4062 USE(instr);
4063 if (offset < 0) {
4064 // Cast to uint64_t so that INT64_MIN is handled in a well-defined way.
4065 uint64_t abs_offset = -static_cast<uint64_t>(offset);
4066 AppendToOutput("#-0x%" PRIx64, abs_offset);
4067 } else {
4068 AppendToOutput("#+0x%" PRIx64, offset);
4069 }
4070 }
4071
4072
AppendAddressToOutput(const Instruction * instr,const void * addr)4073 void Disassembler::AppendAddressToOutput(const Instruction *instr,
4074 const void *addr) {
4075 USE(instr);
4076 AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast<uintptr_t>(addr));
4077 }
4078
4079
AppendCodeAddressToOutput(const Instruction * instr,const void * addr)4080 void Disassembler::AppendCodeAddressToOutput(const Instruction *instr,
4081 const void *addr) {
4082 AppendAddressToOutput(instr, addr);
4083 }
4084
4085
AppendDataAddressToOutput(const Instruction * instr,const void * addr)4086 void Disassembler::AppendDataAddressToOutput(const Instruction *instr,
4087 const void *addr) {
4088 AppendAddressToOutput(instr, addr);
4089 }
4090
4091
AppendCodeRelativeAddressToOutput(const Instruction * instr,const void * addr)4092 void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction *instr,
4093 const void *addr) {
4094 USE(instr);
4095 int64_t rel_addr = CodeRelativeAddress(addr);
4096 if (rel_addr >= 0) {
4097 AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr);
4098 } else {
4099 AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr);
4100 }
4101 }
4102
4103
AppendCodeRelativeCodeAddressToOutput(const Instruction * instr,const void * addr)4104 void Disassembler::AppendCodeRelativeCodeAddressToOutput(
4105 const Instruction *instr, const void *addr) {
4106 AppendCodeRelativeAddressToOutput(instr, addr);
4107 }
4108
4109
AppendCodeRelativeDataAddressToOutput(const Instruction * instr,const void * addr)4110 void Disassembler::AppendCodeRelativeDataAddressToOutput(
4111 const Instruction *instr, const void *addr) {
4112 AppendCodeRelativeAddressToOutput(instr, addr);
4113 }
4114
4115
MapCodeAddress(int64_t base_address,const Instruction * instr_address)4116 void Disassembler::MapCodeAddress(int64_t base_address,
4117 const Instruction *instr_address) {
4118 set_code_address_offset(base_address -
4119 reinterpret_cast<intptr_t>(instr_address));
4120 }
CodeRelativeAddress(const void * addr)4121 int64_t Disassembler::CodeRelativeAddress(const void *addr) {
4122 return reinterpret_cast<intptr_t>(addr) + code_address_offset();
4123 }
4124
4125
Format(const Instruction * instr,const char * mnemonic,const char * format)4126 void Disassembler::Format(const Instruction *instr,
4127 const char *mnemonic,
4128 const char *format) {
4129 VIXL_ASSERT(mnemonic != NULL);
4130 ResetOutput();
4131 Substitute(instr, mnemonic);
4132 if (format != NULL) {
4133 VIXL_ASSERT(buffer_pos_ < buffer_size_);
4134 buffer_[buffer_pos_++] = ' ';
4135 Substitute(instr, format);
4136 }
4137 VIXL_ASSERT(buffer_pos_ < buffer_size_);
4138 buffer_[buffer_pos_] = 0;
4139 ProcessOutput(instr);
4140 }
4141
4142
Substitute(const Instruction * instr,const char * string)4143 void Disassembler::Substitute(const Instruction *instr, const char *string) {
4144 char chr = *string++;
4145 while (chr != '\0') {
4146 if (chr == '\'') {
4147 string += SubstituteField(instr, string);
4148 } else {
4149 VIXL_ASSERT(buffer_pos_ < buffer_size_);
4150 buffer_[buffer_pos_++] = chr;
4151 }
4152 chr = *string++;
4153 }
4154 }
4155
4156
SubstituteField(const Instruction * instr,const char * format)4157 int Disassembler::SubstituteField(const Instruction *instr,
4158 const char *format) {
4159 switch (format[0]) {
4160 // NB. The remaining substitution prefix characters are: GJKUZ.
4161 case 'R': // Register. X or W, selected by sf bit.
4162 case 'F': // FP register. S or D, selected by type field.
4163 case 'V': // Vector register, V, vector format.
4164 case 'W':
4165 case 'X':
4166 case 'B':
4167 case 'H':
4168 case 'S':
4169 case 'D':
4170 case 'Q':
4171 return SubstituteRegisterField(instr, format);
4172 case 'I':
4173 return SubstituteImmediateField(instr, format);
4174 case 'L':
4175 return SubstituteLiteralField(instr, format);
4176 case 'N':
4177 return SubstituteShiftField(instr, format);
4178 case 'P':
4179 return SubstitutePrefetchField(instr, format);
4180 case 'C':
4181 return SubstituteConditionField(instr, format);
4182 case 'E':
4183 return SubstituteExtendField(instr, format);
4184 case 'A':
4185 return SubstitutePCRelAddressField(instr, format);
4186 case 'T':
4187 return SubstituteBranchTargetField(instr, format);
4188 case 'O':
4189 return SubstituteLSRegOffsetField(instr, format);
4190 case 'M':
4191 return SubstituteBarrierField(instr, format);
4192 case 'K':
4193 return SubstituteCrField(instr, format);
4194 case 'G':
4195 return SubstituteSysOpField(instr, format);
4196 default: {
4197 VIXL_UNREACHABLE();
4198 return 1;
4199 }
4200 }
4201 }
4202
4203
SubstituteRegisterField(const Instruction * instr,const char * format)4204 int Disassembler::SubstituteRegisterField(const Instruction *instr,
4205 const char *format) {
4206 char reg_prefix = format[0];
4207 unsigned reg_num = 0;
4208 unsigned field_len = 2;
4209
4210 switch (format[1]) {
4211 case 'd':
4212 reg_num = instr->GetRd();
4213 if (format[2] == 'q') {
4214 reg_prefix = instr->GetNEONQ() ? 'X' : 'W';
4215 field_len = 3;
4216 }
4217 break;
4218 case 'n':
4219 reg_num = instr->GetRn();
4220 break;
4221 case 'm':
4222 reg_num = instr->GetRm();
4223 switch (format[2]) {
4224 // Handle registers tagged with b (bytes), z (instruction), or
4225 // r (registers), used for address updates in
4226 // NEON load/store instructions.
4227 case 'r':
4228 case 'b':
4229 case 'z': {
4230 field_len = 3;
4231 char *eimm;
4232 int imm = static_cast<int>(strtol(&format[3], &eimm, 10));
4233 field_len += eimm - &format[3];
4234 if (reg_num == 31) {
4235 switch (format[2]) {
4236 case 'z':
4237 imm *= (1 << instr->GetNEONLSSize());
4238 break;
4239 case 'r':
4240 imm *= (instr->GetNEONQ() == 0) ? kDRegSizeInBytes
4241 : kQRegSizeInBytes;
4242 break;
4243 case 'b':
4244 break;
4245 }
4246 AppendToOutput("#%d", imm);
4247 return field_len;
4248 }
4249 break;
4250 }
4251 }
4252 break;
4253 case 'e':
4254 // This is register Rm, but using a 4-bit specifier. Used in NEON
4255 // by-element instructions.
4256 reg_num = (instr->GetRm() & 0xf);
4257 break;
4258 case 'a':
4259 reg_num = instr->GetRa();
4260 break;
4261 case 's':
4262 reg_num = instr->GetRs();
4263 break;
4264 case 't':
4265 reg_num = instr->GetRt();
4266 if (format[0] == 'V') {
4267 if ((format[2] >= '2') && (format[2] <= '4')) {
4268 // Handle consecutive vector register specifiers Vt2, Vt3 and Vt4.
4269 reg_num = (reg_num + format[2] - '1') % 32;
4270 field_len = 3;
4271 }
4272 } else {
4273 if (format[2] == '2') {
4274 // Handle register specifier Rt2.
4275 reg_num = instr->GetRt2();
4276 field_len = 3;
4277 }
4278 }
4279 break;
4280 default:
4281 VIXL_UNREACHABLE();
4282 }
4283
4284 // Increase field length for registers tagged as stack.
4285 if (format[2] == 's') {
4286 field_len = 3;
4287 }
4288
4289 CPURegister::RegisterType reg_type = CPURegister::kRegister;
4290 unsigned reg_size = kXRegSize;
4291
4292 if (reg_prefix == 'R') {
4293 reg_prefix = instr->GetSixtyFourBits() ? 'X' : 'W';
4294 } else if (reg_prefix == 'F') {
4295 reg_prefix = ((instr->GetFPType() & 1) == 0) ? 'S' : 'D';
4296 }
4297
4298 switch (reg_prefix) {
4299 case 'W':
4300 reg_type = CPURegister::kRegister;
4301 reg_size = kWRegSize;
4302 break;
4303 case 'X':
4304 reg_type = CPURegister::kRegister;
4305 reg_size = kXRegSize;
4306 break;
4307 case 'B':
4308 reg_type = CPURegister::kVRegister;
4309 reg_size = kBRegSize;
4310 break;
4311 case 'H':
4312 reg_type = CPURegister::kVRegister;
4313 reg_size = kHRegSize;
4314 break;
4315 case 'S':
4316 reg_type = CPURegister::kVRegister;
4317 reg_size = kSRegSize;
4318 break;
4319 case 'D':
4320 reg_type = CPURegister::kVRegister;
4321 reg_size = kDRegSize;
4322 break;
4323 case 'Q':
4324 reg_type = CPURegister::kVRegister;
4325 reg_size = kQRegSize;
4326 break;
4327 case 'V':
4328 AppendToOutput("v%d", reg_num);
4329 return field_len;
4330 default:
4331 VIXL_UNREACHABLE();
4332 }
4333
4334 if ((reg_type == CPURegister::kRegister) && (reg_num == kZeroRegCode) &&
4335 (format[2] == 's')) {
4336 reg_num = kSPRegInternalCode;
4337 }
4338
4339 AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type));
4340
4341 return field_len;
4342 }
4343
4344
SubstituteImmediateField(const Instruction * instr,const char * format)4345 int Disassembler::SubstituteImmediateField(const Instruction *instr,
4346 const char *format) {
4347 VIXL_ASSERT(format[0] == 'I');
4348
4349 switch (format[1]) {
4350 case 'M': { // IMoveImm, IMoveNeg or IMoveLSL.
4351 if (format[5] == 'L') {
4352 AppendToOutput("#0x%" PRIx32, instr->GetImmMoveWide());
4353 if (instr->GetShiftMoveWide() > 0) {
4354 AppendToOutput(", lsl #%" PRId32, 16 * instr->GetShiftMoveWide());
4355 }
4356 } else {
4357 VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N'));
4358 uint64_t imm = static_cast<uint64_t>(instr->GetImmMoveWide())
4359 << (16 * instr->GetShiftMoveWide());
4360 if (format[5] == 'N') imm = ~imm;
4361 if (!instr->GetSixtyFourBits()) imm &= UINT64_C(0xffffffff);
4362 AppendToOutput("#0x%" PRIx64, imm);
4363 }
4364 return 8;
4365 }
4366 case 'L': {
4367 switch (format[2]) {
4368 case 'L': { // ILLiteral - Immediate Load Literal.
4369 AppendToOutput("pc%+" PRId32,
4370 instr->GetImmLLiteral() *
4371 static_cast<int>(kLiteralEntrySize));
4372 return 9;
4373 }
4374 case 'S': { // ILS - Immediate Load/Store.
4375 if (instr->GetImmLS() != 0) {
4376 AppendToOutput(", #%" PRId32, instr->GetImmLS());
4377 }
4378 return 3;
4379 }
4380 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
4381 if (instr->GetImmLSPair() != 0) {
4382 // format[3] is the scale value. Convert to a number.
4383 int scale = 1 << (format[3] - '0');
4384 AppendToOutput(", #%" PRId32, instr->GetImmLSPair() * scale);
4385 }
4386 return 4;
4387 }
4388 case 'U': { // ILU - Immediate Load/Store Unsigned.
4389 if (instr->GetImmLSUnsigned() != 0) {
4390 int shift = instr->GetSizeLS();
4391 AppendToOutput(", #%" PRId32, instr->GetImmLSUnsigned() << shift);
4392 }
4393 return 3;
4394 }
4395 }
4396 }
4397 case 'C': { // ICondB - Immediate Conditional Branch.
4398 int64_t offset = instr->GetImmCondBranch() << 2;
4399 AppendPCRelativeOffsetToOutput(instr, offset);
4400 return 6;
4401 }
4402 case 'A': { // IAddSub.
4403 VIXL_ASSERT(instr->GetShiftAddSub() <= 1);
4404 int64_t imm = instr->GetImmAddSub() << (12 * instr->GetShiftAddSub());
4405 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
4406 return 7;
4407 }
4408 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
4409 if (format[3] == 'F') { // IFPFbits.
4410 AppendToOutput("#%" PRId32, 64 - instr->GetFPScale());
4411 return 8;
4412 } else {
4413 AppendToOutput("#0x%" PRIx32 " (%.4f)",
4414 instr->GetImmFP(),
4415 format[3] == 'S' ? instr->GetImmFP32()
4416 : instr->GetImmFP64());
4417 return 9;
4418 }
4419 }
4420 case 'T': { // ITri - Immediate Triangular Encoded.
4421 AppendToOutput("#0x%" PRIx64, instr->GetImmLogical());
4422 return 4;
4423 }
4424 case 'N': { // INzcv.
4425 int nzcv = (instr->GetNzcv() << Flags_offset);
4426 AppendToOutput("#%c%c%c%c",
4427 ((nzcv & NFlag) == 0) ? 'n' : 'N',
4428 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
4429 ((nzcv & CFlag) == 0) ? 'c' : 'C',
4430 ((nzcv & VFlag) == 0) ? 'v' : 'V');
4431 return 5;
4432 }
4433 case 'P': { // IP - Conditional compare.
4434 AppendToOutput("#%" PRId32, instr->GetImmCondCmp());
4435 return 2;
4436 }
4437 case 'B': { // Bitfields.
4438 return SubstituteBitfieldImmediateField(instr, format);
4439 }
4440 case 'E': { // IExtract.
4441 AppendToOutput("#%" PRId32, instr->GetImmS());
4442 return 8;
4443 }
4444 case 'S': { // IS - Test and branch bit.
4445 AppendToOutput("#%" PRId32,
4446 (instr->GetImmTestBranchBit5() << 5) |
4447 instr->GetImmTestBranchBit40());
4448 return 2;
4449 }
4450 case 's': { // Is - Shift (immediate).
4451 switch (format[2]) {
4452 case '1': { // Is1 - SSHR.
4453 int shift = 16 << HighestSetBitPosition(instr->GetImmNEONImmh());
4454 shift -= instr->GetImmNEONImmhImmb();
4455 AppendToOutput("#%d", shift);
4456 return 3;
4457 }
4458 case '2': { // Is2 - SLI.
4459 int shift = instr->GetImmNEONImmhImmb();
4460 shift -= 8 << HighestSetBitPosition(instr->GetImmNEONImmh());
4461 AppendToOutput("#%d", shift);
4462 return 3;
4463 }
4464 default: {
4465 VIXL_UNIMPLEMENTED();
4466 return 0;
4467 }
4468 }
4469 }
4470 case 'D': { // IDebug - HLT and BRK instructions.
4471 AppendToOutput("#0x%" PRIx32, instr->GetImmException());
4472 return 6;
4473 }
4474 case 'V': { // Immediate Vector.
4475 switch (format[2]) {
4476 case 'E': { // IVExtract.
4477 AppendToOutput("#%" PRId32, instr->GetImmNEONExt());
4478 return 9;
4479 }
4480 case 'B': { // IVByElemIndex.
4481 int vm_index = (instr->GetNEONH() << 1) | instr->GetNEONL();
4482 if (instr->GetNEONSize() == 1) {
4483 vm_index = (vm_index << 1) | instr->GetNEONM();
4484 }
4485 AppendToOutput("%d", vm_index);
4486 return strlen("IVByElemIndex");
4487 }
4488 case 'I': { // INS element.
4489 if (strncmp(format, "IVInsIndex", strlen("IVInsIndex")) == 0) {
4490 unsigned rd_index, rn_index;
4491 unsigned imm5 = instr->GetImmNEON5();
4492 unsigned imm4 = instr->GetImmNEON4();
4493 int tz = CountTrailingZeros(imm5, 32);
4494 if (tz <= 3) { // Defined for tz = 0 to 3 only.
4495 rd_index = imm5 >> (tz + 1);
4496 rn_index = imm4 >> tz;
4497 if (strncmp(format, "IVInsIndex1", strlen("IVInsIndex1")) == 0) {
4498 AppendToOutput("%d", rd_index);
4499 return strlen("IVInsIndex1");
4500 } else if (strncmp(format,
4501 "IVInsIndex2",
4502 strlen("IVInsIndex2")) == 0) {
4503 AppendToOutput("%d", rn_index);
4504 return strlen("IVInsIndex2");
4505 }
4506 }
4507 return 0;
4508 }
4509 VIXL_FALLTHROUGH();
4510 }
4511 case 'L': { // IVLSLane[0123] - suffix indicates access size shift.
4512 AppendToOutput("%d", instr->GetNEONLSIndex(format[8] - '0'));
4513 return 9;
4514 }
4515 case 'M': { // Modified Immediate cases.
4516 if (strncmp(format, "IVMIImmFPSingle", strlen("IVMIImmFPSingle")) ==
4517 0) {
4518 AppendToOutput("#0x%" PRIx32 " (%.4f)",
4519 instr->GetImmNEONabcdefgh(),
4520 instr->GetImmNEONFP32());
4521 return strlen("IVMIImmFPSingle");
4522 } else if (strncmp(format,
4523 "IVMIImmFPDouble",
4524 strlen("IVMIImmFPDouble")) == 0) {
4525 AppendToOutput("#0x%" PRIx32 " (%.4f)",
4526 instr->GetImmNEONabcdefgh(),
4527 instr->GetImmNEONFP64());
4528 return strlen("IVMIImmFPDouble");
4529 } else if (strncmp(format, "IVMIImm8", strlen("IVMIImm8")) == 0) {
4530 uint64_t imm8 = instr->GetImmNEONabcdefgh();
4531 AppendToOutput("#0x%" PRIx64, imm8);
4532 return strlen("IVMIImm8");
4533 } else if (strncmp(format, "IVMIImm", strlen("IVMIImm")) == 0) {
4534 uint64_t imm8 = instr->GetImmNEONabcdefgh();
4535 uint64_t imm = 0;
4536 for (int i = 0; i < 8; ++i) {
4537 if (imm8 & (1 << i)) {
4538 imm |= (UINT64_C(0xff) << (8 * i));
4539 }
4540 }
4541 AppendToOutput("#0x%" PRIx64, imm);
4542 return strlen("IVMIImm");
4543 } else if (strncmp(format,
4544 "IVMIShiftAmt1",
4545 strlen("IVMIShiftAmt1")) == 0) {
4546 int cmode = instr->GetNEONCmode();
4547 int shift_amount = 8 * ((cmode >> 1) & 3);
4548 AppendToOutput("#%d", shift_amount);
4549 return strlen("IVMIShiftAmt1");
4550 } else if (strncmp(format,
4551 "IVMIShiftAmt2",
4552 strlen("IVMIShiftAmt2")) == 0) {
4553 int cmode = instr->GetNEONCmode();
4554 int shift_amount = 8 << (cmode & 1);
4555 AppendToOutput("#%d", shift_amount);
4556 return strlen("IVMIShiftAmt2");
4557 } else {
4558 VIXL_UNIMPLEMENTED();
4559 return 0;
4560 }
4561 }
4562 default: {
4563 VIXL_UNIMPLEMENTED();
4564 return 0;
4565 }
4566 }
4567 }
4568 case 'X': { // IX - CLREX instruction.
4569 AppendToOutput("#0x%" PRIx32, instr->GetCRm());
4570 return 2;
4571 }
4572 case 'Y': { // IY - system register immediate.
4573 switch (instr->GetImmSystemRegister()) {
4574 case NZCV:
4575 AppendToOutput("nzcv");
4576 break;
4577 case FPCR:
4578 AppendToOutput("fpcr");
4579 break;
4580 default:
4581 AppendToOutput("S%d_%d_c%d_c%d_%d",
4582 instr->GetSysOp0(),
4583 instr->GetSysOp1(),
4584 instr->GetCRn(),
4585 instr->GetCRm(),
4586 instr->GetSysOp2());
4587 break;
4588 }
4589 return 2;
4590 }
4591 default: {
4592 VIXL_UNIMPLEMENTED();
4593 return 0;
4594 }
4595 }
4596 }
4597
4598
SubstituteBitfieldImmediateField(const Instruction * instr,const char * format)4599 int Disassembler::SubstituteBitfieldImmediateField(const Instruction *instr,
4600 const char *format) {
4601 VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
4602 unsigned r = instr->GetImmR();
4603 unsigned s = instr->GetImmS();
4604
4605 switch (format[2]) {
4606 case 'r': { // IBr.
4607 AppendToOutput("#%d", r);
4608 return 3;
4609 }
4610 case 's': { // IBs+1 or IBs-r+1.
4611 if (format[3] == '+') {
4612 AppendToOutput("#%d", s + 1);
4613 return 5;
4614 } else {
4615 VIXL_ASSERT(format[3] == '-');
4616 AppendToOutput("#%d", s - r + 1);
4617 return 7;
4618 }
4619 }
4620 case 'Z': { // IBZ-r.
4621 VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));
4622 unsigned reg_size =
4623 (instr->GetSixtyFourBits() == 1) ? kXRegSize : kWRegSize;
4624 AppendToOutput("#%d", reg_size - r);
4625 return 5;
4626 }
4627 default: {
4628 VIXL_UNREACHABLE();
4629 return 0;
4630 }
4631 }
4632 }
4633
4634
SubstituteLiteralField(const Instruction * instr,const char * format)4635 int Disassembler::SubstituteLiteralField(const Instruction *instr,
4636 const char *format) {
4637 VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
4638 USE(format);
4639
4640 const void *address = instr->GetLiteralAddress<const void *>();
4641 switch (instr->Mask(LoadLiteralMask)) {
4642 case LDR_w_lit:
4643 case LDR_x_lit:
4644 case LDRSW_x_lit:
4645 case LDR_s_lit:
4646 case LDR_d_lit:
4647 case LDR_q_lit:
4648 AppendCodeRelativeDataAddressToOutput(instr, address);
4649 break;
4650 case PRFM_lit: {
4651 // Use the prefetch hint to decide how to print the address.
4652 switch (instr->GetPrefetchHint()) {
4653 case 0x0: // PLD: prefetch for load.
4654 case 0x2: // PST: prepare for store.
4655 AppendCodeRelativeDataAddressToOutput(instr, address);
4656 break;
4657 case 0x1: // PLI: preload instructions.
4658 AppendCodeRelativeCodeAddressToOutput(instr, address);
4659 break;
4660 case 0x3: // Unallocated hint.
4661 AppendCodeRelativeAddressToOutput(instr, address);
4662 break;
4663 }
4664 break;
4665 }
4666 default:
4667 VIXL_UNREACHABLE();
4668 }
4669
4670 return 6;
4671 }
4672
4673
SubstituteShiftField(const Instruction * instr,const char * format)4674 int Disassembler::SubstituteShiftField(const Instruction *instr,
4675 const char *format) {
4676 VIXL_ASSERT(format[0] == 'N');
4677 VIXL_ASSERT(instr->GetShiftDP() <= 0x3);
4678
4679 switch (format[1]) {
4680 case 'D': { // HDP.
4681 VIXL_ASSERT(instr->GetShiftDP() != ROR);
4682 VIXL_FALLTHROUGH();
4683 }
4684 case 'L': { // HLo.
4685 if (instr->GetImmDPShift() != 0) {
4686 const char *shift_type[] = {"lsl", "lsr", "asr", "ror"};
4687 AppendToOutput(", %s #%" PRId32,
4688 shift_type[instr->GetShiftDP()],
4689 instr->GetImmDPShift());
4690 }
4691 return 3;
4692 }
4693 default:
4694 VIXL_UNIMPLEMENTED();
4695 return 0;
4696 }
4697 }
4698
4699
SubstituteConditionField(const Instruction * instr,const char * format)4700 int Disassembler::SubstituteConditionField(const Instruction *instr,
4701 const char *format) {
4702 VIXL_ASSERT(format[0] == 'C');
4703 const char *condition_code[] = {"eq",
4704 "ne",
4705 "hs",
4706 "lo",
4707 "mi",
4708 "pl",
4709 "vs",
4710 "vc",
4711 "hi",
4712 "ls",
4713 "ge",
4714 "lt",
4715 "gt",
4716 "le",
4717 "al",
4718 "nv"};
4719 int cond;
4720 switch (format[1]) {
4721 case 'B':
4722 cond = instr->GetConditionBranch();
4723 break;
4724 case 'I': {
4725 cond = InvertCondition(static_cast<Condition>(instr->GetCondition()));
4726 break;
4727 }
4728 default:
4729 cond = instr->GetCondition();
4730 }
4731 AppendToOutput("%s", condition_code[cond]);
4732 return 4;
4733 }
4734
4735
SubstitutePCRelAddressField(const Instruction * instr,const char * format)4736 int Disassembler::SubstitutePCRelAddressField(const Instruction *instr,
4737 const char *format) {
4738 VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`.
4739 (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.
4740
4741 int64_t offset = instr->GetImmPCRel();
4742
4743 // Compute the target address based on the effective address (after applying
4744 // code_address_offset). This is required for correct behaviour of adrp.
4745 const Instruction *base = instr + code_address_offset();
4746 if (format[9] == 'P') {
4747 offset *= kPageSize;
4748 base = AlignDown(base, kPageSize);
4749 }
4750 // Strip code_address_offset before printing, so we can use the
4751 // semantically-correct AppendCodeRelativeAddressToOutput.
4752 const void *target =
4753 reinterpret_cast<const void *>(base + offset - code_address_offset());
4754
4755 AppendPCRelativeOffsetToOutput(instr, offset);
4756 AppendToOutput(" ");
4757 AppendCodeRelativeAddressToOutput(instr, target);
4758 return 13;
4759 }
4760
4761
SubstituteBranchTargetField(const Instruction * instr,const char * format)4762 int Disassembler::SubstituteBranchTargetField(const Instruction *instr,
4763 const char *format) {
4764 VIXL_ASSERT(strncmp(format, "TImm", 4) == 0);
4765
4766 int64_t offset = 0;
4767 switch (format[5]) {
4768 // BImmUncn - unconditional branch immediate.
4769 case 'n':
4770 offset = instr->GetImmUncondBranch();
4771 break;
4772 // BImmCond - conditional branch immediate.
4773 case 'o':
4774 offset = instr->GetImmCondBranch();
4775 break;
4776 // BImmCmpa - compare and branch immediate.
4777 case 'm':
4778 offset = instr->GetImmCmpBranch();
4779 break;
4780 // BImmTest - test and branch immediate.
4781 case 'e':
4782 offset = instr->GetImmTestBranch();
4783 break;
4784 default:
4785 VIXL_UNIMPLEMENTED();
4786 }
4787 offset *= static_cast<int>(kInstructionSize);
4788 const void *target_address = reinterpret_cast<const void *>(instr + offset);
4789 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
4790
4791 AppendPCRelativeOffsetToOutput(instr, offset);
4792 AppendToOutput(" ");
4793 AppendCodeRelativeCodeAddressToOutput(instr, target_address);
4794
4795 return 8;
4796 }
4797
4798
SubstituteExtendField(const Instruction * instr,const char * format)4799 int Disassembler::SubstituteExtendField(const Instruction *instr,
4800 const char *format) {
4801 VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
4802 VIXL_ASSERT(instr->GetExtendMode() <= 7);
4803 USE(format);
4804
4805 const char *extend_mode[] =
4806 {"uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx"};
4807
4808 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
4809 // registers becomes lsl.
4810 if (((instr->GetRd() == kZeroRegCode) || (instr->GetRn() == kZeroRegCode)) &&
4811 (((instr->GetExtendMode() == UXTW) && (instr->GetSixtyFourBits() == 0)) ||
4812 (instr->GetExtendMode() == UXTX))) {
4813 if (instr->GetImmExtendShift() > 0) {
4814 AppendToOutput(", lsl #%" PRId32, instr->GetImmExtendShift());
4815 }
4816 } else {
4817 AppendToOutput(", %s", extend_mode[instr->GetExtendMode()]);
4818 if (instr->GetImmExtendShift() > 0) {
4819 AppendToOutput(" #%" PRId32, instr->GetImmExtendShift());
4820 }
4821 }
4822 return 3;
4823 }
4824
4825
SubstituteLSRegOffsetField(const Instruction * instr,const char * format)4826 int Disassembler::SubstituteLSRegOffsetField(const Instruction *instr,
4827 const char *format) {
4828 VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
4829 const char *extend_mode[] = {"undefined",
4830 "undefined",
4831 "uxtw",
4832 "lsl",
4833 "undefined",
4834 "undefined",
4835 "sxtw",
4836 "sxtx"};
4837 USE(format);
4838
4839 unsigned shift = instr->GetImmShiftLS();
4840 Extend ext = static_cast<Extend>(instr->GetExtendMode());
4841 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
4842
4843 unsigned rm = instr->GetRm();
4844 if (rm == kZeroRegCode) {
4845 AppendToOutput("%czr", reg_type);
4846 } else {
4847 AppendToOutput("%c%d", reg_type, rm);
4848 }
4849
4850 // Extend mode UXTX is an alias for shift mode LSL here.
4851 if (!((ext == UXTX) && (shift == 0))) {
4852 AppendToOutput(", %s", extend_mode[ext]);
4853 if (shift != 0) {
4854 AppendToOutput(" #%d", instr->GetSizeLS());
4855 }
4856 }
4857 return 9;
4858 }
4859
4860
SubstitutePrefetchField(const Instruction * instr,const char * format)4861 int Disassembler::SubstitutePrefetchField(const Instruction *instr,
4862 const char *format) {
4863 VIXL_ASSERT(format[0] == 'P');
4864 USE(format);
4865
4866 static const char *hints[] = {"ld", "li", "st"};
4867 static const char *stream_options[] = {"keep", "strm"};
4868
4869 unsigned hint = instr->GetPrefetchHint();
4870 unsigned target = instr->GetPrefetchTarget() + 1;
4871 unsigned stream = instr->GetPrefetchStream();
4872
4873 if ((hint >= (sizeof(hints) / sizeof(hints[0]))) || (target > 3)) {
4874 // Unallocated prefetch operations.
4875 int prefetch_mode = instr->GetImmPrefetchOperation();
4876 AppendToOutput("#0b%c%c%c%c%c",
4877 (prefetch_mode & (1 << 4)) ? '1' : '0',
4878 (prefetch_mode & (1 << 3)) ? '1' : '0',
4879 (prefetch_mode & (1 << 2)) ? '1' : '0',
4880 (prefetch_mode & (1 << 1)) ? '1' : '0',
4881 (prefetch_mode & (1 << 0)) ? '1' : '0');
4882 } else {
4883 VIXL_ASSERT(stream < (sizeof(stream_options) / sizeof(stream_options[0])));
4884 AppendToOutput("p%sl%d%s", hints[hint], target, stream_options[stream]);
4885 }
4886 return 6;
4887 }
4888
SubstituteBarrierField(const Instruction * instr,const char * format)4889 int Disassembler::SubstituteBarrierField(const Instruction *instr,
4890 const char *format) {
4891 VIXL_ASSERT(format[0] == 'M');
4892 USE(format);
4893
4894 static const char *options[4][4] = {{"sy (0b0000)", "oshld", "oshst", "osh"},
4895 {"sy (0b0100)", "nshld", "nshst", "nsh"},
4896 {"sy (0b1000)", "ishld", "ishst", "ish"},
4897 {"sy (0b1100)", "ld", "st", "sy"}};
4898 int domain = instr->GetImmBarrierDomain();
4899 int type = instr->GetImmBarrierType();
4900
4901 AppendToOutput("%s", options[domain][type]);
4902 return 1;
4903 }
4904
SubstituteSysOpField(const Instruction * instr,const char * format)4905 int Disassembler::SubstituteSysOpField(const Instruction *instr,
4906 const char *format) {
4907 VIXL_ASSERT(format[0] == 'G');
4908 int op = -1;
4909 switch (format[1]) {
4910 case '1':
4911 op = instr->GetSysOp1();
4912 break;
4913 case '2':
4914 op = instr->GetSysOp2();
4915 break;
4916 default:
4917 VIXL_UNREACHABLE();
4918 }
4919 AppendToOutput("#%d", op);
4920 return 2;
4921 }
4922
SubstituteCrField(const Instruction * instr,const char * format)4923 int Disassembler::SubstituteCrField(const Instruction *instr,
4924 const char *format) {
4925 VIXL_ASSERT(format[0] == 'K');
4926 int cr = -1;
4927 switch (format[1]) {
4928 case 'n':
4929 cr = instr->GetCRn();
4930 break;
4931 case 'm':
4932 cr = instr->GetCRm();
4933 break;
4934 default:
4935 VIXL_UNREACHABLE();
4936 }
4937 AppendToOutput("C%d", cr);
4938 return 2;
4939 }
4940
ResetOutput()4941 void Disassembler::ResetOutput() {
4942 buffer_pos_ = 0;
4943 buffer_[buffer_pos_] = 0;
4944 }
4945
4946
AppendToOutput(const char * format,...)4947 void Disassembler::AppendToOutput(const char *format, ...) {
4948 va_list args;
4949 va_start(args, format);
4950 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_],
4951 buffer_size_ - buffer_pos_,
4952 format,
4953 args);
4954 va_end(args);
4955 }
4956
4957
DisassembleBuffer(const Instruction * start,uint64_t size)4958 void PrintDisassembler::DisassembleBuffer(const Instruction *start,
4959 uint64_t size) {
4960 Decoder decoder;
4961 decoder.AppendVisitor(this);
4962 const Instruction *instr_end = start + size;
4963 for (const Instruction *instr = start; instr < instr_end;
4964 instr += kInstructionSize) {
4965 decoder.Decode(instr);
4966 }
4967 }
4968
4969
ProcessOutput(const Instruction * instr)4970 void PrintDisassembler::ProcessOutput(const Instruction *instr) {
4971 fprintf(stream_,
4972 "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
4973 reinterpret_cast<uint64_t>(instr),
4974 instr->GetInstructionBits(),
4975 GetOutput());
4976 }
4977
4978 } // namespace aarch64
4979 } // namespace vixl
4980