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