cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

disasm-a64.cc (118972B)


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