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