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