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