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