1// Copyright 2013, 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 "a64/disasm-a64.h"
28
29namespace vixl {
30
31Disassembler::Disassembler() {
32  buffer_size_ = 256;
33  buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
34  buffer_pos_ = 0;
35  own_buffer_ = true;
36}
37
38
39Disassembler::Disassembler(char* text_buffer, int buffer_size) {
40  buffer_size_ = buffer_size;
41  buffer_ = text_buffer;
42  buffer_pos_ = 0;
43  own_buffer_ = false;
44}
45
46
47Disassembler::~Disassembler() {
48  if (own_buffer_) {
49    free(buffer_);
50  }
51}
52
53
54char* Disassembler::GetOutput() {
55  return buffer_;
56}
57
58
59void Disassembler::VisitAddSubImmediate(Instruction* instr) {
60  bool rd_is_zr = RdIsZROrSP(instr);
61  bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
62                  (instr->ImmAddSub() == 0) ? true : false;
63  const char *mnemonic = "";
64  const char *form = "'Rds, 'Rns, 'IAddSub";
65  const char *form_cmp = "'Rns, 'IAddSub";
66  const char *form_mov = "'Rds, 'Rns";
67
68  switch (instr->Mask(AddSubImmediateMask)) {
69    case ADD_w_imm:
70    case ADD_x_imm: {
71      mnemonic = "add";
72      if (stack_op) {
73        mnemonic = "mov";
74        form = form_mov;
75      }
76      break;
77    }
78    case ADDS_w_imm:
79    case ADDS_x_imm: {
80      mnemonic = "adds";
81      if (rd_is_zr) {
82        mnemonic = "cmn";
83        form = form_cmp;
84      }
85      break;
86    }
87    case SUB_w_imm:
88    case SUB_x_imm: mnemonic = "sub"; break;
89    case SUBS_w_imm:
90    case SUBS_x_imm: {
91      mnemonic = "subs";
92      if (rd_is_zr) {
93        mnemonic = "cmp";
94        form = form_cmp;
95      }
96      break;
97    }
98    default: VIXL_UNREACHABLE();
99  }
100  Format(instr, mnemonic, form);
101}
102
103
104void Disassembler::VisitAddSubShifted(Instruction* instr) {
105  bool rd_is_zr = RdIsZROrSP(instr);
106  bool rn_is_zr = RnIsZROrSP(instr);
107  const char *mnemonic = "";
108  const char *form = "'Rd, 'Rn, 'Rm'HDP";
109  const char *form_cmp = "'Rn, 'Rm'HDP";
110  const char *form_neg = "'Rd, 'Rm'HDP";
111
112  switch (instr->Mask(AddSubShiftedMask)) {
113    case ADD_w_shift:
114    case ADD_x_shift: mnemonic = "add"; break;
115    case ADDS_w_shift:
116    case ADDS_x_shift: {
117      mnemonic = "adds";
118      if (rd_is_zr) {
119        mnemonic = "cmn";
120        form = form_cmp;
121      }
122      break;
123    }
124    case SUB_w_shift:
125    case SUB_x_shift: {
126      mnemonic = "sub";
127      if (rn_is_zr) {
128        mnemonic = "neg";
129        form = form_neg;
130      }
131      break;
132    }
133    case SUBS_w_shift:
134    case SUBS_x_shift: {
135      mnemonic = "subs";
136      if (rd_is_zr) {
137        mnemonic = "cmp";
138        form = form_cmp;
139      } else if (rn_is_zr) {
140        mnemonic = "negs";
141        form = form_neg;
142      }
143      break;
144    }
145    default: VIXL_UNREACHABLE();
146  }
147  Format(instr, mnemonic, form);
148}
149
150
151void Disassembler::VisitAddSubExtended(Instruction* instr) {
152  bool rd_is_zr = RdIsZROrSP(instr);
153  const char *mnemonic = "";
154  Extend mode = static_cast<Extend>(instr->ExtendMode());
155  const char *form = ((mode == UXTX) || (mode == SXTX)) ?
156                     "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
157  const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
158                         "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
159
160  switch (instr->Mask(AddSubExtendedMask)) {
161    case ADD_w_ext:
162    case ADD_x_ext: mnemonic = "add"; break;
163    case ADDS_w_ext:
164    case ADDS_x_ext: {
165      mnemonic = "adds";
166      if (rd_is_zr) {
167        mnemonic = "cmn";
168        form = form_cmp;
169      }
170      break;
171    }
172    case SUB_w_ext:
173    case SUB_x_ext: mnemonic = "sub"; break;
174    case SUBS_w_ext:
175    case SUBS_x_ext: {
176      mnemonic = "subs";
177      if (rd_is_zr) {
178        mnemonic = "cmp";
179        form = form_cmp;
180      }
181      break;
182    }
183    default: VIXL_UNREACHABLE();
184  }
185  Format(instr, mnemonic, form);
186}
187
188
189void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
190  bool rn_is_zr = RnIsZROrSP(instr);
191  const char *mnemonic = "";
192  const char *form = "'Rd, 'Rn, 'Rm";
193  const char *form_neg = "'Rd, 'Rm";
194
195  switch (instr->Mask(AddSubWithCarryMask)) {
196    case ADC_w:
197    case ADC_x: mnemonic = "adc"; break;
198    case ADCS_w:
199    case ADCS_x: mnemonic = "adcs"; break;
200    case SBC_w:
201    case SBC_x: {
202      mnemonic = "sbc";
203      if (rn_is_zr) {
204        mnemonic = "ngc";
205        form = form_neg;
206      }
207      break;
208    }
209    case SBCS_w:
210    case SBCS_x: {
211      mnemonic = "sbcs";
212      if (rn_is_zr) {
213        mnemonic = "ngcs";
214        form = form_neg;
215      }
216      break;
217    }
218    default: VIXL_UNREACHABLE();
219  }
220  Format(instr, mnemonic, form);
221}
222
223
224void Disassembler::VisitLogicalImmediate(Instruction* instr) {
225  bool rd_is_zr = RdIsZROrSP(instr);
226  bool rn_is_zr = RnIsZROrSP(instr);
227  const char *mnemonic = "";
228  const char *form = "'Rds, 'Rn, 'ITri";
229
230  if (instr->ImmLogical() == 0) {
231    // The immediate encoded in the instruction is not in the expected format.
232    Format(instr, "unallocated", "(LogicalImmediate)");
233    return;
234  }
235
236  switch (instr->Mask(LogicalImmediateMask)) {
237    case AND_w_imm:
238    case AND_x_imm: mnemonic = "and"; break;
239    case ORR_w_imm:
240    case ORR_x_imm: {
241      mnemonic = "orr";
242      unsigned reg_size = (instr->SixtyFourBits() != 0) ? kXRegSize
243                                                        : kWRegSize;
244      if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
245        mnemonic = "mov";
246        form = "'Rds, 'ITri";
247      }
248      break;
249    }
250    case EOR_w_imm:
251    case EOR_x_imm: mnemonic = "eor"; break;
252    case ANDS_w_imm:
253    case ANDS_x_imm: {
254      mnemonic = "ands";
255      if (rd_is_zr) {
256        mnemonic = "tst";
257        form = "'Rn, 'ITri";
258      }
259      break;
260    }
261    default: VIXL_UNREACHABLE();
262  }
263  Format(instr, mnemonic, form);
264}
265
266
267bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
268  VIXL_ASSERT((reg_size == kXRegSize) ||
269              ((reg_size == kWRegSize) && (value <= 0xffffffff)));
270
271  // Test for movz: 16 bits set at positions 0, 16, 32 or 48.
272  if (((value & UINT64_C(0xffffffffffff0000)) == 0) ||
273      ((value & UINT64_C(0xffffffff0000ffff)) == 0) ||
274      ((value & UINT64_C(0xffff0000ffffffff)) == 0) ||
275      ((value & UINT64_C(0x0000ffffffffffff)) == 0)) {
276    return true;
277  }
278
279  // Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
280  if ((reg_size == kXRegSize) &&
281      (((~value & UINT64_C(0xffffffffffff0000)) == 0) ||
282       ((~value & UINT64_C(0xffffffff0000ffff)) == 0) ||
283       ((~value & UINT64_C(0xffff0000ffffffff)) == 0) ||
284       ((~value & UINT64_C(0x0000ffffffffffff)) == 0))) {
285    return true;
286  }
287  if ((reg_size == kWRegSize) &&
288      (((value & 0xffff0000) == 0xffff0000) ||
289       ((value & 0x0000ffff) == 0x0000ffff))) {
290    return true;
291  }
292  return false;
293}
294
295
296void Disassembler::VisitLogicalShifted(Instruction* instr) {
297  bool rd_is_zr = RdIsZROrSP(instr);
298  bool rn_is_zr = RnIsZROrSP(instr);
299  const char *mnemonic = "";
300  const char *form = "'Rd, 'Rn, 'Rm'HLo";
301
302  switch (instr->Mask(LogicalShiftedMask)) {
303    case AND_w:
304    case AND_x: mnemonic = "and"; break;
305    case BIC_w:
306    case BIC_x: mnemonic = "bic"; break;
307    case EOR_w:
308    case EOR_x: mnemonic = "eor"; break;
309    case EON_w:
310    case EON_x: mnemonic = "eon"; break;
311    case BICS_w:
312    case BICS_x: mnemonic = "bics"; break;
313    case ANDS_w:
314    case ANDS_x: {
315      mnemonic = "ands";
316      if (rd_is_zr) {
317        mnemonic = "tst";
318        form = "'Rn, 'Rm'HLo";
319      }
320      break;
321    }
322    case ORR_w:
323    case ORR_x: {
324      mnemonic = "orr";
325      if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
326        mnemonic = "mov";
327        form = "'Rd, 'Rm";
328      }
329      break;
330    }
331    case ORN_w:
332    case ORN_x: {
333      mnemonic = "orn";
334      if (rn_is_zr) {
335        mnemonic = "mvn";
336        form = "'Rd, 'Rm'HLo";
337      }
338      break;
339    }
340    default: VIXL_UNREACHABLE();
341  }
342
343  Format(instr, mnemonic, form);
344}
345
346
347void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
348  const char *mnemonic = "";
349  const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
350
351  switch (instr->Mask(ConditionalCompareRegisterMask)) {
352    case CCMN_w:
353    case CCMN_x: mnemonic = "ccmn"; break;
354    case CCMP_w:
355    case CCMP_x: mnemonic = "ccmp"; break;
356    default: VIXL_UNREACHABLE();
357  }
358  Format(instr, mnemonic, form);
359}
360
361
362void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
363  const char *mnemonic = "";
364  const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
365
366  switch (instr->Mask(ConditionalCompareImmediateMask)) {
367    case CCMN_w_imm:
368    case CCMN_x_imm: mnemonic = "ccmn"; break;
369    case CCMP_w_imm:
370    case CCMP_x_imm: mnemonic = "ccmp"; break;
371    default: VIXL_UNREACHABLE();
372  }
373  Format(instr, mnemonic, form);
374}
375
376
377void Disassembler::VisitConditionalSelect(Instruction* instr) {
378  bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
379  bool rn_is_rm = (instr->Rn() == instr->Rm());
380  const char *mnemonic = "";
381  const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
382  const char *form_test = "'Rd, 'CInv";
383  const char *form_update = "'Rd, 'Rn, 'CInv";
384
385  Condition cond = static_cast<Condition>(instr->Condition());
386  bool invertible_cond = (cond != al) && (cond != nv);
387
388  switch (instr->Mask(ConditionalSelectMask)) {
389    case CSEL_w:
390    case CSEL_x: mnemonic = "csel"; break;
391    case CSINC_w:
392    case CSINC_x: {
393      mnemonic = "csinc";
394      if (rnm_is_zr && invertible_cond) {
395        mnemonic = "cset";
396        form = form_test;
397      } else if (rn_is_rm && invertible_cond) {
398        mnemonic = "cinc";
399        form = form_update;
400      }
401      break;
402    }
403    case CSINV_w:
404    case CSINV_x: {
405      mnemonic = "csinv";
406      if (rnm_is_zr && invertible_cond) {
407        mnemonic = "csetm";
408        form = form_test;
409      } else if (rn_is_rm && invertible_cond) {
410        mnemonic = "cinv";
411        form = form_update;
412      }
413      break;
414    }
415    case CSNEG_w:
416    case CSNEG_x: {
417      mnemonic = "csneg";
418      if (rn_is_rm && invertible_cond) {
419        mnemonic = "cneg";
420        form = form_update;
421      }
422      break;
423    }
424    default: VIXL_UNREACHABLE();
425  }
426  Format(instr, mnemonic, form);
427}
428
429
430void Disassembler::VisitBitfield(Instruction* instr) {
431  unsigned s = instr->ImmS();
432  unsigned r = instr->ImmR();
433  unsigned rd_size_minus_1 =
434    ((instr->SixtyFourBits() != 0) ? kXRegSize : kWRegSize) - 1;
435  const char *mnemonic = "";
436  const char *form = "";
437  const char *form_shift_right = "'Rd, 'Rn, 'IBr";
438  const char *form_extend = "'Rd, 'Wn";
439  const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
440  const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
441  const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
442
443  switch (instr->Mask(BitfieldMask)) {
444    case SBFM_w:
445    case SBFM_x: {
446      mnemonic = "sbfx";
447      form = form_bfx;
448      if (r == 0) {
449        form = form_extend;
450        if (s == 7) {
451          mnemonic = "sxtb";
452        } else if (s == 15) {
453          mnemonic = "sxth";
454        } else if ((s == 31) && (instr->SixtyFourBits() != 0)) {
455          mnemonic = "sxtw";
456        } else {
457          form = form_bfx;
458        }
459      } else if (s == rd_size_minus_1) {
460        mnemonic = "asr";
461        form = form_shift_right;
462      } else if (s < r) {
463        mnemonic = "sbfiz";
464        form = form_bfiz;
465      }
466      break;
467    }
468    case UBFM_w:
469    case UBFM_x: {
470      mnemonic = "ubfx";
471      form = form_bfx;
472      if (r == 0) {
473        form = form_extend;
474        if (s == 7) {
475          mnemonic = "uxtb";
476        } else if (s == 15) {
477          mnemonic = "uxth";
478        } else {
479          form = form_bfx;
480        }
481      }
482      if (s == rd_size_minus_1) {
483        mnemonic = "lsr";
484        form = form_shift_right;
485      } else if (r == s + 1) {
486        mnemonic = "lsl";
487        form = form_lsl;
488      } else if (s < r) {
489        mnemonic = "ubfiz";
490        form = form_bfiz;
491      }
492      break;
493    }
494    case BFM_w:
495    case BFM_x: {
496      mnemonic = "bfxil";
497      form = form_bfx;
498      if (s < r) {
499        mnemonic = "bfi";
500        form = form_bfiz;
501      }
502    }
503  }
504  Format(instr, mnemonic, form);
505}
506
507
508void Disassembler::VisitExtract(Instruction* instr) {
509  const char *mnemonic = "";
510  const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
511
512  switch (instr->Mask(ExtractMask)) {
513    case EXTR_w:
514    case EXTR_x: {
515      if (instr->Rn() == instr->Rm()) {
516        mnemonic = "ror";
517        form = "'Rd, 'Rn, 'IExtract";
518      } else {
519        mnemonic = "extr";
520      }
521      break;
522    }
523    default: VIXL_UNREACHABLE();
524  }
525  Format(instr, mnemonic, form);
526}
527
528
529void Disassembler::VisitPCRelAddressing(Instruction* instr) {
530  switch (instr->Mask(PCRelAddressingMask)) {
531    case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
532    // ADRP is not implemented.
533    default: Format(instr, "unimplemented", "(PCRelAddressing)");
534  }
535}
536
537
538void Disassembler::VisitConditionalBranch(Instruction* instr) {
539  switch (instr->Mask(ConditionalBranchMask)) {
540    case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
541    default: VIXL_UNREACHABLE();
542  }
543}
544
545
546void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
547  const char *mnemonic = "unimplemented";
548  const char *form = "'Xn";
549
550  switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
551    case BR: mnemonic = "br"; break;
552    case BLR: mnemonic = "blr"; break;
553    case RET: {
554      mnemonic = "ret";
555      if (instr->Rn() == kLinkRegCode) {
556        form = NULL;
557      }
558      break;
559    }
560    default: form = "(UnconditionalBranchToRegister)";
561  }
562  Format(instr, mnemonic, form);
563}
564
565
566void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
567  const char *mnemonic = "";
568  const char *form = "'BImmUncn";
569
570  switch (instr->Mask(UnconditionalBranchMask)) {
571    case B: mnemonic = "b"; break;
572    case BL: mnemonic = "bl"; break;
573    default: VIXL_UNREACHABLE();
574  }
575  Format(instr, mnemonic, form);
576}
577
578
579void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
580  const char *mnemonic = "";
581  const char *form = "'Rd, 'Rn";
582
583  switch (instr->Mask(DataProcessing1SourceMask)) {
584    #define FORMAT(A, B)  \
585    case A##_w:           \
586    case A##_x: mnemonic = B; break;
587    FORMAT(RBIT, "rbit");
588    FORMAT(REV16, "rev16");
589    FORMAT(REV, "rev");
590    FORMAT(CLZ, "clz");
591    FORMAT(CLS, "cls");
592    #undef FORMAT
593    case REV32_x: mnemonic = "rev32"; break;
594    default: VIXL_UNREACHABLE();
595  }
596  Format(instr, mnemonic, form);
597}
598
599
600void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
601  const char *mnemonic = "unimplemented";
602  const char *form = "'Rd, 'Rn, 'Rm";
603
604  switch (instr->Mask(DataProcessing2SourceMask)) {
605    #define FORMAT(A, B)  \
606    case A##_w:           \
607    case A##_x: mnemonic = B; break;
608    FORMAT(UDIV, "udiv");
609    FORMAT(SDIV, "sdiv");
610    FORMAT(LSLV, "lsl");
611    FORMAT(LSRV, "lsr");
612    FORMAT(ASRV, "asr");
613    FORMAT(RORV, "ror");
614    #undef FORMAT
615    default: form = "(DataProcessing2Source)";
616  }
617  Format(instr, mnemonic, form);
618}
619
620
621void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
622  bool ra_is_zr = RaIsZROrSP(instr);
623  const char *mnemonic = "";
624  const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
625  const char *form_rrr = "'Rd, 'Rn, 'Rm";
626  const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
627  const char *form_xww = "'Xd, 'Wn, 'Wm";
628  const char *form_xxx = "'Xd, 'Xn, 'Xm";
629
630  switch (instr->Mask(DataProcessing3SourceMask)) {
631    case MADD_w:
632    case MADD_x: {
633      mnemonic = "madd";
634      form = form_rrrr;
635      if (ra_is_zr) {
636        mnemonic = "mul";
637        form = form_rrr;
638      }
639      break;
640    }
641    case MSUB_w:
642    case MSUB_x: {
643      mnemonic = "msub";
644      form = form_rrrr;
645      if (ra_is_zr) {
646        mnemonic = "mneg";
647        form = form_rrr;
648      }
649      break;
650    }
651    case SMADDL_x: {
652      mnemonic = "smaddl";
653      if (ra_is_zr) {
654        mnemonic = "smull";
655        form = form_xww;
656      }
657      break;
658    }
659    case SMSUBL_x: {
660      mnemonic = "smsubl";
661      if (ra_is_zr) {
662        mnemonic = "smnegl";
663        form = form_xww;
664      }
665      break;
666    }
667    case UMADDL_x: {
668      mnemonic = "umaddl";
669      if (ra_is_zr) {
670        mnemonic = "umull";
671        form = form_xww;
672      }
673      break;
674    }
675    case UMSUBL_x: {
676      mnemonic = "umsubl";
677      if (ra_is_zr) {
678        mnemonic = "umnegl";
679        form = form_xww;
680      }
681      break;
682    }
683    case SMULH_x: {
684      mnemonic = "smulh";
685      form = form_xxx;
686      break;
687    }
688    case UMULH_x: {
689      mnemonic = "umulh";
690      form = form_xxx;
691      break;
692    }
693    default: VIXL_UNREACHABLE();
694  }
695  Format(instr, mnemonic, form);
696}
697
698
699void Disassembler::VisitCompareBranch(Instruction* instr) {
700  const char *mnemonic = "";
701  const char *form = "'Rt, 'BImmCmpa";
702
703  switch (instr->Mask(CompareBranchMask)) {
704    case CBZ_w:
705    case CBZ_x: mnemonic = "cbz"; break;
706    case CBNZ_w:
707    case CBNZ_x: mnemonic = "cbnz"; break;
708    default: VIXL_UNREACHABLE();
709  }
710  Format(instr, mnemonic, form);
711}
712
713
714void Disassembler::VisitTestBranch(Instruction* instr) {
715  const char *mnemonic = "";
716  // If the top bit of the immediate is clear, the tested register is
717  // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
718  // encoded in bit 31 of the instruction, we can reuse the Rt form, which
719  // uses bit 31 (normally "sf") to choose the register size.
720  const char *form = "'Rt, 'IS, 'BImmTest";
721
722  switch (instr->Mask(TestBranchMask)) {
723    case TBZ: mnemonic = "tbz"; break;
724    case TBNZ: mnemonic = "tbnz"; break;
725    default: VIXL_UNREACHABLE();
726  }
727  Format(instr, mnemonic, form);
728}
729
730
731void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
732  const char *mnemonic = "";
733  const char *form = "'Rd, 'IMoveImm";
734
735  // Print the shift separately for movk, to make it clear which half word will
736  // be overwritten. Movn and movz print the computed immediate, which includes
737  // shift calculation.
738  switch (instr->Mask(MoveWideImmediateMask)) {
739    case MOVN_w:
740    case MOVN_x: mnemonic = "movn"; break;
741    case MOVZ_w:
742    case MOVZ_x: mnemonic = "movz"; break;
743    case MOVK_w:
744    case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
745    default: VIXL_UNREACHABLE();
746  }
747  Format(instr, mnemonic, form);
748}
749
750
751#define LOAD_STORE_LIST(V)    \
752  V(STRB_w, "strb", "'Wt")    \
753  V(STRH_w, "strh", "'Wt")    \
754  V(STR_w, "str", "'Wt")      \
755  V(STR_x, "str", "'Xt")      \
756  V(LDRB_w, "ldrb", "'Wt")    \
757  V(LDRH_w, "ldrh", "'Wt")    \
758  V(LDR_w, "ldr", "'Wt")      \
759  V(LDR_x, "ldr", "'Xt")      \
760  V(LDRSB_x, "ldrsb", "'Xt")  \
761  V(LDRSH_x, "ldrsh", "'Xt")  \
762  V(LDRSW_x, "ldrsw", "'Xt")  \
763  V(LDRSB_w, "ldrsb", "'Wt")  \
764  V(LDRSH_w, "ldrsh", "'Wt")  \
765  V(STR_s, "str", "'St")      \
766  V(STR_d, "str", "'Dt")      \
767  V(LDR_s, "ldr", "'St")      \
768  V(LDR_d, "ldr", "'Dt")
769
770void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
771  const char *mnemonic = "unimplemented";
772  const char *form = "(LoadStorePreIndex)";
773
774  switch (instr->Mask(LoadStorePreIndexMask)) {
775    #define LS_PREINDEX(A, B, C) \
776    case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
777    LOAD_STORE_LIST(LS_PREINDEX)
778    #undef LS_PREINDEX
779  }
780  Format(instr, mnemonic, form);
781}
782
783
784void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
785  const char *mnemonic = "unimplemented";
786  const char *form = "(LoadStorePostIndex)";
787
788  switch (instr->Mask(LoadStorePostIndexMask)) {
789    #define LS_POSTINDEX(A, B, C) \
790    case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
791    LOAD_STORE_LIST(LS_POSTINDEX)
792    #undef LS_POSTINDEX
793  }
794  Format(instr, mnemonic, form);
795}
796
797
798void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
799  const char *mnemonic = "unimplemented";
800  const char *form = "(LoadStoreUnsignedOffset)";
801
802  switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
803    #define LS_UNSIGNEDOFFSET(A, B, C) \
804    case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
805    LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
806    #undef LS_UNSIGNEDOFFSET
807    case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]";
808  }
809  Format(instr, mnemonic, form);
810}
811
812
813void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
814  const char *mnemonic = "unimplemented";
815  const char *form = "(LoadStoreRegisterOffset)";
816
817  switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
818    #define LS_REGISTEROFFSET(A, B, C) \
819    case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
820    LOAD_STORE_LIST(LS_REGISTEROFFSET)
821    #undef LS_REGISTEROFFSET
822    case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
823  }
824  Format(instr, mnemonic, form);
825}
826
827
828void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
829  const char *mnemonic = "unimplemented";
830  const char *form = "'Wt, ['Xns'ILS]";
831  const char *form_x = "'Xt, ['Xns'ILS]";
832  const char *form_s = "'St, ['Xns'ILS]";
833  const char *form_d = "'Dt, ['Xns'ILS]";
834
835  switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
836    case STURB_w:  mnemonic = "sturb"; break;
837    case STURH_w:  mnemonic = "sturh"; break;
838    case STUR_w:   mnemonic = "stur"; break;
839    case STUR_x:   mnemonic = "stur"; form = form_x; break;
840    case STUR_s:   mnemonic = "stur"; form = form_s; break;
841    case STUR_d:   mnemonic = "stur"; form = form_d; break;
842    case LDURB_w:  mnemonic = "ldurb"; break;
843    case LDURH_w:  mnemonic = "ldurh"; break;
844    case LDUR_w:   mnemonic = "ldur"; break;
845    case LDUR_x:   mnemonic = "ldur"; form = form_x; break;
846    case LDUR_s:   mnemonic = "ldur"; form = form_s; break;
847    case LDUR_d:   mnemonic = "ldur"; form = form_d; break;
848    case LDURSB_x: form = form_x;  // Fall through.
849    case LDURSB_w: mnemonic = "ldursb"; break;
850    case LDURSH_x: form = form_x;  // Fall through.
851    case LDURSH_w: mnemonic = "ldursh"; break;
852    case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
853    default: form = "(LoadStoreUnscaledOffset)";
854  }
855  Format(instr, mnemonic, form);
856}
857
858
859void Disassembler::VisitLoadLiteral(Instruction* instr) {
860  const char *mnemonic = "ldr";
861  const char *form = "(LoadLiteral)";
862
863  switch (instr->Mask(LoadLiteralMask)) {
864    case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
865    case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
866    case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
867    case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
868    default: mnemonic = "unimplemented";
869  }
870  Format(instr, mnemonic, form);
871}
872
873
874#define LOAD_STORE_PAIR_LIST(V)         \
875  V(STP_w, "stp", "'Wt, 'Wt2", "4")     \
876  V(LDP_w, "ldp", "'Wt, 'Wt2", "4")     \
877  V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
878  V(STP_x, "stp", "'Xt, 'Xt2", "8")     \
879  V(LDP_x, "ldp", "'Xt, 'Xt2", "8")     \
880  V(STP_s, "stp", "'St, 'St2", "4")     \
881  V(LDP_s, "ldp", "'St, 'St2", "4")     \
882  V(STP_d, "stp", "'Dt, 'Dt2", "8")     \
883  V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
884
885void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
886  const char *mnemonic = "unimplemented";
887  const char *form = "(LoadStorePairPostIndex)";
888
889  switch (instr->Mask(LoadStorePairPostIndexMask)) {
890    #define LSP_POSTINDEX(A, B, C, D) \
891    case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
892    LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
893    #undef LSP_POSTINDEX
894  }
895  Format(instr, mnemonic, form);
896}
897
898
899void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
900  const char *mnemonic = "unimplemented";
901  const char *form = "(LoadStorePairPreIndex)";
902
903  switch (instr->Mask(LoadStorePairPreIndexMask)) {
904    #define LSP_PREINDEX(A, B, C, D) \
905    case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
906    LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
907    #undef LSP_PREINDEX
908  }
909  Format(instr, mnemonic, form);
910}
911
912
913void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
914  const char *mnemonic = "unimplemented";
915  const char *form = "(LoadStorePairOffset)";
916
917  switch (instr->Mask(LoadStorePairOffsetMask)) {
918    #define LSP_OFFSET(A, B, C, D) \
919    case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
920    LOAD_STORE_PAIR_LIST(LSP_OFFSET)
921    #undef LSP_OFFSET
922  }
923  Format(instr, mnemonic, form);
924}
925
926
927void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
928  const char *mnemonic = "unimplemented";
929  const char *form;
930
931  switch (instr->Mask(LoadStorePairNonTemporalMask)) {
932    case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
933    case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
934    case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
935    case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
936    case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
937    case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
938    case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
939    case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
940    default: form = "(LoadStorePairNonTemporal)";
941  }
942  Format(instr, mnemonic, form);
943}
944
945
946void Disassembler::VisitFPCompare(Instruction* instr) {
947  const char *mnemonic = "unimplemented";
948  const char *form = "'Fn, 'Fm";
949  const char *form_zero = "'Fn, #0.0";
950
951  switch (instr->Mask(FPCompareMask)) {
952    case FCMP_s_zero:
953    case FCMP_d_zero: form = form_zero;  // Fall through.
954    case FCMP_s:
955    case FCMP_d: mnemonic = "fcmp"; break;
956    default: form = "(FPCompare)";
957  }
958  Format(instr, mnemonic, form);
959}
960
961
962void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
963  const char *mnemonic = "unmplemented";
964  const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
965
966  switch (instr->Mask(FPConditionalCompareMask)) {
967    case FCCMP_s:
968    case FCCMP_d: mnemonic = "fccmp"; break;
969    case FCCMPE_s:
970    case FCCMPE_d: mnemonic = "fccmpe"; break;
971    default: form = "(FPConditionalCompare)";
972  }
973  Format(instr, mnemonic, form);
974}
975
976
977void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
978  const char *mnemonic = "";
979  const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
980
981  switch (instr->Mask(FPConditionalSelectMask)) {
982    case FCSEL_s:
983    case FCSEL_d: mnemonic = "fcsel"; break;
984    default: VIXL_UNREACHABLE();
985  }
986  Format(instr, mnemonic, form);
987}
988
989
990void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
991  const char *mnemonic = "unimplemented";
992  const char *form = "'Fd, 'Fn";
993
994  switch (instr->Mask(FPDataProcessing1SourceMask)) {
995    #define FORMAT(A, B)  \
996    case A##_s:           \
997    case A##_d: mnemonic = B; break;
998    FORMAT(FMOV, "fmov");
999    FORMAT(FABS, "fabs");
1000    FORMAT(FNEG, "fneg");
1001    FORMAT(FSQRT, "fsqrt");
1002    FORMAT(FRINTN, "frintn");
1003    FORMAT(FRINTP, "frintp");
1004    FORMAT(FRINTM, "frintm");
1005    FORMAT(FRINTZ, "frintz");
1006    FORMAT(FRINTA, "frinta");
1007    FORMAT(FRINTX, "frintx");
1008    FORMAT(FRINTI, "frinti");
1009    #undef FORMAT
1010    case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
1011    case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
1012    default: form = "(FPDataProcessing1Source)";
1013  }
1014  Format(instr, mnemonic, form);
1015}
1016
1017
1018void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
1019  const char *mnemonic = "";
1020  const char *form = "'Fd, 'Fn, 'Fm";
1021
1022  switch (instr->Mask(FPDataProcessing2SourceMask)) {
1023    #define FORMAT(A, B)  \
1024    case A##_s:           \
1025    case A##_d: mnemonic = B; break;
1026    FORMAT(FMUL, "fmul");
1027    FORMAT(FDIV, "fdiv");
1028    FORMAT(FADD, "fadd");
1029    FORMAT(FSUB, "fsub");
1030    FORMAT(FMAX, "fmax");
1031    FORMAT(FMIN, "fmin");
1032    FORMAT(FMAXNM, "fmaxnm");
1033    FORMAT(FMINNM, "fminnm");
1034    FORMAT(FNMUL, "fnmul");
1035    #undef FORMAT
1036    default: VIXL_UNREACHABLE();
1037  }
1038  Format(instr, mnemonic, form);
1039}
1040
1041
1042void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
1043  const char *mnemonic = "";
1044  const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1045
1046  switch (instr->Mask(FPDataProcessing3SourceMask)) {
1047    #define FORMAT(A, B)  \
1048    case A##_s:           \
1049    case A##_d: mnemonic = B; break;
1050    FORMAT(FMADD, "fmadd");
1051    FORMAT(FMSUB, "fmsub");
1052    FORMAT(FNMADD, "fnmadd");
1053    FORMAT(FNMSUB, "fnmsub");
1054    #undef FORMAT
1055    default: VIXL_UNREACHABLE();
1056  }
1057  Format(instr, mnemonic, form);
1058}
1059
1060
1061void Disassembler::VisitFPImmediate(Instruction* instr) {
1062  const char *mnemonic = "";
1063  const char *form = "(FPImmediate)";
1064
1065  switch (instr->Mask(FPImmediateMask)) {
1066    case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1067    case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1068    default: VIXL_UNREACHABLE();
1069  }
1070  Format(instr, mnemonic, form);
1071}
1072
1073
1074void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
1075  const char *mnemonic = "unimplemented";
1076  const char *form = "(FPIntegerConvert)";
1077  const char *form_rf = "'Rd, 'Fn";
1078  const char *form_fr = "'Fd, 'Rn";
1079
1080  switch (instr->Mask(FPIntegerConvertMask)) {
1081    case FMOV_ws:
1082    case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1083    case FMOV_sw:
1084    case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1085    case FCVTAS_ws:
1086    case FCVTAS_xs:
1087    case FCVTAS_wd:
1088    case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
1089    case FCVTAU_ws:
1090    case FCVTAU_xs:
1091    case FCVTAU_wd:
1092    case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
1093    case FCVTMS_ws:
1094    case FCVTMS_xs:
1095    case FCVTMS_wd:
1096    case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1097    case FCVTMU_ws:
1098    case FCVTMU_xs:
1099    case FCVTMU_wd:
1100    case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1101    case FCVTNS_ws:
1102    case FCVTNS_xs:
1103    case FCVTNS_wd:
1104    case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1105    case FCVTNU_ws:
1106    case FCVTNU_xs:
1107    case FCVTNU_wd:
1108    case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1109    case FCVTZU_xd:
1110    case FCVTZU_ws:
1111    case FCVTZU_wd:
1112    case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1113    case FCVTZS_xd:
1114    case FCVTZS_wd:
1115    case FCVTZS_xs:
1116    case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1117    case SCVTF_sw:
1118    case SCVTF_sx:
1119    case SCVTF_dw:
1120    case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1121    case UCVTF_sw:
1122    case UCVTF_sx:
1123    case UCVTF_dw:
1124    case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1125  }
1126  Format(instr, mnemonic, form);
1127}
1128
1129
1130void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
1131  const char *mnemonic = "";
1132  const char *form = "'Rd, 'Fn, 'IFPFBits";
1133  const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1134
1135  switch (instr->Mask(FPFixedPointConvertMask)) {
1136    case FCVTZS_ws_fixed:
1137    case FCVTZS_xs_fixed:
1138    case FCVTZS_wd_fixed:
1139    case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1140    case FCVTZU_ws_fixed:
1141    case FCVTZU_xs_fixed:
1142    case FCVTZU_wd_fixed:
1143    case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1144    case SCVTF_sw_fixed:
1145    case SCVTF_sx_fixed:
1146    case SCVTF_dw_fixed:
1147    case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1148    case UCVTF_sw_fixed:
1149    case UCVTF_sx_fixed:
1150    case UCVTF_dw_fixed:
1151    case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1152    default: VIXL_UNREACHABLE();
1153  }
1154  Format(instr, mnemonic, form);
1155}
1156
1157
1158void Disassembler::VisitSystem(Instruction* instr) {
1159  // Some system instructions hijack their Op and Cp fields to represent a
1160  // range of immediates instead of indicating a different instruction. This
1161  // makes the decoding tricky.
1162  const char *mnemonic = "unimplemented";
1163  const char *form = "(System)";
1164
1165  if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1166    switch (instr->Mask(SystemSysRegMask)) {
1167      case MRS: {
1168        mnemonic = "mrs";
1169        switch (instr->ImmSystemRegister()) {
1170          case NZCV: form = "'Xt, nzcv"; break;
1171          case FPCR: form = "'Xt, fpcr"; break;
1172          default: form = "'Xt, (unknown)"; break;
1173        }
1174        break;
1175      }
1176      case MSR: {
1177        mnemonic = "msr";
1178        switch (instr->ImmSystemRegister()) {
1179          case NZCV: form = "nzcv, 'Xt"; break;
1180          case FPCR: form = "fpcr, 'Xt"; break;
1181          default: form = "(unknown), 'Xt"; break;
1182        }
1183        break;
1184      }
1185    }
1186  } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1187    VIXL_ASSERT(instr->Mask(SystemHintMask) == HINT);
1188    switch (instr->ImmHint()) {
1189      case NOP: {
1190        mnemonic = "nop";
1191        form = NULL;
1192        break;
1193      }
1194    }
1195  } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1196    switch (instr->Mask(MemBarrierMask)) {
1197      case DMB: {
1198        mnemonic = "dmb";
1199        form = "'M";
1200        break;
1201      }
1202      case DSB: {
1203        mnemonic = "dsb";
1204        form = "'M";
1205        break;
1206      }
1207      case ISB: {
1208        mnemonic = "isb";
1209        form = NULL;
1210        break;
1211      }
1212    }
1213  }
1214
1215  Format(instr, mnemonic, form);
1216}
1217
1218
1219void Disassembler::VisitException(Instruction* instr) {
1220  const char *mnemonic = "unimplemented";
1221  const char *form = "'IDebug";
1222
1223  switch (instr->Mask(ExceptionMask)) {
1224    case HLT: mnemonic = "hlt"; break;
1225    case BRK: mnemonic = "brk"; break;
1226    case SVC: mnemonic = "svc"; break;
1227    case HVC: mnemonic = "hvc"; break;
1228    case SMC: mnemonic = "smc"; break;
1229    case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1230    case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1231    case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1232    default: form = "(Exception)";
1233  }
1234  Format(instr, mnemonic, form);
1235}
1236
1237
1238void Disassembler::VisitUnimplemented(Instruction* instr) {
1239  Format(instr, "unimplemented", "(Unimplemented)");
1240}
1241
1242
1243void Disassembler::VisitUnallocated(Instruction* instr) {
1244  Format(instr, "unallocated", "(Unallocated)");
1245}
1246
1247
1248void Disassembler::ProcessOutput(Instruction* /*instr*/) {
1249  // The base disasm does nothing more than disassembling into a buffer.
1250}
1251
1252
1253void Disassembler::Format(Instruction* instr, const char* mnemonic,
1254                          const char* format) {
1255  VIXL_ASSERT(mnemonic != NULL);
1256  ResetOutput();
1257  Substitute(instr, mnemonic);
1258  if (format != NULL) {
1259    buffer_[buffer_pos_++] = ' ';
1260    Substitute(instr, format);
1261  }
1262  buffer_[buffer_pos_] = 0;
1263  ProcessOutput(instr);
1264}
1265
1266
1267void Disassembler::Substitute(Instruction* instr, const char* string) {
1268  char chr = *string++;
1269  while (chr != '\0') {
1270    if (chr == '\'') {
1271      string += SubstituteField(instr, string);
1272    } else {
1273      buffer_[buffer_pos_++] = chr;
1274    }
1275    chr = *string++;
1276  }
1277}
1278
1279
1280int Disassembler::SubstituteField(Instruction* instr, const char* format) {
1281  switch (format[0]) {
1282    case 'R':  // Register. X or W, selected by sf bit.
1283    case 'F':  // FP Register. S or D, selected by type field.
1284    case 'W':
1285    case 'X':
1286    case 'S':
1287    case 'D': return SubstituteRegisterField(instr, format);
1288    case 'I': return SubstituteImmediateField(instr, format);
1289    case 'L': return SubstituteLiteralField(instr, format);
1290    case 'H': return SubstituteShiftField(instr, format);
1291    case 'P': return SubstitutePrefetchField(instr, format);
1292    case 'C': return SubstituteConditionField(instr, format);
1293    case 'E': return SubstituteExtendField(instr, format);
1294    case 'A': return SubstitutePCRelAddressField(instr, format);
1295    case 'B': return SubstituteBranchTargetField(instr, format);
1296    case 'O': return SubstituteLSRegOffsetField(instr, format);
1297    case 'M': return SubstituteBarrierField(instr, format);
1298    default: {
1299      VIXL_UNREACHABLE();
1300      return 1;
1301    }
1302  }
1303}
1304
1305
1306int Disassembler::SubstituteRegisterField(Instruction* instr,
1307                                          const char* format) {
1308  unsigned reg_num = 0;
1309  unsigned field_len = 2;
1310  switch (format[1]) {
1311    case 'd': reg_num = instr->Rd(); break;
1312    case 'n': reg_num = instr->Rn(); break;
1313    case 'm': reg_num = instr->Rm(); break;
1314    case 'a': reg_num = instr->Ra(); break;
1315    case 't': {
1316      if (format[2] == '2') {
1317        reg_num = instr->Rt2();
1318        field_len = 3;
1319      } else {
1320        reg_num = instr->Rt();
1321      }
1322      break;
1323    }
1324    default: VIXL_UNREACHABLE();
1325  }
1326
1327  // Increase field length for registers tagged as stack.
1328  if (format[2] == 's') {
1329    field_len = 3;
1330  }
1331
1332  char reg_type;
1333  if (format[0] == 'R') {
1334    // Register type is R: use sf bit to choose X and W.
1335    reg_type = instr->SixtyFourBits() ? 'x' : 'w';
1336  } else if (format[0] == 'F') {
1337    // Floating-point register: use type field to choose S or D.
1338    reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
1339  } else {
1340    // Register type is specified. Make it lower case.
1341    reg_type = format[0] + 0x20;
1342  }
1343
1344  if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
1345    // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
1346    AppendToOutput("%c%d", reg_type, reg_num);
1347  } else if (format[2] == 's') {
1348    // Disassemble w31/x31 as stack pointer wsp/sp.
1349    AppendToOutput("%s", (reg_type == 'w') ? "wsp" : "sp");
1350  } else {
1351    // Disassemble w31/x31 as zero register wzr/xzr.
1352    AppendToOutput("%czr", reg_type);
1353  }
1354
1355  return field_len;
1356}
1357
1358
1359int Disassembler::SubstituteImmediateField(Instruction* instr,
1360                                           const char* format) {
1361  VIXL_ASSERT(format[0] == 'I');
1362
1363  switch (format[1]) {
1364    case 'M': {  // IMoveImm or IMoveLSL.
1365      if (format[5] == 'I') {
1366        uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
1367        AppendToOutput("#0x%" PRIx64, imm);
1368      } else {
1369        VIXL_ASSERT(format[5] == 'L');
1370        AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
1371        if (instr->ShiftMoveWide() > 0) {
1372          AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
1373        }
1374      }
1375      return 8;
1376    }
1377    case 'L': {
1378      switch (format[2]) {
1379        case 'L': {  // ILLiteral - Immediate Load Literal.
1380          AppendToOutput("pc%+" PRId64,
1381                         instr->ImmLLiteral() << kLiteralEntrySizeLog2);
1382          return 9;
1383        }
1384        case 'S': {  // ILS - Immediate Load/Store.
1385          if (instr->ImmLS() != 0) {
1386            AppendToOutput(", #%" PRId64, instr->ImmLS());
1387          }
1388          return 3;
1389        }
1390        case 'P': {  // ILPx - Immediate Load/Store Pair, x = access size.
1391          if (instr->ImmLSPair() != 0) {
1392            // format[3] is the scale value. Convert to a number.
1393            int scale = format[3] - 0x30;
1394            AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale);
1395          }
1396          return 4;
1397        }
1398        case 'U': {  // ILU - Immediate Load/Store Unsigned.
1399          if (instr->ImmLSUnsigned() != 0) {
1400            AppendToOutput(", #%" PRIu64,
1401                           instr->ImmLSUnsigned() << instr->SizeLS());
1402          }
1403          return 3;
1404        }
1405      }
1406    }
1407    case 'C': {  // ICondB - Immediate Conditional Branch.
1408      int64_t offset = instr->ImmCondBranch() << 2;
1409      char sign = (offset >= 0) ? '+' : '-';
1410      AppendToOutput("#%c0x%" PRIx64, sign, offset);
1411      return 6;
1412    }
1413    case 'A': {  // IAddSub.
1414      VIXL_ASSERT(instr->ShiftAddSub() <= 1);
1415      int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
1416      AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
1417      return 7;
1418    }
1419    case 'F': {  // IFPSingle, IFPDouble or IFPFBits.
1420      if (format[3] == 'F') {  // IFPFbits.
1421        AppendToOutput("#%d", 64 - instr->FPScale());
1422        return 8;
1423      } else {
1424        AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
1425                       format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
1426        return 9;
1427      }
1428    }
1429    case 'T': {  // ITri - Immediate Triangular Encoded.
1430      AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
1431      return 4;
1432    }
1433    case 'N': {  // INzcv.
1434      int nzcv = (instr->Nzcv() << Flags_offset);
1435      AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
1436                                  ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
1437                                  ((nzcv & CFlag) == 0) ? 'c' : 'C',
1438                                  ((nzcv & VFlag) == 0) ? 'v' : 'V');
1439      return 5;
1440    }
1441    case 'P': {  // IP - Conditional compare.
1442      AppendToOutput("#%d", instr->ImmCondCmp());
1443      return 2;
1444    }
1445    case 'B': {  // Bitfields.
1446      return SubstituteBitfieldImmediateField(instr, format);
1447    }
1448    case 'E': {  // IExtract.
1449      AppendToOutput("#%d", instr->ImmS());
1450      return 8;
1451    }
1452    case 'S': {  // IS - Test and branch bit.
1453      AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
1454                            instr->ImmTestBranchBit40());
1455      return 2;
1456    }
1457    case 'D': {  // IDebug - HLT and BRK instructions.
1458      AppendToOutput("#0x%x", instr->ImmException());
1459      return 6;
1460    }
1461    default: {
1462      VIXL_UNIMPLEMENTED();
1463      return 0;
1464    }
1465  }
1466}
1467
1468
1469int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
1470                                                   const char* format) {
1471  VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
1472  unsigned r = instr->ImmR();
1473  unsigned s = instr->ImmS();
1474
1475  switch (format[2]) {
1476    case 'r': {  // IBr.
1477      AppendToOutput("#%d", r);
1478      return 3;
1479    }
1480    case 's': {  // IBs+1 or IBs-r+1.
1481      if (format[3] == '+') {
1482        AppendToOutput("#%d", s + 1);
1483        return 5;
1484      } else {
1485        VIXL_ASSERT(format[3] == '-');
1486        AppendToOutput("#%d", s - r + 1);
1487        return 7;
1488      }
1489    }
1490    case 'Z': {  // IBZ-r.
1491      VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));
1492      unsigned reg_size = (instr->SixtyFourBits() != 0) ? kXRegSize : kWRegSize;
1493      AppendToOutput("#%d", reg_size - r);
1494      return 5;
1495    }
1496    default: {
1497      VIXL_UNREACHABLE();
1498      return 0;
1499    }
1500  }
1501}
1502
1503
1504int Disassembler::SubstituteLiteralField(Instruction* instr,
1505                                         const char* format) {
1506  VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
1507  USE(format);
1508
1509  switch (instr->Mask(LoadLiteralMask)) {
1510    case LDR_w_lit:
1511    case LDR_x_lit:
1512    case LDR_s_lit:
1513    case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
1514    default: VIXL_UNREACHABLE();
1515  }
1516
1517  return 6;
1518}
1519
1520
1521int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
1522  VIXL_ASSERT(format[0] == 'H');
1523  VIXL_ASSERT(instr->ShiftDP() <= 0x3);
1524
1525  switch (format[1]) {
1526    case 'D': {  // HDP.
1527      VIXL_ASSERT(instr->ShiftDP() != ROR);
1528    }  // Fall through.
1529    case 'L': {  // HLo.
1530      if (instr->ImmDPShift() != 0) {
1531        const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
1532        AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()],
1533                       instr->ImmDPShift());
1534      }
1535      return 3;
1536    }
1537    default:
1538      VIXL_UNIMPLEMENTED();
1539      return 0;
1540  }
1541}
1542
1543
1544int Disassembler::SubstituteConditionField(Instruction* instr,
1545                                           const char* format) {
1546  VIXL_ASSERT(format[0] == 'C');
1547  const char* condition_code[] = { "eq", "ne", "hs", "lo",
1548                                   "mi", "pl", "vs", "vc",
1549                                   "hi", "ls", "ge", "lt",
1550                                   "gt", "le", "al", "nv" };
1551  int cond;
1552  switch (format[1]) {
1553    case 'B': cond = instr->ConditionBranch(); break;
1554    case 'I': {
1555      cond = InvertCondition(static_cast<Condition>(instr->Condition()));
1556      break;
1557    }
1558    default: cond = instr->Condition();
1559  }
1560  AppendToOutput("%s", condition_code[cond]);
1561  return 4;
1562}
1563
1564
1565int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
1566                                              const char* format) {
1567  USE(format);
1568  VIXL_ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
1569
1570  int offset = instr->ImmPCRel();
1571
1572  // Only ADR (AddrPCRelByte) is supported.
1573  VIXL_ASSERT(strcmp(format, "AddrPCRelByte") == 0);
1574
1575  char sign = '+';
1576  if (offset < 0) {
1577    offset = -offset;
1578    sign = '-';
1579  }
1580  VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
1581  AppendToOutput("#%c0x%x (addr %p)", sign, offset, instr + offset);
1582  return 13;
1583}
1584
1585
1586int Disassembler::SubstituteBranchTargetField(Instruction* instr,
1587                                              const char* format) {
1588  VIXL_ASSERT(strncmp(format, "BImm", 4) == 0);
1589
1590  int64_t offset = 0;
1591  switch (format[5]) {
1592    // BImmUncn - unconditional branch immediate.
1593    case 'n': offset = instr->ImmUncondBranch(); break;
1594    // BImmCond - conditional branch immediate.
1595    case 'o': offset = instr->ImmCondBranch(); break;
1596    // BImmCmpa - compare and branch immediate.
1597    case 'm': offset = instr->ImmCmpBranch(); break;
1598    // BImmTest - test and branch immediate.
1599    case 'e': offset = instr->ImmTestBranch(); break;
1600    default: VIXL_UNIMPLEMENTED();
1601  }
1602  offset <<= kInstructionSizeLog2;
1603  char sign = '+';
1604  if (offset < 0) {
1605    offset = -offset;
1606    sign = '-';
1607  }
1608  VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
1609  AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, offset, instr + offset);
1610  return 8;
1611}
1612
1613
1614int Disassembler::SubstituteExtendField(Instruction* instr,
1615                                        const char* format) {
1616  VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
1617  VIXL_ASSERT(instr->ExtendMode() <= 7);
1618  USE(format);
1619
1620  const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
1621                                "sxtb", "sxth", "sxtw", "sxtx" };
1622
1623  // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
1624  // registers becomes lsl.
1625  if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
1626      (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
1627       (instr->ExtendMode() == UXTX))) {
1628    if (instr->ImmExtendShift() > 0) {
1629      AppendToOutput(", lsl #%d", instr->ImmExtendShift());
1630    }
1631  } else {
1632    AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
1633    if (instr->ImmExtendShift() > 0) {
1634      AppendToOutput(" #%d", instr->ImmExtendShift());
1635    }
1636  }
1637  return 3;
1638}
1639
1640
1641int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
1642                                             const char* format) {
1643  VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
1644  const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
1645                                "undefined", "undefined", "sxtw", "sxtx" };
1646  USE(format);
1647
1648  unsigned shift = instr->ImmShiftLS();
1649  Extend ext = static_cast<Extend>(instr->ExtendMode());
1650  char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
1651
1652  unsigned rm = instr->Rm();
1653  if (rm == kZeroRegCode) {
1654    AppendToOutput("%czr", reg_type);
1655  } else {
1656    AppendToOutput("%c%d", reg_type, rm);
1657  }
1658
1659  // Extend mode UXTX is an alias for shift mode LSL here.
1660  if (!((ext == UXTX) && (shift == 0))) {
1661    AppendToOutput(", %s", extend_mode[ext]);
1662    if (shift != 0) {
1663      AppendToOutput(" #%d", instr->SizeLS());
1664    }
1665  }
1666  return 9;
1667}
1668
1669
1670int Disassembler::SubstitutePrefetchField(Instruction* instr,
1671                                          const char* format) {
1672  VIXL_ASSERT(format[0] == 'P');
1673  USE(format);
1674
1675  int prefetch_mode = instr->PrefetchMode();
1676
1677  const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
1678  int level = (prefetch_mode >> 1) + 1;
1679  const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
1680
1681  AppendToOutput("p%sl%d%s", ls, level, ks);
1682  return 6;
1683}
1684
1685int Disassembler::SubstituteBarrierField(Instruction* instr,
1686                                         const char* format) {
1687  VIXL_ASSERT(format[0] == 'M');
1688  USE(format);
1689
1690  static const char* options[4][4] = {
1691    { "sy (0b0000)", "oshld", "oshst", "osh" },
1692    { "sy (0b0100)", "nshld", "nshst", "nsh" },
1693    { "sy (0b1000)", "ishld", "ishst", "ish" },
1694    { "sy (0b1100)", "ld", "st", "sy" }
1695  };
1696  int domain = instr->ImmBarrierDomain();
1697  int type = instr->ImmBarrierType();
1698
1699  AppendToOutput("%s", options[domain][type]);
1700  return 1;
1701}
1702
1703void Disassembler::ResetOutput() {
1704  buffer_pos_ = 0;
1705  buffer_[buffer_pos_] = 0;
1706}
1707
1708
1709void Disassembler::AppendToOutput(const char* format, ...) {
1710  va_list args;
1711  va_start(args, format);
1712  buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
1713  va_end(args);
1714}
1715
1716
1717void PrintDisassembler::ProcessOutput(Instruction* instr) {
1718  fprintf(stream_, "0x%016" PRIx64 "  %08" PRIx32 "\t\t%s\n",
1719          reinterpret_cast<uint64_t>(instr),
1720          instr->InstructionBits(),
1721          GetOutput());
1722}
1723}  // namespace vixl
1724