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