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