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