migration/rdma: Plug memory leaks in qemu_rdma_registration_stop()
[qemu/armbru.git] / disas / libvixl / vixl / a64 / disasm-a64.cc
blob7a58a5c08766dddafcc5e599b28e2a970f9774ef
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 uint64_t abs_offset = offset;
2692 char sign = (offset < 0) ? '-' : '+';
2693 if (offset < 0) {
2694 abs_offset = -abs_offset;
2696 AppendToOutput("#%c0x%" PRIx64, sign, abs_offset);
2700 void Disassembler::AppendAddressToOutput(const Instruction* instr,
2701 const void* addr) {
2702 USE(instr);
2703 AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast<uintptr_t>(addr));
2707 void Disassembler::AppendCodeAddressToOutput(const Instruction* instr,
2708 const void* addr) {
2709 AppendAddressToOutput(instr, addr);
2713 void Disassembler::AppendDataAddressToOutput(const Instruction* instr,
2714 const void* addr) {
2715 AppendAddressToOutput(instr, addr);
2719 void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction* instr,
2720 const void* addr) {
2721 USE(instr);
2722 int64_t rel_addr = CodeRelativeAddress(addr);
2723 if (rel_addr >= 0) {
2724 AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr);
2725 } else {
2726 AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr);
2731 void Disassembler::AppendCodeRelativeCodeAddressToOutput(
2732 const Instruction* instr, const void* addr) {
2733 AppendCodeRelativeAddressToOutput(instr, addr);
2737 void Disassembler::AppendCodeRelativeDataAddressToOutput(
2738 const Instruction* instr, const void* addr) {
2739 AppendCodeRelativeAddressToOutput(instr, addr);
2743 void Disassembler::MapCodeAddress(int64_t base_address,
2744 const Instruction* instr_address) {
2745 set_code_address_offset(
2746 base_address - reinterpret_cast<intptr_t>(instr_address));
2748 int64_t Disassembler::CodeRelativeAddress(const void* addr) {
2749 return reinterpret_cast<intptr_t>(addr) + code_address_offset();
2753 void Disassembler::Format(const Instruction* instr, const char* mnemonic,
2754 const char* format) {
2755 VIXL_ASSERT(mnemonic != NULL);
2756 ResetOutput();
2757 Substitute(instr, mnemonic);
2758 if (format != NULL) {
2759 VIXL_ASSERT(buffer_pos_ < buffer_size_);
2760 buffer_[buffer_pos_++] = ' ';
2761 Substitute(instr, format);
2763 VIXL_ASSERT(buffer_pos_ < buffer_size_);
2764 buffer_[buffer_pos_] = 0;
2765 ProcessOutput(instr);
2769 void Disassembler::Substitute(const Instruction* instr, const char* string) {
2770 char chr = *string++;
2771 while (chr != '\0') {
2772 if (chr == '\'') {
2773 string += SubstituteField(instr, string);
2774 } else {
2775 VIXL_ASSERT(buffer_pos_ < buffer_size_);
2776 buffer_[buffer_pos_++] = chr;
2778 chr = *string++;
2783 int Disassembler::SubstituteField(const Instruction* instr,
2784 const char* format) {
2785 switch (format[0]) {
2786 // NB. The remaining substitution prefix characters are: GJKUZ.
2787 case 'R': // Register. X or W, selected by sf bit.
2788 case 'F': // FP register. S or D, selected by type field.
2789 case 'V': // Vector register, V, vector format.
2790 case 'W':
2791 case 'X':
2792 case 'B':
2793 case 'H':
2794 case 'S':
2795 case 'D':
2796 case 'Q': return SubstituteRegisterField(instr, format);
2797 case 'I': return SubstituteImmediateField(instr, format);
2798 case 'L': return SubstituteLiteralField(instr, format);
2799 case 'N': return SubstituteShiftField(instr, format);
2800 case 'P': return SubstitutePrefetchField(instr, format);
2801 case 'C': return SubstituteConditionField(instr, format);
2802 case 'E': return SubstituteExtendField(instr, format);
2803 case 'A': return SubstitutePCRelAddressField(instr, format);
2804 case 'T': return SubstituteBranchTargetField(instr, format);
2805 case 'O': return SubstituteLSRegOffsetField(instr, format);
2806 case 'M': return SubstituteBarrierField(instr, format);
2807 case 'K': return SubstituteCrField(instr, format);
2808 case 'G': return SubstituteSysOpField(instr, format);
2809 default: {
2810 VIXL_UNREACHABLE();
2811 return 1;
2817 int Disassembler::SubstituteRegisterField(const Instruction* instr,
2818 const char* format) {
2819 char reg_prefix = format[0];
2820 unsigned reg_num = 0;
2821 unsigned field_len = 2;
2823 switch (format[1]) {
2824 case 'd':
2825 reg_num = instr->Rd();
2826 if (format[2] == 'q') {
2827 reg_prefix = instr->NEONQ() ? 'X' : 'W';
2828 field_len = 3;
2830 break;
2831 case 'n': reg_num = instr->Rn(); break;
2832 case 'm':
2833 reg_num = instr->Rm();
2834 switch (format[2]) {
2835 // Handle registers tagged with b (bytes), z (instruction), or
2836 // r (registers), used for address updates in
2837 // NEON load/store instructions.
2838 case 'r':
2839 case 'b':
2840 case 'z': {
2841 field_len = 3;
2842 char* eimm;
2843 int imm = static_cast<int>(strtol(&format[3], &eimm, 10));
2844 field_len += eimm - &format[3];
2845 if (reg_num == 31) {
2846 switch (format[2]) {
2847 case 'z':
2848 imm *= (1 << instr->NEONLSSize());
2849 break;
2850 case 'r':
2851 imm *= (instr->NEONQ() == 0) ? kDRegSizeInBytes
2852 : kQRegSizeInBytes;
2853 break;
2854 case 'b':
2855 break;
2857 AppendToOutput("#%d", imm);
2858 return field_len;
2860 break;
2863 break;
2864 case 'e':
2865 // This is register Rm, but using a 4-bit specifier. Used in NEON
2866 // by-element instructions.
2867 reg_num = (instr->Rm() & 0xf);
2868 break;
2869 case 'a': reg_num = instr->Ra(); break;
2870 case 's': reg_num = instr->Rs(); break;
2871 case 't':
2872 reg_num = instr->Rt();
2873 if (format[0] == 'V') {
2874 if ((format[2] >= '2') && (format[2] <= '4')) {
2875 // Handle consecutive vector register specifiers Vt2, Vt3 and Vt4.
2876 reg_num = (reg_num + format[2] - '1') % 32;
2877 field_len = 3;
2879 } else {
2880 if (format[2] == '2') {
2881 // Handle register specifier Rt2.
2882 reg_num = instr->Rt2();
2883 field_len = 3;
2886 break;
2887 default: VIXL_UNREACHABLE();
2890 // Increase field length for registers tagged as stack.
2891 if (format[2] == 's') {
2892 field_len = 3;
2895 CPURegister::RegisterType reg_type = CPURegister::kRegister;
2896 unsigned reg_size = kXRegSize;
2898 if (reg_prefix == 'R') {
2899 reg_prefix = instr->SixtyFourBits() ? 'X' : 'W';
2900 } else if (reg_prefix == 'F') {
2901 reg_prefix = ((instr->FPType() & 1) == 0) ? 'S' : 'D';
2904 switch (reg_prefix) {
2905 case 'W':
2906 reg_type = CPURegister::kRegister; reg_size = kWRegSize; break;
2907 case 'X':
2908 reg_type = CPURegister::kRegister; reg_size = kXRegSize; break;
2909 case 'B':
2910 reg_type = CPURegister::kVRegister; reg_size = kBRegSize; break;
2911 case 'H':
2912 reg_type = CPURegister::kVRegister; reg_size = kHRegSize; break;
2913 case 'S':
2914 reg_type = CPURegister::kVRegister; reg_size = kSRegSize; break;
2915 case 'D':
2916 reg_type = CPURegister::kVRegister; reg_size = kDRegSize; break;
2917 case 'Q':
2918 reg_type = CPURegister::kVRegister; reg_size = kQRegSize; break;
2919 case 'V':
2920 AppendToOutput("v%d", reg_num);
2921 return field_len;
2922 default:
2923 VIXL_UNREACHABLE();
2926 if ((reg_type == CPURegister::kRegister) &&
2927 (reg_num == kZeroRegCode) && (format[2] == 's')) {
2928 reg_num = kSPRegInternalCode;
2931 AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type));
2933 return field_len;
2937 int Disassembler::SubstituteImmediateField(const Instruction* instr,
2938 const char* format) {
2939 VIXL_ASSERT(format[0] == 'I');
2941 switch (format[1]) {
2942 case 'M': { // IMoveImm, IMoveNeg or IMoveLSL.
2943 if (format[5] == 'L') {
2944 AppendToOutput("#0x%" PRIx32, instr->ImmMoveWide());
2945 if (instr->ShiftMoveWide() > 0) {
2946 AppendToOutput(", lsl #%" PRId32, 16 * instr->ShiftMoveWide());
2948 } else {
2949 VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N'));
2950 uint64_t imm = static_cast<uint64_t>(instr->ImmMoveWide()) <<
2951 (16 * instr->ShiftMoveWide());
2952 if (format[5] == 'N')
2953 imm = ~imm;
2954 if (!instr->SixtyFourBits())
2955 imm &= UINT64_C(0xffffffff);
2956 AppendToOutput("#0x%" PRIx64, imm);
2958 return 8;
2960 case 'L': {
2961 switch (format[2]) {
2962 case 'L': { // ILLiteral - Immediate Load Literal.
2963 AppendToOutput("pc%+" PRId32,
2964 instr->ImmLLiteral() << kLiteralEntrySizeLog2);
2965 return 9;
2967 case 'S': { // ILS - Immediate Load/Store.
2968 if (instr->ImmLS() != 0) {
2969 AppendToOutput(", #%" PRId32, instr->ImmLS());
2971 return 3;
2973 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
2974 if (instr->ImmLSPair() != 0) {
2975 // format[3] is the scale value. Convert to a number.
2976 int scale = 1 << (format[3] - '0');
2977 AppendToOutput(", #%" PRId32, instr->ImmLSPair() * scale);
2979 return 4;
2981 case 'U': { // ILU - Immediate Load/Store Unsigned.
2982 if (instr->ImmLSUnsigned() != 0) {
2983 int shift = instr->SizeLS();
2984 AppendToOutput(", #%" PRId32, instr->ImmLSUnsigned() << shift);
2986 return 3;
2990 case 'C': { // ICondB - Immediate Conditional Branch.
2991 int64_t offset = instr->ImmCondBranch() << 2;
2992 AppendPCRelativeOffsetToOutput(instr, offset);
2993 return 6;
2995 case 'A': { // IAddSub.
2996 VIXL_ASSERT(instr->ShiftAddSub() <= 1);
2997 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
2998 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
2999 return 7;
3001 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
3002 if (format[3] == 'F') { // IFPFbits.
3003 AppendToOutput("#%" PRId32, 64 - instr->FPScale());
3004 return 8;
3005 } else {
3006 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmFP(),
3007 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
3008 return 9;
3011 case 'T': { // ITri - Immediate Triangular Encoded.
3012 AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
3013 return 4;
3015 case 'N': { // INzcv.
3016 int nzcv = (instr->Nzcv() << Flags_offset);
3017 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
3018 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
3019 ((nzcv & CFlag) == 0) ? 'c' : 'C',
3020 ((nzcv & VFlag) == 0) ? 'v' : 'V');
3021 return 5;
3023 case 'P': { // IP - Conditional compare.
3024 AppendToOutput("#%" PRId32, instr->ImmCondCmp());
3025 return 2;
3027 case 'B': { // Bitfields.
3028 return SubstituteBitfieldImmediateField(instr, format);
3030 case 'E': { // IExtract.
3031 AppendToOutput("#%" PRId32, instr->ImmS());
3032 return 8;
3034 case 'S': { // IS - Test and branch bit.
3035 AppendToOutput("#%" PRId32, (instr->ImmTestBranchBit5() << 5) |
3036 instr->ImmTestBranchBit40());
3037 return 2;
3039 case 's': { // Is - Shift (immediate).
3040 switch (format[2]) {
3041 case '1': { // Is1 - SSHR.
3042 int shift = 16 << HighestSetBitPosition(instr->ImmNEONImmh());
3043 shift -= instr->ImmNEONImmhImmb();
3044 AppendToOutput("#%d", shift);
3045 return 3;
3047 case '2': { // Is2 - SLI.
3048 int shift = instr->ImmNEONImmhImmb();
3049 shift -= 8 << HighestSetBitPosition(instr->ImmNEONImmh());
3050 AppendToOutput("#%d", shift);
3051 return 3;
3053 default: {
3054 VIXL_UNIMPLEMENTED();
3055 return 0;
3059 case 'D': { // IDebug - HLT and BRK instructions.
3060 AppendToOutput("#0x%" PRIx32, instr->ImmException());
3061 return 6;
3063 case 'V': { // Immediate Vector.
3064 switch (format[2]) {
3065 case 'E': { // IVExtract.
3066 AppendToOutput("#%" PRId32, instr->ImmNEONExt());
3067 return 9;
3069 case 'B': { // IVByElemIndex.
3070 int vm_index = (instr->NEONH() << 1) | instr->NEONL();
3071 if (instr->NEONSize() == 1) {
3072 vm_index = (vm_index << 1) | instr->NEONM();
3074 AppendToOutput("%d", vm_index);
3075 return strlen("IVByElemIndex");
3077 case 'I': { // INS element.
3078 if (strncmp(format, "IVInsIndex", strlen("IVInsIndex")) == 0) {
3079 int rd_index, rn_index;
3080 int imm5 = instr->ImmNEON5();
3081 int imm4 = instr->ImmNEON4();
3082 int tz = CountTrailingZeros(imm5, 32);
3083 rd_index = imm5 >> (tz + 1);
3084 rn_index = imm4 >> tz;
3085 if (strncmp(format, "IVInsIndex1", strlen("IVInsIndex1")) == 0) {
3086 AppendToOutput("%d", rd_index);
3087 return strlen("IVInsIndex1");
3088 } else if (strncmp(format, "IVInsIndex2",
3089 strlen("IVInsIndex2")) == 0) {
3090 AppendToOutput("%d", rn_index);
3091 return strlen("IVInsIndex2");
3092 } else {
3093 VIXL_UNIMPLEMENTED();
3094 return 0;
3097 VIXL_FALLTHROUGH();
3099 case 'L': { // IVLSLane[0123] - suffix indicates access size shift.
3100 AppendToOutput("%d", instr->NEONLSIndex(format[8] - '0'));
3101 return 9;
3103 case 'M': { // Modified Immediate cases.
3104 if (strncmp(format,
3105 "IVMIImmFPSingle",
3106 strlen("IVMIImmFPSingle")) == 0) {
3107 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(),
3108 instr->ImmNEONFP32());
3109 return strlen("IVMIImmFPSingle");
3110 } else if (strncmp(format,
3111 "IVMIImmFPDouble",
3112 strlen("IVMIImmFPDouble")) == 0) {
3113 AppendToOutput("#0x%" PRIx32 " (%.4f)", instr->ImmNEONabcdefgh(),
3114 instr->ImmNEONFP64());
3115 return strlen("IVMIImmFPDouble");
3116 } else if (strncmp(format, "IVMIImm8", strlen("IVMIImm8")) == 0) {
3117 uint64_t imm8 = instr->ImmNEONabcdefgh();
3118 AppendToOutput("#0x%" PRIx64, imm8);
3119 return strlen("IVMIImm8");
3120 } else if (strncmp(format, "IVMIImm", strlen("IVMIImm")) == 0) {
3121 uint64_t imm8 = instr->ImmNEONabcdefgh();
3122 uint64_t imm = 0;
3123 for (int i = 0; i < 8; ++i) {
3124 if (imm8 & (1 << i)) {
3125 imm |= (UINT64_C(0xff) << (8 * i));
3128 AppendToOutput("#0x%" PRIx64, imm);
3129 return strlen("IVMIImm");
3130 } else if (strncmp(format, "IVMIShiftAmt1",
3131 strlen("IVMIShiftAmt1")) == 0) {
3132 int cmode = instr->NEONCmode();
3133 int shift_amount = 8 * ((cmode >> 1) & 3);
3134 AppendToOutput("#%d", shift_amount);
3135 return strlen("IVMIShiftAmt1");
3136 } else if (strncmp(format, "IVMIShiftAmt2",
3137 strlen("IVMIShiftAmt2")) == 0) {
3138 int cmode = instr->NEONCmode();
3139 int shift_amount = 8 << (cmode & 1);
3140 AppendToOutput("#%d", shift_amount);
3141 return strlen("IVMIShiftAmt2");
3142 } else {
3143 VIXL_UNIMPLEMENTED();
3144 return 0;
3147 default: {
3148 VIXL_UNIMPLEMENTED();
3149 return 0;
3153 case 'X': { // IX - CLREX instruction.
3154 AppendToOutput("#0x%" PRIx32, instr->CRm());
3155 return 2;
3157 default: {
3158 VIXL_UNIMPLEMENTED();
3159 return 0;
3165 int Disassembler::SubstituteBitfieldImmediateField(const Instruction* instr,
3166 const char* format) {
3167 VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
3168 unsigned r = instr->ImmR();
3169 unsigned s = instr->ImmS();
3171 switch (format[2]) {
3172 case 'r': { // IBr.
3173 AppendToOutput("#%d", r);
3174 return 3;
3176 case 's': { // IBs+1 or IBs-r+1.
3177 if (format[3] == '+') {
3178 AppendToOutput("#%d", s + 1);
3179 return 5;
3180 } else {
3181 VIXL_ASSERT(format[3] == '-');
3182 AppendToOutput("#%d", s - r + 1);
3183 return 7;
3186 case 'Z': { // IBZ-r.
3187 VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));
3188 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
3189 AppendToOutput("#%d", reg_size - r);
3190 return 5;
3192 default: {
3193 VIXL_UNREACHABLE();
3194 return 0;
3200 int Disassembler::SubstituteLiteralField(const Instruction* instr,
3201 const char* format) {
3202 VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
3203 USE(format);
3205 const void * address = instr->LiteralAddress<const void *>();
3206 switch (instr->Mask(LoadLiteralMask)) {
3207 case LDR_w_lit:
3208 case LDR_x_lit:
3209 case LDRSW_x_lit:
3210 case LDR_s_lit:
3211 case LDR_d_lit:
3212 case LDR_q_lit:
3213 AppendCodeRelativeDataAddressToOutput(instr, address);
3214 break;
3215 case PRFM_lit: {
3216 // Use the prefetch hint to decide how to print the address.
3217 switch (instr->PrefetchHint()) {
3218 case 0x0: // PLD: prefetch for load.
3219 case 0x2: // PST: prepare for store.
3220 AppendCodeRelativeDataAddressToOutput(instr, address);
3221 break;
3222 case 0x1: // PLI: preload instructions.
3223 AppendCodeRelativeCodeAddressToOutput(instr, address);
3224 break;
3225 case 0x3: // Unallocated hint.
3226 AppendCodeRelativeAddressToOutput(instr, address);
3227 break;
3229 break;
3231 default:
3232 VIXL_UNREACHABLE();
3235 return 6;
3239 int Disassembler::SubstituteShiftField(const Instruction* instr,
3240 const char* format) {
3241 VIXL_ASSERT(format[0] == 'N');
3242 VIXL_ASSERT(instr->ShiftDP() <= 0x3);
3244 switch (format[1]) {
3245 case 'D': { // HDP.
3246 VIXL_ASSERT(instr->ShiftDP() != ROR);
3247 VIXL_FALLTHROUGH();
3249 case 'L': { // HLo.
3250 if (instr->ImmDPShift() != 0) {
3251 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
3252 AppendToOutput(", %s #%" PRId32, shift_type[instr->ShiftDP()],
3253 instr->ImmDPShift());
3255 return 3;
3257 default:
3258 VIXL_UNIMPLEMENTED();
3259 return 0;
3264 int Disassembler::SubstituteConditionField(const Instruction* instr,
3265 const char* format) {
3266 VIXL_ASSERT(format[0] == 'C');
3267 const char* condition_code[] = { "eq", "ne", "hs", "lo",
3268 "mi", "pl", "vs", "vc",
3269 "hi", "ls", "ge", "lt",
3270 "gt", "le", "al", "nv" };
3271 int cond;
3272 switch (format[1]) {
3273 case 'B': cond = instr->ConditionBranch(); break;
3274 case 'I': {
3275 cond = InvertCondition(static_cast<Condition>(instr->Condition()));
3276 break;
3278 default: cond = instr->Condition();
3280 AppendToOutput("%s", condition_code[cond]);
3281 return 4;
3285 int Disassembler::SubstitutePCRelAddressField(const Instruction* instr,
3286 const char* format) {
3287 VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`.
3288 (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.
3290 int64_t offset = instr->ImmPCRel();
3292 // Compute the target address based on the effective address (after applying
3293 // code_address_offset). This is required for correct behaviour of adrp.
3294 const Instruction* base = instr + code_address_offset();
3295 if (format[9] == 'P') {
3296 offset *= kPageSize;
3297 base = AlignDown(base, kPageSize);
3299 // Strip code_address_offset before printing, so we can use the
3300 // semantically-correct AppendCodeRelativeAddressToOutput.
3301 const void* target =
3302 reinterpret_cast<const void*>(base + offset - code_address_offset());
3304 AppendPCRelativeOffsetToOutput(instr, offset);
3305 AppendToOutput(" ");
3306 AppendCodeRelativeAddressToOutput(instr, target);
3307 return 13;
3311 int Disassembler::SubstituteBranchTargetField(const Instruction* instr,
3312 const char* format) {
3313 VIXL_ASSERT(strncmp(format, "TImm", 4) == 0);
3315 int64_t offset = 0;
3316 switch (format[5]) {
3317 // BImmUncn - unconditional branch immediate.
3318 case 'n': offset = instr->ImmUncondBranch(); break;
3319 // BImmCond - conditional branch immediate.
3320 case 'o': offset = instr->ImmCondBranch(); break;
3321 // BImmCmpa - compare and branch immediate.
3322 case 'm': offset = instr->ImmCmpBranch(); break;
3323 // BImmTest - test and branch immediate.
3324 case 'e': offset = instr->ImmTestBranch(); break;
3325 default: VIXL_UNIMPLEMENTED();
3327 offset <<= kInstructionSizeLog2;
3328 const void* target_address = reinterpret_cast<const void*>(instr + offset);
3329 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
3331 AppendPCRelativeOffsetToOutput(instr, offset);
3332 AppendToOutput(" ");
3333 AppendCodeRelativeCodeAddressToOutput(instr, target_address);
3335 return 8;
3339 int Disassembler::SubstituteExtendField(const Instruction* instr,
3340 const char* format) {
3341 VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
3342 VIXL_ASSERT(instr->ExtendMode() <= 7);
3343 USE(format);
3345 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
3346 "sxtb", "sxth", "sxtw", "sxtx" };
3348 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
3349 // registers becomes lsl.
3350 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
3351 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
3352 (instr->ExtendMode() == UXTX))) {
3353 if (instr->ImmExtendShift() > 0) {
3354 AppendToOutput(", lsl #%" PRId32, instr->ImmExtendShift());
3356 } else {
3357 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
3358 if (instr->ImmExtendShift() > 0) {
3359 AppendToOutput(" #%" PRId32, instr->ImmExtendShift());
3362 return 3;
3366 int Disassembler::SubstituteLSRegOffsetField(const Instruction* instr,
3367 const char* format) {
3368 VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
3369 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
3370 "undefined", "undefined", "sxtw", "sxtx" };
3371 USE(format);
3373 unsigned shift = instr->ImmShiftLS();
3374 Extend ext = static_cast<Extend>(instr->ExtendMode());
3375 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
3377 unsigned rm = instr->Rm();
3378 if (rm == kZeroRegCode) {
3379 AppendToOutput("%czr", reg_type);
3380 } else {
3381 AppendToOutput("%c%d", reg_type, rm);
3384 // Extend mode UXTX is an alias for shift mode LSL here.
3385 if (!((ext == UXTX) && (shift == 0))) {
3386 AppendToOutput(", %s", extend_mode[ext]);
3387 if (shift != 0) {
3388 AppendToOutput(" #%d", instr->SizeLS());
3391 return 9;
3395 int Disassembler::SubstitutePrefetchField(const Instruction* instr,
3396 const char* format) {
3397 VIXL_ASSERT(format[0] == 'P');
3398 USE(format);
3400 static const char* hints[] = {"ld", "li", "st"};
3401 static const char* stream_options[] = {"keep", "strm"};
3403 unsigned hint = instr->PrefetchHint();
3404 unsigned target = instr->PrefetchTarget() + 1;
3405 unsigned stream = instr->PrefetchStream();
3407 if ((hint >= (sizeof(hints) / sizeof(hints[0]))) || (target > 3)) {
3408 // Unallocated prefetch operations.
3409 int prefetch_mode = instr->ImmPrefetchOperation();
3410 AppendToOutput("#0b%c%c%c%c%c",
3411 (prefetch_mode & (1 << 4)) ? '1' : '0',
3412 (prefetch_mode & (1 << 3)) ? '1' : '0',
3413 (prefetch_mode & (1 << 2)) ? '1' : '0',
3414 (prefetch_mode & (1 << 1)) ? '1' : '0',
3415 (prefetch_mode & (1 << 0)) ? '1' : '0');
3416 } else {
3417 VIXL_ASSERT(stream < (sizeof(stream_options) / sizeof(stream_options[0])));
3418 AppendToOutput("p%sl%d%s", hints[hint], target, stream_options[stream]);
3420 return 6;
3423 int Disassembler::SubstituteBarrierField(const Instruction* instr,
3424 const char* format) {
3425 VIXL_ASSERT(format[0] == 'M');
3426 USE(format);
3428 static const char* options[4][4] = {
3429 { "sy (0b0000)", "oshld", "oshst", "osh" },
3430 { "sy (0b0100)", "nshld", "nshst", "nsh" },
3431 { "sy (0b1000)", "ishld", "ishst", "ish" },
3432 { "sy (0b1100)", "ld", "st", "sy" }
3434 int domain = instr->ImmBarrierDomain();
3435 int type = instr->ImmBarrierType();
3437 AppendToOutput("%s", options[domain][type]);
3438 return 1;
3441 int Disassembler::SubstituteSysOpField(const Instruction* instr,
3442 const char* format) {
3443 VIXL_ASSERT(format[0] == 'G');
3444 int op = -1;
3445 switch (format[1]) {
3446 case '1': op = instr->SysOp1(); break;
3447 case '2': op = instr->SysOp2(); break;
3448 default:
3449 VIXL_UNREACHABLE();
3451 AppendToOutput("#%d", op);
3452 return 2;
3455 int Disassembler::SubstituteCrField(const Instruction* instr,
3456 const char* format) {
3457 VIXL_ASSERT(format[0] == 'K');
3458 int cr = -1;
3459 switch (format[1]) {
3460 case 'n': cr = instr->CRn(); break;
3461 case 'm': cr = instr->CRm(); break;
3462 default:
3463 VIXL_UNREACHABLE();
3465 AppendToOutput("C%d", cr);
3466 return 2;
3469 void Disassembler::ResetOutput() {
3470 buffer_pos_ = 0;
3471 buffer_[buffer_pos_] = 0;
3475 void Disassembler::AppendToOutput(const char* format, ...) {
3476 va_list args;
3477 va_start(args, format);
3478 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_ - buffer_pos_,
3479 format, args);
3480 va_end(args);
3484 void PrintDisassembler::ProcessOutput(const Instruction* instr) {
3485 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
3486 reinterpret_cast<uint64_t>(instr),
3487 instr->InstructionBits(),
3488 GetOutput());
3491 } // namespace vixl