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