Path: blob/master/dep/vixl/src/aarch64/disasm-aarch64.cc
4261 views
// Copyright 2015, VIXL authors1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are met:5//6// * Redistributions of source code must retain the above copyright notice,7// this list of conditions and the following disclaimer.8// * Redistributions in binary form must reproduce the above copyright notice,9// this list of conditions and the following disclaimer in the documentation10// and/or other materials provided with the distribution.11// * Neither the name of ARM Limited nor the names of its contributors may be12// used to endorse or promote products derived from this software without13// specific prior written permission.14//15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE19// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR21// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER22// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,23// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE24// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2526#include "disasm-aarch64.h"2728#include <bitset>29#include <cstdlib>30#include <sstream>3132namespace vixl {33namespace aarch64 {3435const Disassembler::FormToVisitorFnMap *Disassembler::GetFormToVisitorFnMap() {36static const FormToVisitorFnMap form_to_visitor = {37DEFAULT_FORM_TO_VISITOR_MAP(Disassembler),38{"autia1716_hi_hints"_h, &Disassembler::DisassembleNoArgs},39{"autiasp_hi_hints"_h, &Disassembler::DisassembleNoArgs},40{"autiaz_hi_hints"_h, &Disassembler::DisassembleNoArgs},41{"autib1716_hi_hints"_h, &Disassembler::DisassembleNoArgs},42{"autibsp_hi_hints"_h, &Disassembler::DisassembleNoArgs},43{"autibz_hi_hints"_h, &Disassembler::DisassembleNoArgs},44{"axflag_m_pstate"_h, &Disassembler::DisassembleNoArgs},45{"cfinv_m_pstate"_h, &Disassembler::DisassembleNoArgs},46{"csdb_hi_hints"_h, &Disassembler::DisassembleNoArgs},47{"dgh_hi_hints"_h, &Disassembler::DisassembleNoArgs},48{"ssbb_only_barriers"_h, &Disassembler::DisassembleNoArgs},49{"esb_hi_hints"_h, &Disassembler::DisassembleNoArgs},50{"isb_bi_barriers"_h, &Disassembler::DisassembleNoArgs},51{"nop_hi_hints"_h, &Disassembler::DisassembleNoArgs},52{"pacia1716_hi_hints"_h, &Disassembler::DisassembleNoArgs},53{"paciasp_hi_hints"_h, &Disassembler::DisassembleNoArgs},54{"paciaz_hi_hints"_h, &Disassembler::DisassembleNoArgs},55{"pacib1716_hi_hints"_h, &Disassembler::DisassembleNoArgs},56{"pacibsp_hi_hints"_h, &Disassembler::DisassembleNoArgs},57{"pacibz_hi_hints"_h, &Disassembler::DisassembleNoArgs},58{"sev_hi_hints"_h, &Disassembler::DisassembleNoArgs},59{"sevl_hi_hints"_h, &Disassembler::DisassembleNoArgs},60{"wfe_hi_hints"_h, &Disassembler::DisassembleNoArgs},61{"wfi_hi_hints"_h, &Disassembler::DisassembleNoArgs},62{"xaflag_m_pstate"_h, &Disassembler::DisassembleNoArgs},63{"xpaclri_hi_hints"_h, &Disassembler::DisassembleNoArgs},64{"yield_hi_hints"_h, &Disassembler::DisassembleNoArgs},65{"abs_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},66{"cls_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},67{"clz_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},68{"cnt_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},69{"neg_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},70{"rev16_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},71{"rev32_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},72{"rev64_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},73{"sqabs_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},74{"sqneg_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},75{"suqadd_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},76{"urecpe_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},77{"ursqrte_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},78{"usqadd_asimdmisc_r"_h, &Disassembler::VisitNEON2RegMisc},79{"not_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegLogical},80{"rbit_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegLogical},81{"xtn_asimdmisc_n"_h, &Disassembler::DisassembleNEON2RegExtract},82{"sqxtn_asimdmisc_n"_h, &Disassembler::DisassembleNEON2RegExtract},83{"uqxtn_asimdmisc_n"_h, &Disassembler::DisassembleNEON2RegExtract},84{"sqxtun_asimdmisc_n"_h, &Disassembler::DisassembleNEON2RegExtract},85{"shll_asimdmisc_s"_h, &Disassembler::DisassembleNEON2RegExtract},86{"sadalp_asimdmisc_p"_h, &Disassembler::DisassembleNEON2RegAddlp},87{"saddlp_asimdmisc_p"_h, &Disassembler::DisassembleNEON2RegAddlp},88{"uadalp_asimdmisc_p"_h, &Disassembler::DisassembleNEON2RegAddlp},89{"uaddlp_asimdmisc_p"_h, &Disassembler::DisassembleNEON2RegAddlp},90{"cmeq_asimdmisc_z"_h, &Disassembler::DisassembleNEON2RegCompare},91{"cmge_asimdmisc_z"_h, &Disassembler::DisassembleNEON2RegCompare},92{"cmgt_asimdmisc_z"_h, &Disassembler::DisassembleNEON2RegCompare},93{"cmle_asimdmisc_z"_h, &Disassembler::DisassembleNEON2RegCompare},94{"cmlt_asimdmisc_z"_h, &Disassembler::DisassembleNEON2RegCompare},95{"fcmeq_asimdmisc_fz"_h, &Disassembler::DisassembleNEON2RegFPCompare},96{"fcmge_asimdmisc_fz"_h, &Disassembler::DisassembleNEON2RegFPCompare},97{"fcmgt_asimdmisc_fz"_h, &Disassembler::DisassembleNEON2RegFPCompare},98{"fcmle_asimdmisc_fz"_h, &Disassembler::DisassembleNEON2RegFPCompare},99{"fcmlt_asimdmisc_fz"_h, &Disassembler::DisassembleNEON2RegFPCompare},100{"fcvtl_asimdmisc_l"_h, &Disassembler::DisassembleNEON2RegFPConvert},101{"fcvtn_asimdmisc_n"_h, &Disassembler::DisassembleNEON2RegFPConvert},102{"fcvtxn_asimdmisc_n"_h, &Disassembler::DisassembleNEON2RegFPConvert},103{"fabs_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},104{"fcvtas_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},105{"fcvtau_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},106{"fcvtms_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},107{"fcvtmu_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},108{"fcvtns_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},109{"fcvtnu_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},110{"fcvtps_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},111{"fcvtpu_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},112{"fcvtzs_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},113{"fcvtzu_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},114{"fneg_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},115{"frecpe_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},116{"frint32x_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},117{"frint32z_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},118{"frint64x_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},119{"frint64z_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},120{"frinta_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},121{"frinti_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},122{"frintm_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},123{"frintn_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},124{"frintp_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},125{"frintx_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},126{"frintz_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},127{"frsqrte_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},128{"fsqrt_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},129{"scvtf_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},130{"ucvtf_asimdmisc_r"_h, &Disassembler::DisassembleNEON2RegFP},131{"smlal_asimdelem_l"_h, &Disassembler::DisassembleNEONMulByElementLong},132{"smlsl_asimdelem_l"_h, &Disassembler::DisassembleNEONMulByElementLong},133{"smull_asimdelem_l"_h, &Disassembler::DisassembleNEONMulByElementLong},134{"umlal_asimdelem_l"_h, &Disassembler::DisassembleNEONMulByElementLong},135{"umlsl_asimdelem_l"_h, &Disassembler::DisassembleNEONMulByElementLong},136{"umull_asimdelem_l"_h, &Disassembler::DisassembleNEONMulByElementLong},137{"sqdmull_asimdelem_l"_h, &Disassembler::DisassembleNEONMulByElementLong},138{"sqdmlal_asimdelem_l"_h, &Disassembler::DisassembleNEONMulByElementLong},139{"sqdmlsl_asimdelem_l"_h, &Disassembler::DisassembleNEONMulByElementLong},140{"sdot_asimdelem_d"_h, &Disassembler::DisassembleNEONDotProdByElement},141{"udot_asimdelem_d"_h, &Disassembler::DisassembleNEONDotProdByElement},142{"usdot_asimdelem_d"_h, &Disassembler::DisassembleNEONDotProdByElement},143{"sudot_asimdelem_d"_h, &Disassembler::DisassembleNEONDotProdByElement},144{"fmlal2_asimdelem_lh"_h,145&Disassembler::DisassembleNEONFPMulByElementLong},146{"fmlal_asimdelem_lh"_h,147&Disassembler::DisassembleNEONFPMulByElementLong},148{"fmlsl2_asimdelem_lh"_h,149&Disassembler::DisassembleNEONFPMulByElementLong},150{"fmlsl_asimdelem_lh"_h,151&Disassembler::DisassembleNEONFPMulByElementLong},152{"fcmla_asimdelem_c_h"_h,153&Disassembler::DisassembleNEONComplexMulByElement},154{"fcmla_asimdelem_c_s"_h,155&Disassembler::DisassembleNEONComplexMulByElement},156{"fmla_asimdelem_rh_h"_h,157&Disassembler::DisassembleNEONHalfFPMulByElement},158{"fmls_asimdelem_rh_h"_h,159&Disassembler::DisassembleNEONHalfFPMulByElement},160{"fmulx_asimdelem_rh_h"_h,161&Disassembler::DisassembleNEONHalfFPMulByElement},162{"fmul_asimdelem_rh_h"_h,163&Disassembler::DisassembleNEONHalfFPMulByElement},164{"fmla_asimdelem_r_sd"_h, &Disassembler::DisassembleNEONFPMulByElement},165{"fmls_asimdelem_r_sd"_h, &Disassembler::DisassembleNEONFPMulByElement},166{"fmulx_asimdelem_r_sd"_h, &Disassembler::DisassembleNEONFPMulByElement},167{"fmul_asimdelem_r_sd"_h, &Disassembler::DisassembleNEONFPMulByElement},168{"mla_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},169{"mls_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},170{"mul_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},171{"saba_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},172{"sabd_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},173{"shadd_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},174{"shsub_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},175{"smaxp_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},176{"smax_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},177{"sminp_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},178{"smin_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},179{"srhadd_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},180{"uaba_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},181{"uabd_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},182{"uhadd_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},183{"uhsub_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},184{"umaxp_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},185{"umax_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},186{"uminp_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},187{"umin_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},188{"urhadd_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameNoD},189{"and_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameLogical},190{"bic_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameLogical},191{"bif_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameLogical},192{"bit_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameLogical},193{"bsl_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameLogical},194{"eor_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameLogical},195{"orr_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameLogical},196{"orn_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameLogical},197{"pmul_asimdsame_only"_h, &Disassembler::DisassembleNEON3SameLogical},198{"fmlal2_asimdsame_f"_h, &Disassembler::DisassembleNEON3SameFHM},199{"fmlal_asimdsame_f"_h, &Disassembler::DisassembleNEON3SameFHM},200{"fmlsl2_asimdsame_f"_h, &Disassembler::DisassembleNEON3SameFHM},201{"fmlsl_asimdsame_f"_h, &Disassembler::DisassembleNEON3SameFHM},202{"sri_asimdshf_r"_h, &Disassembler::DisassembleNEONShiftRightImm},203{"srshr_asimdshf_r"_h, &Disassembler::DisassembleNEONShiftRightImm},204{"srsra_asimdshf_r"_h, &Disassembler::DisassembleNEONShiftRightImm},205{"sshr_asimdshf_r"_h, &Disassembler::DisassembleNEONShiftRightImm},206{"ssra_asimdshf_r"_h, &Disassembler::DisassembleNEONShiftRightImm},207{"urshr_asimdshf_r"_h, &Disassembler::DisassembleNEONShiftRightImm},208{"ursra_asimdshf_r"_h, &Disassembler::DisassembleNEONShiftRightImm},209{"ushr_asimdshf_r"_h, &Disassembler::DisassembleNEONShiftRightImm},210{"usra_asimdshf_r"_h, &Disassembler::DisassembleNEONShiftRightImm},211{"scvtf_asimdshf_c"_h, &Disassembler::DisassembleNEONShiftRightImm},212{"ucvtf_asimdshf_c"_h, &Disassembler::DisassembleNEONShiftRightImm},213{"fcvtzs_asimdshf_c"_h, &Disassembler::DisassembleNEONShiftRightImm},214{"fcvtzu_asimdshf_c"_h, &Disassembler::DisassembleNEONShiftRightImm},215{"ushll_asimdshf_l"_h, &Disassembler::DisassembleNEONShiftLeftLongImm},216{"sshll_asimdshf_l"_h, &Disassembler::DisassembleNEONShiftLeftLongImm},217{"shrn_asimdshf_n"_h, &Disassembler::DisassembleNEONShiftRightNarrowImm},218{"rshrn_asimdshf_n"_h, &Disassembler::DisassembleNEONShiftRightNarrowImm},219{"sqshrn_asimdshf_n"_h,220&Disassembler::DisassembleNEONShiftRightNarrowImm},221{"sqrshrn_asimdshf_n"_h,222&Disassembler::DisassembleNEONShiftRightNarrowImm},223{"sqshrun_asimdshf_n"_h,224&Disassembler::DisassembleNEONShiftRightNarrowImm},225{"sqrshrun_asimdshf_n"_h,226&Disassembler::DisassembleNEONShiftRightNarrowImm},227{"uqshrn_asimdshf_n"_h,228&Disassembler::DisassembleNEONShiftRightNarrowImm},229{"uqrshrn_asimdshf_n"_h,230&Disassembler::DisassembleNEONShiftRightNarrowImm},231{"sqdmlal_asisdelem_l"_h,232&Disassembler::DisassembleNEONScalarSatMulLongIndex},233{"sqdmlsl_asisdelem_l"_h,234&Disassembler::DisassembleNEONScalarSatMulLongIndex},235{"sqdmull_asisdelem_l"_h,236&Disassembler::DisassembleNEONScalarSatMulLongIndex},237{"fmla_asisdelem_rh_h"_h, &Disassembler::DisassembleNEONFPScalarMulIndex},238{"fmla_asisdelem_r_sd"_h, &Disassembler::DisassembleNEONFPScalarMulIndex},239{"fmls_asisdelem_rh_h"_h, &Disassembler::DisassembleNEONFPScalarMulIndex},240{"fmls_asisdelem_r_sd"_h, &Disassembler::DisassembleNEONFPScalarMulIndex},241{"fmulx_asisdelem_rh_h"_h,242&Disassembler::DisassembleNEONFPScalarMulIndex},243{"fmulx_asisdelem_r_sd"_h,244&Disassembler::DisassembleNEONFPScalarMulIndex},245{"fmul_asisdelem_rh_h"_h, &Disassembler::DisassembleNEONFPScalarMulIndex},246{"fmul_asisdelem_r_sd"_h, &Disassembler::DisassembleNEONFPScalarMulIndex},247{"fabd_asisdsame_only"_h, &Disassembler::DisassembleNEONFPScalar3Same},248{"facge_asisdsame_only"_h, &Disassembler::DisassembleNEONFPScalar3Same},249{"facgt_asisdsame_only"_h, &Disassembler::DisassembleNEONFPScalar3Same},250{"fcmeq_asisdsame_only"_h, &Disassembler::DisassembleNEONFPScalar3Same},251{"fcmge_asisdsame_only"_h, &Disassembler::DisassembleNEONFPScalar3Same},252{"fcmgt_asisdsame_only"_h, &Disassembler::DisassembleNEONFPScalar3Same},253{"fmulx_asisdsame_only"_h, &Disassembler::DisassembleNEONFPScalar3Same},254{"frecps_asisdsame_only"_h, &Disassembler::DisassembleNEONFPScalar3Same},255{"frsqrts_asisdsame_only"_h, &Disassembler::DisassembleNEONFPScalar3Same},256{"sqrdmlah_asisdsame2_only"_h, &Disassembler::VisitNEONScalar3Same},257{"sqrdmlsh_asisdsame2_only"_h, &Disassembler::VisitNEONScalar3Same},258{"cmeq_asisdsame_only"_h, &Disassembler::DisassembleNEONScalar3SameOnlyD},259{"cmge_asisdsame_only"_h, &Disassembler::DisassembleNEONScalar3SameOnlyD},260{"cmgt_asisdsame_only"_h, &Disassembler::DisassembleNEONScalar3SameOnlyD},261{"cmhi_asisdsame_only"_h, &Disassembler::DisassembleNEONScalar3SameOnlyD},262{"cmhs_asisdsame_only"_h, &Disassembler::DisassembleNEONScalar3SameOnlyD},263{"cmtst_asisdsame_only"_h,264&Disassembler::DisassembleNEONScalar3SameOnlyD},265{"add_asisdsame_only"_h, &Disassembler::DisassembleNEONScalar3SameOnlyD},266{"sub_asisdsame_only"_h, &Disassembler::DisassembleNEONScalar3SameOnlyD},267{"fmaxnmv_asimdall_only_h"_h,268&Disassembler::DisassembleNEONFP16AcrossLanes},269{"fmaxv_asimdall_only_h"_h,270&Disassembler::DisassembleNEONFP16AcrossLanes},271{"fminnmv_asimdall_only_h"_h,272&Disassembler::DisassembleNEONFP16AcrossLanes},273{"fminv_asimdall_only_h"_h,274&Disassembler::DisassembleNEONFP16AcrossLanes},275{"fmaxnmv_asimdall_only_sd"_h,276&Disassembler::DisassembleNEONFPAcrossLanes},277{"fminnmv_asimdall_only_sd"_h,278&Disassembler::DisassembleNEONFPAcrossLanes},279{"fmaxv_asimdall_only_sd"_h, &Disassembler::DisassembleNEONFPAcrossLanes},280{"fminv_asimdall_only_sd"_h, &Disassembler::DisassembleNEONFPAcrossLanes},281{"shl_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},282{"sli_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},283{"sri_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},284{"srshr_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},285{"srsra_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},286{"sshr_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},287{"ssra_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},288{"urshr_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},289{"ursra_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},290{"ushr_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},291{"usra_asisdshf_r"_h, &Disassembler::DisassembleNEONScalarShiftImmOnlyD},292{"sqrshrn_asisdshf_n"_h,293&Disassembler::DisassembleNEONScalarShiftRightNarrowImm},294{"sqrshrun_asisdshf_n"_h,295&Disassembler::DisassembleNEONScalarShiftRightNarrowImm},296{"sqshrn_asisdshf_n"_h,297&Disassembler::DisassembleNEONScalarShiftRightNarrowImm},298{"sqshrun_asisdshf_n"_h,299&Disassembler::DisassembleNEONScalarShiftRightNarrowImm},300{"uqrshrn_asisdshf_n"_h,301&Disassembler::DisassembleNEONScalarShiftRightNarrowImm},302{"uqshrn_asisdshf_n"_h,303&Disassembler::DisassembleNEONScalarShiftRightNarrowImm},304{"cmeq_asisdmisc_z"_h, &Disassembler::DisassembleNEONScalar2RegMiscOnlyD},305{"cmge_asisdmisc_z"_h, &Disassembler::DisassembleNEONScalar2RegMiscOnlyD},306{"cmgt_asisdmisc_z"_h, &Disassembler::DisassembleNEONScalar2RegMiscOnlyD},307{"cmle_asisdmisc_z"_h, &Disassembler::DisassembleNEONScalar2RegMiscOnlyD},308{"cmlt_asisdmisc_z"_h, &Disassembler::DisassembleNEONScalar2RegMiscOnlyD},309{"abs_asisdmisc_r"_h, &Disassembler::DisassembleNEONScalar2RegMiscOnlyD},310{"neg_asisdmisc_r"_h, &Disassembler::DisassembleNEONScalar2RegMiscOnlyD},311{"fcmeq_asisdmisc_fz"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},312{"fcmge_asisdmisc_fz"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},313{"fcmgt_asisdmisc_fz"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},314{"fcmle_asisdmisc_fz"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},315{"fcmlt_asisdmisc_fz"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},316{"fcvtas_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},317{"fcvtau_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},318{"fcvtms_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},319{"fcvtmu_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},320{"fcvtns_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},321{"fcvtnu_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},322{"fcvtps_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},323{"fcvtpu_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},324{"fcvtxn_asisdmisc_n"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},325{"fcvtzs_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},326{"fcvtzu_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},327{"frecpe_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},328{"frecpx_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},329{"frsqrte_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},330{"scvtf_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},331{"ucvtf_asisdmisc_r"_h, &Disassembler::DisassembleNEONFPScalar2RegMisc},332{"pmull_asimddiff_l"_h, &Disassembler::DisassembleNEONPolynomialMul},333{"adclb_z_zzz"_h, &Disassembler::DisassembleSVEAddSubCarry},334{"adclt_z_zzz"_h, &Disassembler::DisassembleSVEAddSubCarry},335{"addhnb_z_zz"_h, &Disassembler::DisassembleSVEAddSubHigh},336{"addhnt_z_zz"_h, &Disassembler::DisassembleSVEAddSubHigh},337{"addp_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},338{"aesd_z_zz"_h, &Disassembler::Disassemble_ZdnB_ZdnB_ZmB},339{"aese_z_zz"_h, &Disassembler::Disassemble_ZdnB_ZdnB_ZmB},340{"aesimc_z_z"_h, &Disassembler::Disassemble_ZdnB_ZdnB},341{"aesmc_z_z"_h, &Disassembler::Disassemble_ZdnB_ZdnB},342{"bcax_z_zzz"_h, &Disassembler::DisassembleSVEBitwiseTernary},343{"bdep_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},344{"bext_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},345{"bgrp_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},346{"bsl1n_z_zzz"_h, &Disassembler::DisassembleSVEBitwiseTernary},347{"bsl2n_z_zzz"_h, &Disassembler::DisassembleSVEBitwiseTernary},348{"bsl_z_zzz"_h, &Disassembler::DisassembleSVEBitwiseTernary},349{"cadd_z_zz"_h, &Disassembler::DisassembleSVEComplexIntAddition},350{"cdot_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb_const},351{"cdot_z_zzzi_d"_h, &Disassembler::Disassemble_ZdaD_ZnH_ZmH_imm_const},352{"cdot_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnB_ZmB_imm_const},353{"cmla_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnT_ZmT_const},354{"cmla_z_zzzi_h"_h, &Disassembler::Disassemble_ZdaH_ZnH_ZmH_imm_const},355{"cmla_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnS_ZmS_imm_const},356{"eor3_z_zzz"_h, &Disassembler::DisassembleSVEBitwiseTernary},357{"eorbt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},358{"eortb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},359{"ext_z_zi_con"_h, &Disassembler::Disassemble_ZdB_Zn1B_Zn2B_imm},360{"faddp_z_p_zz"_h, &Disassembler::DisassembleSVEFPPair},361{"fcvtlt_z_p_z_h2s"_h, &Disassembler::Disassemble_ZdS_PgM_ZnH},362{"fcvtlt_z_p_z_s2d"_h, &Disassembler::Disassemble_ZdD_PgM_ZnS},363{"fcvtnt_z_p_z_d2s"_h, &Disassembler::Disassemble_ZdS_PgM_ZnD},364{"fcvtnt_z_p_z_s2h"_h, &Disassembler::Disassemble_ZdH_PgM_ZnS},365{"fcvtx_z_p_z_d2s"_h, &Disassembler::Disassemble_ZdS_PgM_ZnD},366{"fcvtxnt_z_p_z_d2s"_h, &Disassembler::Disassemble_ZdS_PgM_ZnD},367{"flogb_z_p_z"_h, &Disassembler::DisassembleSVEFlogb},368{"fmaxnmp_z_p_zz"_h, &Disassembler::DisassembleSVEFPPair},369{"fmaxp_z_p_zz"_h, &Disassembler::DisassembleSVEFPPair},370{"fminnmp_z_p_zz"_h, &Disassembler::DisassembleSVEFPPair},371{"fminp_z_p_zz"_h, &Disassembler::DisassembleSVEFPPair},372{"fmlalb_z_zzz"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH},373{"fmlalb_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH_imm},374{"fmlalt_z_zzz"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH},375{"fmlalt_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH_imm},376{"fmlslb_z_zzz"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH},377{"fmlslb_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH_imm},378{"fmlslt_z_zzz"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH},379{"fmlslt_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH_imm},380{"histcnt_z_p_zz"_h, &Disassembler::Disassemble_ZdT_PgZ_ZnT_ZmT},381{"histseg_z_zz"_h, &Disassembler::Disassemble_ZdB_ZnB_ZmB},382{"ldnt1b_z_p_ar_d_64_unscaled"_h,383&Disassembler::Disassemble_ZtD_PgZ_ZnD_Xm},384{"ldnt1b_z_p_ar_s_x32_unscaled"_h,385&Disassembler::Disassemble_ZtS_PgZ_ZnS_Xm},386{"ldnt1d_z_p_ar_d_64_unscaled"_h,387&Disassembler::Disassemble_ZtD_PgZ_ZnD_Xm},388{"ldnt1h_z_p_ar_d_64_unscaled"_h,389&Disassembler::Disassemble_ZtD_PgZ_ZnD_Xm},390{"ldnt1h_z_p_ar_s_x32_unscaled"_h,391&Disassembler::Disassemble_ZtS_PgZ_ZnS_Xm},392{"ldnt1sb_z_p_ar_d_64_unscaled"_h,393&Disassembler::Disassemble_ZtD_PgZ_ZnD_Xm},394{"ldnt1sb_z_p_ar_s_x32_unscaled"_h,395&Disassembler::Disassemble_ZtS_PgZ_ZnS_Xm},396{"ldnt1sh_z_p_ar_d_64_unscaled"_h,397&Disassembler::Disassemble_ZtD_PgZ_ZnD_Xm},398{"ldnt1sh_z_p_ar_s_x32_unscaled"_h,399&Disassembler::Disassemble_ZtS_PgZ_ZnS_Xm},400{"ldnt1sw_z_p_ar_d_64_unscaled"_h,401&Disassembler::Disassemble_ZtD_PgZ_ZnD_Xm},402{"ldnt1w_z_p_ar_d_64_unscaled"_h,403&Disassembler::Disassemble_ZtD_PgZ_ZnD_Xm},404{"ldnt1w_z_p_ar_s_x32_unscaled"_h,405&Disassembler::Disassemble_ZtS_PgZ_ZnS_Xm},406{"match_p_p_zz"_h, &Disassembler::Disassemble_PdT_PgZ_ZnT_ZmT},407{"mla_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnD_ZmD_imm},408{"mla_z_zzzi_h"_h, &Disassembler::Disassemble_ZdH_ZnH_ZmH_imm},409{"mla_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnS_ZmS_imm},410{"mls_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnD_ZmD_imm},411{"mls_z_zzzi_h"_h, &Disassembler::Disassemble_ZdH_ZnH_ZmH_imm},412{"mls_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnS_ZmS_imm},413{"mul_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},414{"mul_z_zzi_d"_h, &Disassembler::Disassemble_ZdD_ZnD_ZmD_imm},415{"mul_z_zzi_h"_h, &Disassembler::Disassemble_ZdH_ZnH_ZmH_imm},416{"mul_z_zzi_s"_h, &Disassembler::Disassemble_ZdS_ZnS_ZmS_imm},417{"nbsl_z_zzz"_h, &Disassembler::DisassembleSVEBitwiseTernary},418{"nmatch_p_p_zz"_h, &Disassembler::Disassemble_PdT_PgZ_ZnT_ZmT},419{"pmul_z_zz"_h, &Disassembler::Disassemble_ZdB_ZnB_ZmB},420{"pmullb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},421{"pmullt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},422{"raddhnb_z_zz"_h, &Disassembler::DisassembleSVEAddSubHigh},423{"raddhnt_z_zz"_h, &Disassembler::DisassembleSVEAddSubHigh},424{"rax1_z_zz"_h, &Disassembler::Disassemble_ZdD_ZnD_ZmD},425{"rshrnb_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},426{"rshrnt_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},427{"rsubhnb_z_zz"_h, &Disassembler::DisassembleSVEAddSubHigh},428{"rsubhnt_z_zz"_h, &Disassembler::DisassembleSVEAddSubHigh},429{"saba_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnT_ZmT},430{"sabalb_z_zzz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},431{"sabalt_z_zzz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},432{"sabdlb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},433{"sabdlt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},434{"sadalp_z_p_z"_h, &Disassembler::Disassemble_ZdaT_PgM_ZnTb},435{"saddlb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},436{"saddlbt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},437{"saddlt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},438{"saddwb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmTb},439{"saddwt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmTb},440{"sbclb_z_zzz"_h, &Disassembler::DisassembleSVEAddSubCarry},441{"sbclt_z_zzz"_h, &Disassembler::DisassembleSVEAddSubCarry},442{"shadd_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},443{"shrnb_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},444{"shrnt_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},445{"shsub_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},446{"shsubr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},447{"sli_z_zzi"_h, &Disassembler::VisitSVEBitwiseShiftUnpredicated},448{"sm4e_z_zz"_h, &Disassembler::Disassemble_ZdnS_ZdnS_ZmS},449{"sm4ekey_z_zz"_h, &Disassembler::Disassemble_ZdS_ZnS_ZmS},450{"smaxp_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},451{"sminp_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},452{"smlalb_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},453{"smlalb_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},454{"smlalb_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},455{"smlalt_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},456{"smlalt_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},457{"smlalt_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},458{"smlslb_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},459{"smlslb_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},460{"smlslb_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},461{"smlslt_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},462{"smlslt_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},463{"smlslt_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},464{"smulh_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},465{"smullb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},466{"smullb_z_zzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},467{"smullb_z_zzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},468{"smullt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},469{"smullt_z_zzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},470{"smullt_z_zzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},471{"splice_z_p_zz_con"_h, &Disassembler::Disassemble_ZdT_Pg_Zn1T_Zn2T},472{"sqabs_z_p_z"_h, &Disassembler::Disassemble_ZdT_PgM_ZnT},473{"sqadd_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},474{"sqcadd_z_zz"_h, &Disassembler::DisassembleSVEComplexIntAddition},475{"sqdmlalb_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},476{"sqdmlalb_z_zzzi_d"_h, &Disassembler::Disassemble_ZdaD_ZnS_ZmS_imm},477{"sqdmlalb_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH_imm},478{"sqdmlalbt_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},479{"sqdmlalt_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},480{"sqdmlalt_z_zzzi_d"_h, &Disassembler::Disassemble_ZdaD_ZnS_ZmS_imm},481{"sqdmlalt_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH_imm},482{"sqdmlslb_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},483{"sqdmlslb_z_zzzi_d"_h, &Disassembler::Disassemble_ZdaD_ZnS_ZmS_imm},484{"sqdmlslb_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH_imm},485{"sqdmlslbt_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},486{"sqdmlslt_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},487{"sqdmlslt_z_zzzi_d"_h, &Disassembler::Disassemble_ZdaD_ZnS_ZmS_imm},488{"sqdmlslt_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnH_ZmH_imm},489{"sqdmulh_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},490{"sqdmulh_z_zzi_d"_h, &Disassembler::Disassemble_ZdD_ZnD_ZmD_imm},491{"sqdmulh_z_zzi_h"_h, &Disassembler::Disassemble_ZdH_ZnH_ZmH_imm},492{"sqdmulh_z_zzi_s"_h, &Disassembler::Disassemble_ZdS_ZnS_ZmS_imm},493{"sqdmullb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},494{"sqdmullb_z_zzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},495{"sqdmullb_z_zzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},496{"sqdmullt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},497{"sqdmullt_z_zzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},498{"sqdmullt_z_zzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},499{"sqneg_z_p_z"_h, &Disassembler::Disassemble_ZdT_PgM_ZnT},500{"sqrdcmlah_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnT_ZmT_const},501{"sqrdcmlah_z_zzzi_h"_h,502&Disassembler::Disassemble_ZdaH_ZnH_ZmH_imm_const},503{"sqrdcmlah_z_zzzi_s"_h,504&Disassembler::Disassemble_ZdaS_ZnS_ZmS_imm_const},505{"sqrdmlah_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnT_ZmT},506{"sqrdmlah_z_zzzi_d"_h, &Disassembler::Disassemble_ZdaD_ZnD_ZmD_imm},507{"sqrdmlah_z_zzzi_h"_h, &Disassembler::Disassemble_ZdaH_ZnH_ZmH_imm},508{"sqrdmlah_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnS_ZmS_imm},509{"sqrdmlsh_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnT_ZmT},510{"sqrdmlsh_z_zzzi_d"_h, &Disassembler::Disassemble_ZdaD_ZnD_ZmD_imm},511{"sqrdmlsh_z_zzzi_h"_h, &Disassembler::Disassemble_ZdaH_ZnH_ZmH_imm},512{"sqrdmlsh_z_zzzi_s"_h, &Disassembler::Disassemble_ZdaS_ZnS_ZmS_imm},513{"sqrdmulh_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},514{"sqrdmulh_z_zzi_d"_h, &Disassembler::Disassemble_ZdD_ZnD_ZmD_imm},515{"sqrdmulh_z_zzi_h"_h, &Disassembler::Disassemble_ZdH_ZnH_ZmH_imm},516{"sqrdmulh_z_zzi_s"_h, &Disassembler::Disassemble_ZdS_ZnS_ZmS_imm},517{"sqrshl_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},518{"sqrshlr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},519{"sqrshrnb_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},520{"sqrshrnt_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},521{"sqrshrunb_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},522{"sqrshrunt_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},523{"sqshl_z_p_zi"_h, &Disassembler::VisitSVEBitwiseShiftByImm_Predicated},524{"sqshl_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},525{"sqshlr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},526{"sqshlu_z_p_zi"_h, &Disassembler::VisitSVEBitwiseShiftByImm_Predicated},527{"sqshrnb_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},528{"sqshrnt_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},529{"sqshrunb_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},530{"sqshrunt_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},531{"sqsub_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},532{"sqsubr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},533{"sqxtnb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb},534{"sqxtnt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb},535{"sqxtunb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb},536{"sqxtunt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb},537{"srhadd_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},538{"sri_z_zzi"_h, &Disassembler::VisitSVEBitwiseShiftUnpredicated},539{"srshl_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},540{"srshlr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},541{"srshr_z_p_zi"_h, &Disassembler::VisitSVEBitwiseShiftByImm_Predicated},542{"srsra_z_zi"_h, &Disassembler::VisitSVEBitwiseShiftUnpredicated},543{"sshllb_z_zi"_h, &Disassembler::DisassembleSVEShiftLeftImm},544{"sshllt_z_zi"_h, &Disassembler::DisassembleSVEShiftLeftImm},545{"ssra_z_zi"_h, &Disassembler::VisitSVEBitwiseShiftUnpredicated},546{"ssublb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},547{"ssublbt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},548{"ssublt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},549{"ssubltb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},550{"ssubwb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmTb},551{"ssubwt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmTb},552{"stnt1b_z_p_ar_d_64_unscaled"_h,553&Disassembler::Disassemble_ZtD_Pg_ZnD_Xm},554{"stnt1b_z_p_ar_s_x32_unscaled"_h,555&Disassembler::Disassemble_ZtS_Pg_ZnS_Xm},556{"stnt1d_z_p_ar_d_64_unscaled"_h,557&Disassembler::Disassemble_ZtD_Pg_ZnD_Xm},558{"stnt1h_z_p_ar_d_64_unscaled"_h,559&Disassembler::Disassemble_ZtD_Pg_ZnD_Xm},560{"stnt1h_z_p_ar_s_x32_unscaled"_h,561&Disassembler::Disassemble_ZtS_Pg_ZnS_Xm},562{"stnt1w_z_p_ar_d_64_unscaled"_h,563&Disassembler::Disassemble_ZtD_Pg_ZnD_Xm},564{"stnt1w_z_p_ar_s_x32_unscaled"_h,565&Disassembler::Disassemble_ZtS_Pg_ZnS_Xm},566{"subhnb_z_zz"_h, &Disassembler::DisassembleSVEAddSubHigh},567{"subhnt_z_zz"_h, &Disassembler::DisassembleSVEAddSubHigh},568{"suqadd_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},569{"tbl_z_zz_2"_h, &Disassembler::Disassemble_ZdT_Zn1T_Zn2T_ZmT},570{"tbx_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},571{"uaba_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnT_ZmT},572{"uabalb_z_zzz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},573{"uabalt_z_zzz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},574{"uabdlb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},575{"uabdlt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},576{"uadalp_z_p_z"_h, &Disassembler::Disassemble_ZdaT_PgM_ZnTb},577{"uaddlb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},578{"uaddlt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},579{"uaddwb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmTb},580{"uaddwt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmTb},581{"uhadd_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},582{"uhsub_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},583{"uhsubr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},584{"umaxp_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},585{"uminp_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},586{"umlalb_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},587{"umlalb_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},588{"umlalb_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},589{"umlalt_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},590{"umlalt_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},591{"umlalt_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},592{"umlslb_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},593{"umlslb_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},594{"umlslb_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},595{"umlslt_z_zzz"_h, &Disassembler::Disassemble_ZdaT_ZnTb_ZmTb},596{"umlslt_z_zzzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},597{"umlslt_z_zzzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},598{"umulh_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmT},599{"umullb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},600{"umullb_z_zzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},601{"umullb_z_zzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},602{"umullt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},603{"umullt_z_zzi_d"_h, &Disassembler::Disassemble_ZdD_ZnS_ZmS_imm},604{"umullt_z_zzi_s"_h, &Disassembler::Disassemble_ZdS_ZnH_ZmH_imm},605{"uqadd_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},606{"uqrshl_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},607{"uqrshlr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},608{"uqrshrnb_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},609{"uqrshrnt_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},610{"uqshl_z_p_zi"_h, &Disassembler::VisitSVEBitwiseShiftByImm_Predicated},611{"uqshl_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},612{"uqshlr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},613{"uqshrnb_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},614{"uqshrnt_z_zi"_h, &Disassembler::DisassembleSVEShiftRightImm},615{"uqsub_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},616{"uqsubr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},617{"uqxtnb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb},618{"uqxtnt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb},619{"urecpe_z_p_z"_h, &Disassembler::Disassemble_ZdS_PgM_ZnS},620{"urhadd_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},621{"urshl_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},622{"urshlr_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},623{"urshr_z_p_zi"_h, &Disassembler::VisitSVEBitwiseShiftByImm_Predicated},624{"ursqrte_z_p_z"_h, &Disassembler::Disassemble_ZdS_PgM_ZnS},625{"ursra_z_zi"_h, &Disassembler::VisitSVEBitwiseShiftUnpredicated},626{"ushllb_z_zi"_h, &Disassembler::DisassembleSVEShiftLeftImm},627{"ushllt_z_zi"_h, &Disassembler::DisassembleSVEShiftLeftImm},628{"usqadd_z_p_zz"_h, &Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT},629{"usra_z_zi"_h, &Disassembler::VisitSVEBitwiseShiftUnpredicated},630{"usublb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},631{"usublt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnTb_ZmTb},632{"usubwb_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmTb},633{"usubwt_z_zz"_h, &Disassembler::Disassemble_ZdT_ZnT_ZmTb},634{"whilege_p_p_rr"_h,635&Disassembler::VisitSVEIntCompareScalarCountAndLimit},636{"whilegt_p_p_rr"_h,637&Disassembler::VisitSVEIntCompareScalarCountAndLimit},638{"whilehi_p_p_rr"_h,639&Disassembler::VisitSVEIntCompareScalarCountAndLimit},640{"whilehs_p_p_rr"_h,641&Disassembler::VisitSVEIntCompareScalarCountAndLimit},642{"whilerw_p_rr"_h, &Disassembler::VisitSVEIntCompareScalarCountAndLimit},643{"whilewr_p_rr"_h, &Disassembler::VisitSVEIntCompareScalarCountAndLimit},644{"xar_z_zzi"_h, &Disassembler::Disassemble_ZdnT_ZdnT_ZmT_const},645{"fmmla_z_zzz_s"_h, &Disassembler::Disassemble_ZdaT_ZnT_ZmT},646{"fmmla_z_zzz_d"_h, &Disassembler::Disassemble_ZdaT_ZnT_ZmT},647{"smmla_z_zzz"_h, &Disassembler::Disassemble_ZdaS_ZnB_ZmB},648{"ummla_z_zzz"_h, &Disassembler::Disassemble_ZdaS_ZnB_ZmB},649{"usmmla_z_zzz"_h, &Disassembler::Disassemble_ZdaS_ZnB_ZmB},650{"usdot_z_zzz_s"_h, &Disassembler::Disassemble_ZdaS_ZnB_ZmB},651{"smmla_asimdsame2_g"_h, &Disassembler::Disassemble_Vd4S_Vn16B_Vm16B},652{"ummla_asimdsame2_g"_h, &Disassembler::Disassemble_Vd4S_Vn16B_Vm16B},653{"usmmla_asimdsame2_g"_h, &Disassembler::Disassemble_Vd4S_Vn16B_Vm16B},654{"ld1row_z_p_bi_u32"_h,655&Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm},656{"ld1row_z_p_br_contiguous"_h,657&Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar},658{"ld1rod_z_p_bi_u64"_h,659&Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm},660{"ld1rod_z_p_br_contiguous"_h,661&Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar},662{"ld1rob_z_p_bi_u8"_h,663&Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm},664{"ld1rob_z_p_br_contiguous"_h,665&Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar},666{"ld1roh_z_p_bi_u16"_h,667&Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm},668{"ld1roh_z_p_br_contiguous"_h,669&Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar},670{"usdot_z_zzzi_s"_h, &Disassembler::VisitSVEMulIndex},671{"sudot_z_zzzi_s"_h, &Disassembler::VisitSVEMulIndex},672{"usdot_asimdsame2_d"_h, &Disassembler::VisitNEON3SameExtra},673{"addg_64_addsub_immtags"_h,674&Disassembler::Disassemble_XdSP_XnSP_uimm6_uimm4},675{"gmi_64g_dp_2src"_h, &Disassembler::Disassemble_Xd_XnSP_Xm},676{"irg_64i_dp_2src"_h, &Disassembler::Disassemble_XdSP_XnSP_Xm},677{"ldg_64loffset_ldsttags"_h, &Disassembler::DisassembleMTELoadTag},678{"st2g_64soffset_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},679{"st2g_64spost_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},680{"st2g_64spre_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},681{"stgp_64_ldstpair_off"_h, &Disassembler::DisassembleMTEStoreTagPair},682{"stgp_64_ldstpair_post"_h, &Disassembler::DisassembleMTEStoreTagPair},683{"stgp_64_ldstpair_pre"_h, &Disassembler::DisassembleMTEStoreTagPair},684{"stg_64soffset_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},685{"stg_64spost_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},686{"stg_64spre_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},687{"stz2g_64soffset_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},688{"stz2g_64spost_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},689{"stz2g_64spre_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},690{"stzg_64soffset_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},691{"stzg_64spost_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},692{"stzg_64spre_ldsttags"_h, &Disassembler::DisassembleMTEStoreTag},693{"subg_64_addsub_immtags"_h,694&Disassembler::Disassemble_XdSP_XnSP_uimm6_uimm4},695{"subps_64s_dp_2src"_h, &Disassembler::Disassemble_Xd_XnSP_XmSP},696{"subp_64s_dp_2src"_h, &Disassembler::Disassemble_Xd_XnSP_XmSP},697{"cpyen_cpy_memcms"_h, &Disassembler::DisassembleCpy},698{"cpyern_cpy_memcms"_h, &Disassembler::DisassembleCpy},699{"cpyewn_cpy_memcms"_h, &Disassembler::DisassembleCpy},700{"cpye_cpy_memcms"_h, &Disassembler::DisassembleCpy},701{"cpyfen_cpy_memcms"_h, &Disassembler::DisassembleCpy},702{"cpyfern_cpy_memcms"_h, &Disassembler::DisassembleCpy},703{"cpyfewn_cpy_memcms"_h, &Disassembler::DisassembleCpy},704{"cpyfe_cpy_memcms"_h, &Disassembler::DisassembleCpy},705{"cpyfmn_cpy_memcms"_h, &Disassembler::DisassembleCpy},706{"cpyfmrn_cpy_memcms"_h, &Disassembler::DisassembleCpy},707{"cpyfmwn_cpy_memcms"_h, &Disassembler::DisassembleCpy},708{"cpyfm_cpy_memcms"_h, &Disassembler::DisassembleCpy},709{"cpyfpn_cpy_memcms"_h, &Disassembler::DisassembleCpy},710{"cpyfprn_cpy_memcms"_h, &Disassembler::DisassembleCpy},711{"cpyfpwn_cpy_memcms"_h, &Disassembler::DisassembleCpy},712{"cpyfp_cpy_memcms"_h, &Disassembler::DisassembleCpy},713{"cpymn_cpy_memcms"_h, &Disassembler::DisassembleCpy},714{"cpymrn_cpy_memcms"_h, &Disassembler::DisassembleCpy},715{"cpymwn_cpy_memcms"_h, &Disassembler::DisassembleCpy},716{"cpym_cpy_memcms"_h, &Disassembler::DisassembleCpy},717{"cpypn_cpy_memcms"_h, &Disassembler::DisassembleCpy},718{"cpyprn_cpy_memcms"_h, &Disassembler::DisassembleCpy},719{"cpypwn_cpy_memcms"_h, &Disassembler::DisassembleCpy},720{"cpyp_cpy_memcms"_h, &Disassembler::DisassembleCpy},721{"seten_set_memcms"_h, &Disassembler::DisassembleSet},722{"sete_set_memcms"_h, &Disassembler::DisassembleSet},723{"setgen_set_memcms"_h, &Disassembler::DisassembleSet},724{"setge_set_memcms"_h, &Disassembler::DisassembleSet},725{"setgmn_set_memcms"_h, &Disassembler::DisassembleSet},726{"setgm_set_memcms"_h, &Disassembler::DisassembleSet},727{"setgpn_set_memcms"_h, &Disassembler::DisassembleSet},728{"setgp_set_memcms"_h, &Disassembler::DisassembleSet},729{"setmn_set_memcms"_h, &Disassembler::DisassembleSet},730{"setm_set_memcms"_h, &Disassembler::DisassembleSet},731{"setpn_set_memcms"_h, &Disassembler::DisassembleSet},732{"setp_set_memcms"_h, &Disassembler::DisassembleSet},733{"abs_32_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},734{"abs_64_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},735{"cnt_32_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},736{"cnt_64_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},737{"ctz_32_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},738{"ctz_64_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},739{"smax_32_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},740{"smax_64_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},741{"smin_32_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},742{"smin_64_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},743{"umax_32_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},744{"umax_64_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},745{"umin_32_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},746{"umin_64_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},747{"smax_32_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},748{"smax_64_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},749{"smin_32_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},750{"smin_64_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},751{"umax_32u_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},752{"umax_64u_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},753{"umin_32u_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},754{"umin_64u_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},755};756return &form_to_visitor;757} // NOLINT(readability/fn_size)758759Disassembler::Disassembler() {760buffer_size_ = 256;761buffer_ = reinterpret_cast<char *>(malloc(buffer_size_));762buffer_pos_ = 0;763own_buffer_ = true;764code_address_offset_ = 0;765}766767Disassembler::Disassembler(char *text_buffer, int buffer_size) {768buffer_size_ = buffer_size;769buffer_ = text_buffer;770buffer_pos_ = 0;771own_buffer_ = false;772code_address_offset_ = 0;773}774775Disassembler::~Disassembler() {776if (own_buffer_) {777free(buffer_);778}779}780781char *Disassembler::GetOutput() { return buffer_; }782783void Disassembler::VisitAddSubImmediate(const Instruction *instr) {784bool rd_is_zr = RdIsZROrSP(instr);785bool stack_op =786(rd_is_zr || RnIsZROrSP(instr)) && (instr->GetImmAddSub() == 0) ? true787: false;788const char *mnemonic = mnemonic_.c_str();789const char *form = "'Rds, 'Rns, 'IAddSub";790const char *form_cmp = "'Rns, 'IAddSub";791const char *form_mov = "'Rds, 'Rns";792793switch (form_hash_) {794case "add_32_addsub_imm"_h:795case "add_64_addsub_imm"_h:796if (stack_op) {797mnemonic = "mov";798form = form_mov;799}800break;801case "adds_32s_addsub_imm"_h:802case "adds_64s_addsub_imm"_h:803if (rd_is_zr) {804mnemonic = "cmn";805form = form_cmp;806}807break;808case "subs_32s_addsub_imm"_h:809case "subs_64s_addsub_imm"_h:810if (rd_is_zr) {811mnemonic = "cmp";812form = form_cmp;813}814break;815}816Format(instr, mnemonic, form);817}818819820void Disassembler::VisitAddSubShifted(const Instruction *instr) {821bool rd_is_zr = RdIsZROrSP(instr);822bool rn_is_zr = RnIsZROrSP(instr);823const char *mnemonic = mnemonic_.c_str();824const char *form = "'Rd, 'Rn, 'Rm'NDP";825const char *form_cmp = "'Rn, 'Rm'NDP";826const char *form_neg = "'Rd, 'Rm'NDP";827828if (instr->GetShiftDP() == ROR) {829// Add/sub/adds/subs don't allow ROR as a shift mode.830VisitUnallocated(instr);831return;832}833834switch (form_hash_) {835case "adds_32_addsub_shift"_h:836case "adds_64_addsub_shift"_h:837if (rd_is_zr) {838mnemonic = "cmn";839form = form_cmp;840}841break;842case "sub_32_addsub_shift"_h:843case "sub_64_addsub_shift"_h:844if (rn_is_zr) {845mnemonic = "neg";846form = form_neg;847}848break;849case "subs_32_addsub_shift"_h:850case "subs_64_addsub_shift"_h:851if (rd_is_zr) {852mnemonic = "cmp";853form = form_cmp;854} else if (rn_is_zr) {855mnemonic = "negs";856form = form_neg;857}858}859Format(instr, mnemonic, form);860}861862863void Disassembler::VisitAddSubExtended(const Instruction *instr) {864bool rd_is_zr = RdIsZROrSP(instr);865const char *mnemonic = "";866Extend mode = static_cast<Extend>(instr->GetExtendMode());867const char *form = ((mode == UXTX) || (mode == SXTX)) ? "'Rds, 'Rns, 'Xm'Ext"868: "'Rds, 'Rns, 'Wm'Ext";869const char *form_cmp =870((mode == UXTX) || (mode == SXTX)) ? "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";871872switch (instr->Mask(AddSubExtendedMask)) {873case ADD_w_ext:874case ADD_x_ext:875mnemonic = "add";876break;877case ADDS_w_ext:878case ADDS_x_ext: {879mnemonic = "adds";880if (rd_is_zr) {881mnemonic = "cmn";882form = form_cmp;883}884break;885}886case SUB_w_ext:887case SUB_x_ext:888mnemonic = "sub";889break;890case SUBS_w_ext:891case SUBS_x_ext: {892mnemonic = "subs";893if (rd_is_zr) {894mnemonic = "cmp";895form = form_cmp;896}897break;898}899default:900VIXL_UNREACHABLE();901}902Format(instr, mnemonic, form);903}904905906void Disassembler::VisitAddSubWithCarry(const Instruction *instr) {907bool rn_is_zr = RnIsZROrSP(instr);908const char *mnemonic = "";909const char *form = "'Rd, 'Rn, 'Rm";910const char *form_neg = "'Rd, 'Rm";911912switch (instr->Mask(AddSubWithCarryMask)) {913case ADC_w:914case ADC_x:915mnemonic = "adc";916break;917case ADCS_w:918case ADCS_x:919mnemonic = "adcs";920break;921case SBC_w:922case SBC_x: {923mnemonic = "sbc";924if (rn_is_zr) {925mnemonic = "ngc";926form = form_neg;927}928break;929}930case SBCS_w:931case SBCS_x: {932mnemonic = "sbcs";933if (rn_is_zr) {934mnemonic = "ngcs";935form = form_neg;936}937break;938}939default:940VIXL_UNREACHABLE();941}942Format(instr, mnemonic, form);943}944945946void Disassembler::VisitRotateRightIntoFlags(const Instruction *instr) {947FormatWithDecodedMnemonic(instr, "'Xn, 'IRr, 'INzcv");948}949950951void Disassembler::VisitEvaluateIntoFlags(const Instruction *instr) {952FormatWithDecodedMnemonic(instr, "'Wn");953}954955956void Disassembler::VisitLogicalImmediate(const Instruction *instr) {957bool rd_is_zr = RdIsZROrSP(instr);958bool rn_is_zr = RnIsZROrSP(instr);959const char *mnemonic = "";960const char *form = "'Rds, 'Rn, 'ITri";961962if (instr->GetImmLogical() == 0) {963// The immediate encoded in the instruction is not in the expected format.964Format(instr, "unallocated", "(LogicalImmediate)");965return;966}967968switch (instr->Mask(LogicalImmediateMask)) {969case AND_w_imm:970case AND_x_imm:971mnemonic = "and";972break;973case ORR_w_imm:974case ORR_x_imm: {975mnemonic = "orr";976unsigned reg_size =977(instr->GetSixtyFourBits() == 1) ? kXRegSize : kWRegSize;978if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->GetImmLogical())) {979mnemonic = "mov";980form = "'Rds, 'ITri";981}982break;983}984case EOR_w_imm:985case EOR_x_imm:986mnemonic = "eor";987break;988case ANDS_w_imm:989case ANDS_x_imm: {990mnemonic = "ands";991if (rd_is_zr) {992mnemonic = "tst";993form = "'Rn, 'ITri";994}995break;996}997default:998VIXL_UNREACHABLE();999}1000Format(instr, mnemonic, form);1001}100210031004bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {1005VIXL_ASSERT((reg_size == kXRegSize) ||1006((reg_size == kWRegSize) && (value <= 0xffffffff)));10071008// Test for movz: 16 bits set at positions 0, 16, 32 or 48.1009if (((value & UINT64_C(0xffffffffffff0000)) == 0) ||1010((value & UINT64_C(0xffffffff0000ffff)) == 0) ||1011((value & UINT64_C(0xffff0000ffffffff)) == 0) ||1012((value & UINT64_C(0x0000ffffffffffff)) == 0)) {1013return true;1014}10151016// Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).1017if ((reg_size == kXRegSize) &&1018(((~value & UINT64_C(0xffffffffffff0000)) == 0) ||1019((~value & UINT64_C(0xffffffff0000ffff)) == 0) ||1020((~value & UINT64_C(0xffff0000ffffffff)) == 0) ||1021((~value & UINT64_C(0x0000ffffffffffff)) == 0))) {1022return true;1023}1024if ((reg_size == kWRegSize) && (((value & 0xffff0000) == 0xffff0000) ||1025((value & 0x0000ffff) == 0x0000ffff))) {1026return true;1027}1028return false;1029}103010311032void Disassembler::VisitLogicalShifted(const Instruction *instr) {1033bool rd_is_zr = RdIsZROrSP(instr);1034bool rn_is_zr = RnIsZROrSP(instr);1035const char *mnemonic = mnemonic_.c_str();1036const char *form = "'Rd, 'Rn, 'Rm'NLo";10371038switch (form_hash_) {1039case "ands_32_log_shift"_h:1040case "ands_64_log_shift"_h:1041if (rd_is_zr) {1042mnemonic = "tst";1043form = "'Rn, 'Rm'NLo";1044}1045break;1046case "orr_32_log_shift"_h:1047case "orr_64_log_shift"_h:1048if (rn_is_zr && (instr->GetImmDPShift() == 0) &&1049(instr->GetShiftDP() == LSL)) {1050mnemonic = "mov";1051form = "'Rd, 'Rm";1052}1053break;1054case "orn_32_log_shift"_h:1055case "orn_64_log_shift"_h:1056if (rn_is_zr) {1057mnemonic = "mvn";1058form = "'Rd, 'Rm'NLo";1059}1060break;1061}10621063Format(instr, mnemonic, form);1064}106510661067void Disassembler::VisitConditionalCompareRegister(const Instruction *instr) {1068FormatWithDecodedMnemonic(instr, "'Rn, 'Rm, 'INzcv, 'Cond");1069}107010711072void Disassembler::VisitConditionalCompareImmediate(const Instruction *instr) {1073FormatWithDecodedMnemonic(instr, "'Rn, 'IP, 'INzcv, 'Cond");1074}107510761077void Disassembler::VisitConditionalSelect(const Instruction *instr) {1078bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));1079bool rn_is_rm = (instr->GetRn() == instr->GetRm());1080const char *mnemonic = "";1081const char *form = "'Rd, 'Rn, 'Rm, 'Cond";1082const char *form_test = "'Rd, 'CInv";1083const char *form_update = "'Rd, 'Rn, 'CInv";10841085Condition cond = static_cast<Condition>(instr->GetCondition());1086bool invertible_cond = (cond != al) && (cond != nv);10871088switch (instr->Mask(ConditionalSelectMask)) {1089case CSEL_w:1090case CSEL_x:1091mnemonic = "csel";1092break;1093case CSINC_w:1094case CSINC_x: {1095mnemonic = "csinc";1096if (rnm_is_zr && invertible_cond) {1097mnemonic = "cset";1098form = form_test;1099} else if (rn_is_rm && invertible_cond) {1100mnemonic = "cinc";1101form = form_update;1102}1103break;1104}1105case CSINV_w:1106case CSINV_x: {1107mnemonic = "csinv";1108if (rnm_is_zr && invertible_cond) {1109mnemonic = "csetm";1110form = form_test;1111} else if (rn_is_rm && invertible_cond) {1112mnemonic = "cinv";1113form = form_update;1114}1115break;1116}1117case CSNEG_w:1118case CSNEG_x: {1119mnemonic = "csneg";1120if (rn_is_rm && invertible_cond) {1121mnemonic = "cneg";1122form = form_update;1123}1124break;1125}1126default:1127VIXL_UNREACHABLE();1128}1129Format(instr, mnemonic, form);1130}113111321133void Disassembler::VisitBitfield(const Instruction *instr) {1134unsigned s = instr->GetImmS();1135unsigned r = instr->GetImmR();1136unsigned rd_size_minus_1 =1137((instr->GetSixtyFourBits() == 1) ? kXRegSize : kWRegSize) - 1;1138const char *mnemonic = "";1139const char *form = "";1140const char *form_shift_right = "'Rd, 'Rn, 'IBr";1141const char *form_extend = "'Rd, 'Wn";1142const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";1143const char *form_bfc = "'Rd, 'IBZ-r, 'IBs+1";1144const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";1145const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";11461147if (instr->GetSixtyFourBits() != instr->GetBitN()) {1148VisitUnallocated(instr);1149return;1150}11511152if ((instr->GetSixtyFourBits() == 0) && ((s > 31) || (r > 31))) {1153VisitUnallocated(instr);1154return;1155}11561157switch (instr->Mask(BitfieldMask)) {1158case SBFM_w:1159case SBFM_x: {1160mnemonic = "sbfx";1161form = form_bfx;1162if (r == 0) {1163form = form_extend;1164if (s == 7) {1165mnemonic = "sxtb";1166} else if (s == 15) {1167mnemonic = "sxth";1168} else if ((s == 31) && (instr->GetSixtyFourBits() == 1)) {1169mnemonic = "sxtw";1170} else {1171form = form_bfx;1172}1173} else if (s == rd_size_minus_1) {1174mnemonic = "asr";1175form = form_shift_right;1176} else if (s < r) {1177mnemonic = "sbfiz";1178form = form_bfiz;1179}1180break;1181}1182case UBFM_w:1183case UBFM_x: {1184mnemonic = "ubfx";1185form = form_bfx;1186if (r == 0) {1187form = form_extend;1188if (s == 7) {1189mnemonic = "uxtb";1190} else if (s == 15) {1191mnemonic = "uxth";1192} else {1193form = form_bfx;1194}1195}1196if (s == rd_size_minus_1) {1197mnemonic = "lsr";1198form = form_shift_right;1199} else if (r == s + 1) {1200mnemonic = "lsl";1201form = form_lsl;1202} else if (s < r) {1203mnemonic = "ubfiz";1204form = form_bfiz;1205}1206break;1207}1208case BFM_w:1209case BFM_x: {1210mnemonic = "bfxil";1211form = form_bfx;1212if (s < r) {1213if (instr->GetRn() == kZeroRegCode) {1214mnemonic = "bfc";1215form = form_bfc;1216} else {1217mnemonic = "bfi";1218form = form_bfiz;1219}1220}1221}1222}1223Format(instr, mnemonic, form);1224}122512261227void Disassembler::VisitExtract(const Instruction *instr) {1228const char *mnemonic = "";1229const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";12301231switch (instr->Mask(ExtractMask)) {1232case EXTR_w:1233case EXTR_x: {1234if (instr->GetRn() == instr->GetRm()) {1235mnemonic = "ror";1236form = "'Rd, 'Rn, 'IExtract";1237} else {1238mnemonic = "extr";1239}1240break;1241}1242default:1243VIXL_UNREACHABLE();1244}1245Format(instr, mnemonic, form);1246}124712481249void Disassembler::VisitPCRelAddressing(const Instruction *instr) {1250switch (instr->Mask(PCRelAddressingMask)) {1251case ADR:1252Format(instr, "adr", "'Xd, 'AddrPCRelByte");1253break;1254case ADRP:1255Format(instr, "adrp", "'Xd, 'AddrPCRelPage");1256break;1257default:1258Format(instr, "unimplemented", "(PCRelAddressing)");1259}1260}126112621263void Disassembler::VisitConditionalBranch(const Instruction *instr) {1264// We can't use the mnemonic directly here, as there's no space between it and1265// the condition. Assert that we have the correct mnemonic, then use "b"1266// explicitly for formatting the output.1267VIXL_ASSERT(form_hash_ == "b_only_condbranch"_h);1268Format(instr, "b.'CBrn", "'TImmCond");1269}127012711272void Disassembler::VisitUnconditionalBranchToRegister(1273const Instruction *instr) {1274const char *form = "'Xn";12751276switch (form_hash_) {1277case "ret_64r_branch_reg"_h:1278if (instr->GetRn() == kLinkRegCode) {1279form = "";1280}1281break;1282case "retaa_64e_branch_reg"_h:1283case "retab_64e_branch_reg"_h:1284form = "";1285break;1286case "braa_64p_branch_reg"_h:1287case "brab_64p_branch_reg"_h:1288case "blraa_64p_branch_reg"_h:1289case "blrab_64p_branch_reg"_h:1290form = "'Xn, 'Xds";1291break;1292}12931294FormatWithDecodedMnemonic(instr, form);1295}129612971298void Disassembler::VisitUnconditionalBranch(const Instruction *instr) {1299FormatWithDecodedMnemonic(instr, "'TImmUncn");1300}130113021303void Disassembler::VisitDataProcessing1Source(const Instruction *instr) {1304const char *form = "'Rd, 'Rn";13051306switch (form_hash_) {1307case "pacia_64p_dp_1src"_h:1308case "pacda_64p_dp_1src"_h:1309case "autia_64p_dp_1src"_h:1310case "autda_64p_dp_1src"_h:1311case "pacib_64p_dp_1src"_h:1312case "pacdb_64p_dp_1src"_h:1313case "autib_64p_dp_1src"_h:1314case "autdb_64p_dp_1src"_h:1315form = "'Xd, 'Xns";1316break;1317case "paciza_64z_dp_1src"_h:1318case "pacdza_64z_dp_1src"_h:1319case "autiza_64z_dp_1src"_h:1320case "autdza_64z_dp_1src"_h:1321case "pacizb_64z_dp_1src"_h:1322case "pacdzb_64z_dp_1src"_h:1323case "autizb_64z_dp_1src"_h:1324case "autdzb_64z_dp_1src"_h:1325case "xpacd_64z_dp_1src"_h:1326case "xpaci_64z_dp_1src"_h:1327form = "'Xd";1328break;1329}1330FormatWithDecodedMnemonic(instr, form);1331}133213331334void Disassembler::VisitDataProcessing2Source(const Instruction *instr) {1335std::string mnemonic = mnemonic_;1336const char *form = "'Rd, 'Rn, 'Rm";13371338switch (form_hash_) {1339case "asrv_32_dp_2src"_h:1340case "asrv_64_dp_2src"_h:1341case "lslv_32_dp_2src"_h:1342case "lslv_64_dp_2src"_h:1343case "lsrv_32_dp_2src"_h:1344case "lsrv_64_dp_2src"_h:1345case "rorv_32_dp_2src"_h:1346case "rorv_64_dp_2src"_h:1347// Drop the last 'v' character.1348VIXL_ASSERT(mnemonic[3] == 'v');1349mnemonic.pop_back();1350break;1351case "pacga_64p_dp_2src"_h:1352form = "'Xd, 'Xn, 'Xms";1353break;1354case "crc32x_64c_dp_2src"_h:1355case "crc32cx_64c_dp_2src"_h:1356form = "'Wd, 'Wn, 'Xm";1357break;1358}1359Format(instr, mnemonic.c_str(), form);1360}136113621363void Disassembler::VisitDataProcessing3Source(const Instruction *instr) {1364bool ra_is_zr = RaIsZROrSP(instr);1365const char *mnemonic = "";1366const char *form = "'Xd, 'Wn, 'Wm, 'Xa";1367const char *form_rrr = "'Rd, 'Rn, 'Rm";1368const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";1369const char *form_xww = "'Xd, 'Wn, 'Wm";1370const char *form_xxx = "'Xd, 'Xn, 'Xm";13711372switch (instr->Mask(DataProcessing3SourceMask)) {1373case MADD_w:1374case MADD_x: {1375mnemonic = "madd";1376form = form_rrrr;1377if (ra_is_zr) {1378mnemonic = "mul";1379form = form_rrr;1380}1381break;1382}1383case MSUB_w:1384case MSUB_x: {1385mnemonic = "msub";1386form = form_rrrr;1387if (ra_is_zr) {1388mnemonic = "mneg";1389form = form_rrr;1390}1391break;1392}1393case SMADDL_x: {1394mnemonic = "smaddl";1395if (ra_is_zr) {1396mnemonic = "smull";1397form = form_xww;1398}1399break;1400}1401case SMSUBL_x: {1402mnemonic = "smsubl";1403if (ra_is_zr) {1404mnemonic = "smnegl";1405form = form_xww;1406}1407break;1408}1409case UMADDL_x: {1410mnemonic = "umaddl";1411if (ra_is_zr) {1412mnemonic = "umull";1413form = form_xww;1414}1415break;1416}1417case UMSUBL_x: {1418mnemonic = "umsubl";1419if (ra_is_zr) {1420mnemonic = "umnegl";1421form = form_xww;1422}1423break;1424}1425case SMULH_x: {1426mnemonic = "smulh";1427form = form_xxx;1428break;1429}1430case UMULH_x: {1431mnemonic = "umulh";1432form = form_xxx;1433break;1434}1435default:1436VIXL_UNREACHABLE();1437}1438Format(instr, mnemonic, form);1439}14401441void Disassembler::DisassembleMinMaxImm(const Instruction *instr) {1442const char *suffix = (instr->ExtractBit(18) == 0) ? "'s1710" : "'u1710";1443FormatWithDecodedMnemonic(instr, "'Rd, 'Rn, #", suffix);1444}14451446void Disassembler::VisitCompareBranch(const Instruction *instr) {1447FormatWithDecodedMnemonic(instr, "'Rt, 'TImmCmpa");1448}144914501451void Disassembler::VisitTestBranch(const Instruction *instr) {1452// If the top bit of the immediate is clear, the tested register is1453// disassembled as Wt, otherwise Xt. As the top bit of the immediate is1454// encoded in bit 31 of the instruction, we can reuse the Rt form, which1455// uses bit 31 (normally "sf") to choose the register size.1456FormatWithDecodedMnemonic(instr, "'Rt, 'It, 'TImmTest");1457}145814591460void Disassembler::VisitMoveWideImmediate(const Instruction *instr) {1461const char *mnemonic = "";1462const char *form = "'Rd, 'IMoveImm";14631464// Print the shift separately for movk, to make it clear which half word will1465// be overwritten. Movn and movz print the computed immediate, which includes1466// shift calculation.1467switch (instr->Mask(MoveWideImmediateMask)) {1468case MOVN_w:1469case MOVN_x:1470if ((instr->GetImmMoveWide()) || (instr->GetShiftMoveWide() == 0)) {1471if ((instr->GetSixtyFourBits() == 0) &&1472(instr->GetImmMoveWide() == 0xffff)) {1473mnemonic = "movn";1474} else {1475mnemonic = "mov";1476form = "'Rd, 'IMoveNeg";1477}1478} else {1479mnemonic = "movn";1480}1481break;1482case MOVZ_w:1483case MOVZ_x:1484if ((instr->GetImmMoveWide()) || (instr->GetShiftMoveWide() == 0))1485mnemonic = "mov";1486else1487mnemonic = "movz";1488break;1489case MOVK_w:1490case MOVK_x:1491mnemonic = "movk";1492form = "'Rd, 'IMoveLSL";1493break;1494default:1495VIXL_UNREACHABLE();1496}1497Format(instr, mnemonic, form);1498}149915001501#define LOAD_STORE_LIST(V) \1502V(STRB_w, "'Wt") \1503V(STRH_w, "'Wt") \1504V(STR_w, "'Wt") \1505V(STR_x, "'Xt") \1506V(LDRB_w, "'Wt") \1507V(LDRH_w, "'Wt") \1508V(LDR_w, "'Wt") \1509V(LDR_x, "'Xt") \1510V(LDRSB_x, "'Xt") \1511V(LDRSH_x, "'Xt") \1512V(LDRSW_x, "'Xt") \1513V(LDRSB_w, "'Wt") \1514V(LDRSH_w, "'Wt") \1515V(STR_b, "'Bt") \1516V(STR_h, "'Ht") \1517V(STR_s, "'St") \1518V(STR_d, "'Dt") \1519V(LDR_b, "'Bt") \1520V(LDR_h, "'Ht") \1521V(LDR_s, "'St") \1522V(LDR_d, "'Dt") \1523V(STR_q, "'Qt") \1524V(LDR_q, "'Qt")15251526void Disassembler::VisitLoadStorePreIndex(const Instruction *instr) {1527const char *form = "(LoadStorePreIndex)";1528const char *suffix = ", ['Xns'ILSi]!";15291530switch (instr->Mask(LoadStorePreIndexMask)) {1531#define LS_PREINDEX(A, B) \1532case A##_pre: \1533form = B; \1534break;1535LOAD_STORE_LIST(LS_PREINDEX)1536#undef LS_PREINDEX1537}1538FormatWithDecodedMnemonic(instr, form, suffix);1539}154015411542void Disassembler::VisitLoadStorePostIndex(const Instruction *instr) {1543const char *form = "(LoadStorePostIndex)";1544const char *suffix = ", ['Xns]'ILSi";15451546switch (instr->Mask(LoadStorePostIndexMask)) {1547#define LS_POSTINDEX(A, B) \1548case A##_post: \1549form = B; \1550break;1551LOAD_STORE_LIST(LS_POSTINDEX)1552#undef LS_POSTINDEX1553}1554FormatWithDecodedMnemonic(instr, form, suffix);1555}155615571558void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction *instr) {1559const char *form = "(LoadStoreUnsignedOffset)";1560const char *suffix = ", ['Xns'ILU]";15611562switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {1563#define LS_UNSIGNEDOFFSET(A, B) \1564case A##_unsigned: \1565form = B; \1566break;1567LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)1568#undef LS_UNSIGNEDOFFSET1569case PRFM_unsigned:1570form = "'prefOp";1571}1572FormatWithDecodedMnemonic(instr, form, suffix);1573}157415751576void Disassembler::VisitLoadStoreRCpcUnscaledOffset(const Instruction *instr) {1577const char *mnemonic = mnemonic_.c_str();1578const char *form = "'Wt, ['Xns'ILS]";1579const char *form_x = "'Xt, ['Xns'ILS]";15801581switch (form_hash_) {1582case "ldapursb_64_ldapstl_unscaled"_h:1583case "ldapursh_64_ldapstl_unscaled"_h:1584case "ldapursw_64_ldapstl_unscaled"_h:1585case "ldapur_64_ldapstl_unscaled"_h:1586case "stlur_64_ldapstl_unscaled"_h:1587form = form_x;1588break;1589}15901591Format(instr, mnemonic, form);1592}159315941595void Disassembler::VisitLoadStoreRegisterOffset(const Instruction *instr) {1596const char *form = "(LoadStoreRegisterOffset)";1597const char *suffix = ", ['Xns, 'Offsetreg]";15981599switch (instr->Mask(LoadStoreRegisterOffsetMask)) {1600#define LS_REGISTEROFFSET(A, B) \1601case A##_reg: \1602form = B; \1603break;1604LOAD_STORE_LIST(LS_REGISTEROFFSET)1605#undef LS_REGISTEROFFSET1606case PRFM_reg:1607form = "'prefOp";1608}1609FormatWithDecodedMnemonic(instr, form, suffix);1610}161116121613void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction *instr) {1614const char *form = "'Wt";1615const char *suffix = ", ['Xns'ILS]";16161617switch (form_hash_) {1618case "ldur_64_ldst_unscaled"_h:1619case "ldursb_64_ldst_unscaled"_h:1620case "ldursh_64_ldst_unscaled"_h:1621case "ldursw_64_ldst_unscaled"_h:1622case "stur_64_ldst_unscaled"_h:1623form = "'Xt";1624break;1625case "ldur_b_ldst_unscaled"_h:1626case "stur_b_ldst_unscaled"_h:1627form = "'Bt";1628break;1629case "ldur_h_ldst_unscaled"_h:1630case "stur_h_ldst_unscaled"_h:1631form = "'Ht";1632break;1633case "ldur_s_ldst_unscaled"_h:1634case "stur_s_ldst_unscaled"_h:1635form = "'St";1636break;1637case "ldur_d_ldst_unscaled"_h:1638case "stur_d_ldst_unscaled"_h:1639form = "'Dt";1640break;1641case "ldur_q_ldst_unscaled"_h:1642case "stur_q_ldst_unscaled"_h:1643form = "'Qt";1644break;1645case "prfum_p_ldst_unscaled"_h:1646form = "'prefOp";1647break;1648}1649FormatWithDecodedMnemonic(instr, form, suffix);1650}165116521653void Disassembler::VisitLoadLiteral(const Instruction *instr) {1654const char *form = "'Wt";1655const char *suffix = ", 'ILLiteral 'LValue";16561657switch (form_hash_) {1658case "ldr_64_loadlit"_h:1659case "ldrsw_64_loadlit"_h:1660form = "'Xt";1661break;1662case "ldr_s_loadlit"_h:1663form = "'St";1664break;1665case "ldr_d_loadlit"_h:1666form = "'Dt";1667break;1668case "ldr_q_loadlit"_h:1669form = "'Qt";1670break;1671case "prfm_p_loadlit"_h:1672form = "'prefOp";1673break;1674}1675FormatWithDecodedMnemonic(instr, form, suffix);1676}167716781679#define LOAD_STORE_PAIR_LIST(V) \1680V(STP_w, "'Wt, 'Wt2", "2") \1681V(LDP_w, "'Wt, 'Wt2", "2") \1682V(LDPSW_x, "'Xt, 'Xt2", "2") \1683V(STP_x, "'Xt, 'Xt2", "3") \1684V(LDP_x, "'Xt, 'Xt2", "3") \1685V(STP_s, "'St, 'St2", "2") \1686V(LDP_s, "'St, 'St2", "2") \1687V(STP_d, "'Dt, 'Dt2", "3") \1688V(LDP_d, "'Dt, 'Dt2", "3") \1689V(LDP_q, "'Qt, 'Qt2", "4") \1690V(STP_q, "'Qt, 'Qt2", "4")16911692void Disassembler::VisitLoadStorePairPostIndex(const Instruction *instr) {1693const char *form = "(LoadStorePairPostIndex)";16941695switch (instr->Mask(LoadStorePairPostIndexMask)) {1696#define LSP_POSTINDEX(A, B, C) \1697case A##_post: \1698form = B ", ['Xns]'ILP" C "i"; \1699break;1700LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)1701#undef LSP_POSTINDEX1702}1703FormatWithDecodedMnemonic(instr, form);1704}170517061707void Disassembler::VisitLoadStorePairPreIndex(const Instruction *instr) {1708const char *form = "(LoadStorePairPreIndex)";17091710switch (instr->Mask(LoadStorePairPreIndexMask)) {1711#define LSP_PREINDEX(A, B, C) \1712case A##_pre: \1713form = B ", ['Xns'ILP" C "i]!"; \1714break;1715LOAD_STORE_PAIR_LIST(LSP_PREINDEX)1716#undef LSP_PREINDEX1717}1718FormatWithDecodedMnemonic(instr, form);1719}172017211722void Disassembler::VisitLoadStorePairOffset(const Instruction *instr) {1723const char *form = "(LoadStorePairOffset)";17241725switch (instr->Mask(LoadStorePairOffsetMask)) {1726#define LSP_OFFSET(A, B, C) \1727case A##_off: \1728form = B ", ['Xns'ILP" C "]"; \1729break;1730LOAD_STORE_PAIR_LIST(LSP_OFFSET)1731#undef LSP_OFFSET1732}1733FormatWithDecodedMnemonic(instr, form);1734}173517361737void Disassembler::VisitLoadStorePairNonTemporal(const Instruction *instr) {1738const char *form = "'Wt, 'Wt2, ['Xns'ILP2]";17391740switch (form_hash_) {1741case "ldnp_64_ldstnapair_offs"_h:1742case "stnp_64_ldstnapair_offs"_h:1743form = "'Xt, 'Xt2, ['Xns'ILP3]";1744break;1745case "ldnp_s_ldstnapair_offs"_h:1746case "stnp_s_ldstnapair_offs"_h:1747form = "'St, 'St2, ['Xns'ILP2]";1748break;1749case "ldnp_d_ldstnapair_offs"_h:1750case "stnp_d_ldstnapair_offs"_h:1751form = "'Dt, 'Dt2, ['Xns'ILP3]";1752break;1753case "ldnp_q_ldstnapair_offs"_h:1754case "stnp_q_ldstnapair_offs"_h:1755form = "'Qt, 'Qt2, ['Xns'ILP4]";1756break;1757}1758FormatWithDecodedMnemonic(instr, form);1759}17601761// clang-format off1762#define LOAD_STORE_EXCLUSIVE_LIST(V) \1763V(STXRB_w, "'Ws, 'Wt") \1764V(STXRH_w, "'Ws, 'Wt") \1765V(STXR_w, "'Ws, 'Wt") \1766V(STXR_x, "'Ws, 'Xt") \1767V(LDXR_x, "'Xt") \1768V(STXP_w, "'Ws, 'Wt, 'Wt2") \1769V(STXP_x, "'Ws, 'Xt, 'Xt2") \1770V(LDXP_w, "'Wt, 'Wt2") \1771V(LDXP_x, "'Xt, 'Xt2") \1772V(STLXRB_w, "'Ws, 'Wt") \1773V(STLXRH_w, "'Ws, 'Wt") \1774V(STLXR_w, "'Ws, 'Wt") \1775V(STLXR_x, "'Ws, 'Xt") \1776V(LDAXR_x, "'Xt") \1777V(STLXP_w, "'Ws, 'Wt, 'Wt2") \1778V(STLXP_x, "'Ws, 'Xt, 'Xt2") \1779V(LDAXP_w, "'Wt, 'Wt2") \1780V(LDAXP_x, "'Xt, 'Xt2") \1781V(STLR_x, "'Xt") \1782V(LDAR_x, "'Xt") \1783V(STLLR_x, "'Xt") \1784V(LDLAR_x, "'Xt") \1785V(CAS_w, "'Ws, 'Wt") \1786V(CAS_x, "'Xs, 'Xt") \1787V(CASA_w, "'Ws, 'Wt") \1788V(CASA_x, "'Xs, 'Xt") \1789V(CASL_w, "'Ws, 'Wt") \1790V(CASL_x, "'Xs, 'Xt") \1791V(CASAL_w, "'Ws, 'Wt") \1792V(CASAL_x, "'Xs, 'Xt") \1793V(CASB, "'Ws, 'Wt") \1794V(CASAB, "'Ws, 'Wt") \1795V(CASLB, "'Ws, 'Wt") \1796V(CASALB, "'Ws, 'Wt") \1797V(CASH, "'Ws, 'Wt") \1798V(CASAH, "'Ws, 'Wt") \1799V(CASLH, "'Ws, 'Wt") \1800V(CASALH, "'Ws, 'Wt") \1801V(CASP_w, "'Ws, 'Ws+, 'Wt, 'Wt+") \1802V(CASP_x, "'Xs, 'Xs+, 'Xt, 'Xt+") \1803V(CASPA_w, "'Ws, 'Ws+, 'Wt, 'Wt+") \1804V(CASPA_x, "'Xs, 'Xs+, 'Xt, 'Xt+") \1805V(CASPL_w, "'Ws, 'Ws+, 'Wt, 'Wt+") \1806V(CASPL_x, "'Xs, 'Xs+, 'Xt, 'Xt+") \1807V(CASPAL_w, "'Ws, 'Ws+, 'Wt, 'Wt+") \1808V(CASPAL_x, "'Xs, 'Xs+, 'Xt, 'Xt+")1809// clang-format on181018111812void Disassembler::VisitLoadStoreExclusive(const Instruction *instr) {1813const char *form = "'Wt";1814const char *suffix = ", ['Xns]";18151816switch (instr->Mask(LoadStoreExclusiveMask)) {1817#define LSX(A, B) \1818case A: \1819form = B; \1820break;1821LOAD_STORE_EXCLUSIVE_LIST(LSX)1822#undef LSX1823}18241825switch (instr->Mask(LoadStoreExclusiveMask)) {1826case CASP_w:1827case CASP_x:1828case CASPA_w:1829case CASPA_x:1830case CASPL_w:1831case CASPL_x:1832case CASPAL_w:1833case CASPAL_x:1834if ((instr->GetRs() % 2 == 1) || (instr->GetRt() % 2 == 1)) {1835VisitUnallocated(instr);1836return;1837}1838break;1839}18401841FormatWithDecodedMnemonic(instr, form, suffix);1842}18431844void Disassembler::VisitLoadStorePAC(const Instruction *instr) {1845const char *form = "'Xt, ['Xns'ILA]";1846const char *suffix = "";1847switch (form_hash_) {1848case "ldraa_64w_ldst_pac"_h:1849case "ldrab_64w_ldst_pac"_h:1850suffix = "!";1851break;1852}1853FormatWithDecodedMnemonic(instr, form, suffix);1854}18551856void Disassembler::VisitAtomicMemory(const Instruction *instr) {1857bool is_x = (instr->ExtractBits(31, 30) == 3);1858const char *form = is_x ? "'Xs, 'Xt" : "'Ws, 'Wt";1859const char *suffix = ", ['Xns]";18601861std::string mnemonic = mnemonic_;18621863switch (form_hash_) {1864case "ldaprb_32l_memop"_h:1865case "ldaprh_32l_memop"_h:1866case "ldapr_32l_memop"_h:1867form = "'Wt";1868break;1869case "ldapr_64l_memop"_h:1870form = "'Xt";1871break;1872default:1873// Zero register implies a store instruction.1874if (instr->GetRt() == kZeroRegCode) {1875mnemonic.replace(0, 2, "st");1876form = is_x ? "'Xs" : "'Ws";1877}1878}1879Format(instr, mnemonic.c_str(), form, suffix);1880}188118821883void Disassembler::VisitFPCompare(const Instruction *instr) {1884const char *form = "'Fn, 'Fm";1885switch (form_hash_) {1886case "fcmpe_dz_floatcmp"_h:1887case "fcmpe_hz_floatcmp"_h:1888case "fcmpe_sz_floatcmp"_h:1889case "fcmp_dz_floatcmp"_h:1890case "fcmp_hz_floatcmp"_h:1891case "fcmp_sz_floatcmp"_h:1892form = "'Fn, #0.0";1893}1894FormatWithDecodedMnemonic(instr, form);1895}189618971898void Disassembler::VisitFPConditionalCompare(const Instruction *instr) {1899FormatWithDecodedMnemonic(instr, "'Fn, 'Fm, 'INzcv, 'Cond");1900}190119021903void Disassembler::VisitFPConditionalSelect(const Instruction *instr) {1904FormatWithDecodedMnemonic(instr, "'Fd, 'Fn, 'Fm, 'Cond");1905}190619071908void Disassembler::VisitFPDataProcessing1Source(const Instruction *instr) {1909const char *form = "'Fd, 'Fn";1910switch (form_hash_) {1911case "fcvt_ds_floatdp1"_h:1912form = "'Dd, 'Sn";1913break;1914case "fcvt_sd_floatdp1"_h:1915form = "'Sd, 'Dn";1916break;1917case "fcvt_hs_floatdp1"_h:1918form = "'Hd, 'Sn";1919break;1920case "fcvt_sh_floatdp1"_h:1921form = "'Sd, 'Hn";1922break;1923case "fcvt_dh_floatdp1"_h:1924form = "'Dd, 'Hn";1925break;1926case "fcvt_hd_floatdp1"_h:1927form = "'Hd, 'Dn";1928break;1929}1930FormatWithDecodedMnemonic(instr, form);1931}193219331934void Disassembler::VisitFPDataProcessing2Source(const Instruction *instr) {1935FormatWithDecodedMnemonic(instr, "'Fd, 'Fn, 'Fm");1936}193719381939void Disassembler::VisitFPDataProcessing3Source(const Instruction *instr) {1940FormatWithDecodedMnemonic(instr, "'Fd, 'Fn, 'Fm, 'Fa");1941}194219431944void Disassembler::VisitFPImmediate(const Instruction *instr) {1945const char *form = "'Hd";1946const char *suffix = ", 'IFP";1947switch (form_hash_) {1948case "fmov_s_floatimm"_h:1949form = "'Sd";1950break;1951case "fmov_d_floatimm"_h:1952form = "'Dd";1953break;1954}1955FormatWithDecodedMnemonic(instr, form, suffix);1956}195719581959void Disassembler::VisitFPIntegerConvert(const Instruction *instr) {1960const char *form = "'Rd, 'Fn";1961switch (form_hash_) {1962case "fmov_h32_float2int"_h:1963case "fmov_h64_float2int"_h:1964case "fmov_s32_float2int"_h:1965case "fmov_d64_float2int"_h:1966case "scvtf_d32_float2int"_h:1967case "scvtf_d64_float2int"_h:1968case "scvtf_h32_float2int"_h:1969case "scvtf_h64_float2int"_h:1970case "scvtf_s32_float2int"_h:1971case "scvtf_s64_float2int"_h:1972case "ucvtf_d32_float2int"_h:1973case "ucvtf_d64_float2int"_h:1974case "ucvtf_h32_float2int"_h:1975case "ucvtf_h64_float2int"_h:1976case "ucvtf_s32_float2int"_h:1977case "ucvtf_s64_float2int"_h:1978form = "'Fd, 'Rn";1979break;1980case "fmov_v64i_float2int"_h:1981form = "'Vd.D[1], 'Rn";1982break;1983case "fmov_64vx_float2int"_h:1984form = "'Rd, 'Vn.D[1]";1985break;1986}1987FormatWithDecodedMnemonic(instr, form);1988}198919901991void Disassembler::VisitFPFixedPointConvert(const Instruction *instr) {1992const char *form = "'Rd, 'Fn";1993const char *suffix = ", 'IFPFBits";19941995switch (form_hash_) {1996case "scvtf_d32_float2fix"_h:1997case "scvtf_d64_float2fix"_h:1998case "scvtf_h32_float2fix"_h:1999case "scvtf_h64_float2fix"_h:2000case "scvtf_s32_float2fix"_h:2001case "scvtf_s64_float2fix"_h:2002case "ucvtf_d32_float2fix"_h:2003case "ucvtf_d64_float2fix"_h:2004case "ucvtf_h32_float2fix"_h:2005case "ucvtf_h64_float2fix"_h:2006case "ucvtf_s32_float2fix"_h:2007case "ucvtf_s64_float2fix"_h:2008form = "'Fd, 'Rn";2009break;2010}2011FormatWithDecodedMnemonic(instr, form, suffix);2012}20132014void Disassembler::DisassembleNoArgs(const Instruction *instr) {2015Format(instr, mnemonic_.c_str(), "");2016}20172018void Disassembler::VisitSystem(const Instruction *instr) {2019const char *mnemonic = mnemonic_.c_str();2020const char *form = "(System)";2021const char *suffix = NULL;20222023switch (form_hash_) {2024case "clrex_bn_barriers"_h:2025form = (instr->GetCRm() == 0xf) ? "" : "'IX";2026break;2027case "mrs_rs_systemmove"_h:2028form = "'Xt, 'IY";2029break;2030case "msr_sr_systemmove"_h:2031form = "'IY, 'Xt";2032break;2033case "bti_hb_hints"_h:2034switch (instr->ExtractBits(7, 6)) {2035case 0:2036form = "";2037break;2038case 1:2039form = "c";2040break;2041case 2:2042form = "j";2043break;2044case 3:2045form = "jc";2046break;2047}2048break;2049case "hint_hm_hints"_h:2050form = "'IH";2051break;2052case Hash("dmb_bo_barriers"):2053form = "'M";2054break;2055case Hash("dsb_bo_barriers"): {2056int crm = instr->GetCRm();2057if (crm == 0) {2058mnemonic = "ssbb";2059form = "";2060} else if (crm == 4) {2061mnemonic = "pssbb";2062form = "";2063} else {2064form = "'M";2065}2066break;2067}2068case Hash("sys_cr_systeminstrs"): {2069mnemonic = "dc";2070suffix = ", 'Xt";20712072const std::map<uint32_t, const char *> dcop = {2073{IVAU, "ivau"},2074{CVAC, "cvac"},2075{CVAU, "cvau"},2076{CVAP, "cvap"},2077{CVADP, "cvadp"},2078{CIVAC, "civac"},2079{ZVA, "zva"},2080{GVA, "gva"},2081{GZVA, "gzva"},2082{CGVAC, "cgvac"},2083{CGDVAC, "cgdvac"},2084{CGVAP, "cgvap"},2085{CGDVAP, "cgdvap"},2086{CIGVAC, "cigvac"},2087{CIGDVAC, "cigdvac"},2088};20892090uint32_t sysop = instr->GetSysOp();2091if (dcop.count(sysop)) {2092if (sysop == IVAU) {2093mnemonic = "ic";2094}2095form = dcop.at(sysop);2096} else {2097mnemonic = "sys";2098form = "'G1, 'Kn, 'Km, 'G2";2099if (instr->GetRt() == 31) {2100suffix = NULL;2101}2102break;2103}2104}2105}2106Format(instr, mnemonic, form, suffix);2107}210821092110void Disassembler::VisitException(const Instruction *instr) {2111const char *mnemonic = "unimplemented";2112const char *form = "'IDebug";21132114switch (instr->Mask(ExceptionMask)) {2115case HLT:2116mnemonic = "hlt";2117break;2118case BRK:2119mnemonic = "brk";2120break;2121case SVC:2122mnemonic = "svc";2123break;2124case HVC:2125mnemonic = "hvc";2126break;2127case SMC:2128mnemonic = "smc";2129break;2130case DCPS1:2131mnemonic = "dcps1";2132form = "{'IDebug}";2133break;2134case DCPS2:2135mnemonic = "dcps2";2136form = "{'IDebug}";2137break;2138case DCPS3:2139mnemonic = "dcps3";2140form = "{'IDebug}";2141break;2142default:2143form = "(Exception)";2144}2145Format(instr, mnemonic, form);2146}214721482149void Disassembler::VisitCrypto2RegSHA(const Instruction *instr) {2150VisitUnimplemented(instr);2151}215221532154void Disassembler::VisitCrypto3RegSHA(const Instruction *instr) {2155VisitUnimplemented(instr);2156}215721582159void Disassembler::VisitCryptoAES(const Instruction *instr) {2160VisitUnimplemented(instr);2161}21622163void Disassembler::DisassembleNEON2RegAddlp(const Instruction *instr) {2164const char *mnemonic = mnemonic_.c_str();2165const char *form = "'Vd.%s, 'Vn.%s";21662167static const NEONFormatMap map_lp_ta =2168{{23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}};2169NEONFormatDecoder nfd(instr);2170nfd.SetFormatMap(0, &map_lp_ta);2171Format(instr, mnemonic, nfd.Substitute(form));2172}21732174void Disassembler::DisassembleNEON2RegCompare(const Instruction *instr) {2175const char *mnemonic = mnemonic_.c_str();2176const char *form = "'Vd.%s, 'Vn.%s, #0";2177NEONFormatDecoder nfd(instr);2178Format(instr, mnemonic, nfd.Substitute(form));2179}21802181void Disassembler::DisassembleNEON2RegFPCompare(const Instruction *instr) {2182const char *mnemonic = mnemonic_.c_str();2183const char *form = "'Vd.%s, 'Vn.%s, #0.0";2184NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPFormatMap());2185Format(instr, mnemonic, nfd.Substitute(form));2186}21872188void Disassembler::DisassembleNEON2RegFPConvert(const Instruction *instr) {2189const char *mnemonic = mnemonic_.c_str();2190const char *form = "'Vd.%s, 'Vn.%s";2191static const NEONFormatMap map_cvt_ta = {{22}, {NF_4S, NF_2D}};21922193static const NEONFormatMap map_cvt_tb = {{22, 30},2194{NF_4H, NF_8H, NF_2S, NF_4S}};2195NEONFormatDecoder nfd(instr, &map_cvt_tb, &map_cvt_ta);21962197VectorFormat vform_dst = nfd.GetVectorFormat(0);2198switch (form_hash_) {2199case "fcvtl_asimdmisc_l"_h:2200nfd.SetFormatMaps(&map_cvt_ta, &map_cvt_tb);2201break;2202case "fcvtxn_asimdmisc_n"_h:2203if ((vform_dst != kFormat2S) && (vform_dst != kFormat4S)) {2204mnemonic = NULL;2205}2206break;2207}2208Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));2209}22102211void Disassembler::DisassembleNEON2RegFP(const Instruction *instr) {2212const char *mnemonic = mnemonic_.c_str();2213const char *form = "'Vd.%s, 'Vn.%s";2214NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPFormatMap());2215Format(instr, mnemonic, nfd.Substitute(form));2216}22172218void Disassembler::DisassembleNEON2RegLogical(const Instruction *instr) {2219const char *mnemonic = mnemonic_.c_str();2220const char *form = "'Vd.%s, 'Vn.%s";2221NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());2222if (form_hash_ == "not_asimdmisc_r"_h) {2223mnemonic = "mvn";2224}2225Format(instr, mnemonic, nfd.Substitute(form));2226}22272228void Disassembler::DisassembleNEON2RegExtract(const Instruction *instr) {2229const char *mnemonic = mnemonic_.c_str();2230const char *form = "'Vd.%s, 'Vn.%s";2231const char *suffix = NULL;2232NEONFormatDecoder nfd(instr,2233NEONFormatDecoder::IntegerFormatMap(),2234NEONFormatDecoder::LongIntegerFormatMap());22352236if (form_hash_ == "shll_asimdmisc_s"_h) {2237nfd.SetFormatMaps(nfd.LongIntegerFormatMap(), nfd.IntegerFormatMap());2238switch (instr->GetNEONSize()) {2239case 0:2240suffix = ", #8";2241break;2242case 1:2243suffix = ", #16";2244break;2245case 2:2246suffix = ", #32";2247break;2248}2249}2250Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form), suffix);2251}22522253void Disassembler::VisitNEON2RegMisc(const Instruction *instr) {2254const char *mnemonic = mnemonic_.c_str();2255const char *form = "'Vd.%s, 'Vn.%s";2256NEONFormatDecoder nfd(instr);22572258VectorFormat vform_dst = nfd.GetVectorFormat(0);2259if (vform_dst != kFormatUndefined) {2260uint32_t ls_dst = LaneSizeInBitsFromFormat(vform_dst);2261switch (form_hash_) {2262case "cnt_asimdmisc_r"_h:2263case "rev16_asimdmisc_r"_h:2264if (ls_dst != kBRegSize) {2265mnemonic = NULL;2266}2267break;2268case "rev32_asimdmisc_r"_h:2269if ((ls_dst == kDRegSize) || (ls_dst == kSRegSize)) {2270mnemonic = NULL;2271}2272break;2273case "urecpe_asimdmisc_r"_h:2274case "ursqrte_asimdmisc_r"_h:2275// For urecpe and ursqrte, only S-sized elements are supported. The MSB2276// of the size field is always set by the instruction (0b1x) so we need2277// only check and discard D-sized elements here.2278VIXL_ASSERT((ls_dst == kSRegSize) || (ls_dst == kDRegSize));2279VIXL_FALLTHROUGH();2280case "clz_asimdmisc_r"_h:2281case "cls_asimdmisc_r"_h:2282case "rev64_asimdmisc_r"_h:2283if (ls_dst == kDRegSize) {2284mnemonic = NULL;2285}2286break;2287}2288}22892290Format(instr, mnemonic, nfd.Substitute(form));2291}22922293void Disassembler::VisitNEON2RegMiscFP16(const Instruction *instr) {2294const char *mnemonic = mnemonic_.c_str();2295const char *form = "'Vd.'?30:84h, 'Vn.'?30:84h";2296const char *suffix = NULL;22972298switch (form_hash_) {2299case "fcmeq_asimdmiscfp16_fz"_h:2300case "fcmge_asimdmiscfp16_fz"_h:2301case "fcmgt_asimdmiscfp16_fz"_h:2302case "fcmle_asimdmiscfp16_fz"_h:2303case "fcmlt_asimdmiscfp16_fz"_h:2304suffix = ", #0.0";2305}2306Format(instr, mnemonic, form, suffix);2307}23082309void Disassembler::DisassembleNEON3SameLogical(const Instruction *instr) {2310const char *mnemonic = mnemonic_.c_str();2311const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";2312NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());23132314switch (form_hash_) {2315case "orr_asimdsame_only"_h:2316if (instr->GetRm() == instr->GetRn()) {2317mnemonic = "mov";2318form = "'Vd.%s, 'Vn.%s";2319}2320break;2321case "pmul_asimdsame_only"_h:2322if (instr->GetNEONSize() != 0) {2323mnemonic = NULL;2324}2325}2326Format(instr, mnemonic, nfd.Substitute(form));2327}23282329void Disassembler::DisassembleNEON3SameFHM(const Instruction *instr) {2330FormatWithDecodedMnemonic(instr, "'Vd.'?30:42s, 'Vn.'?30:42h, 'Vm.'?30:42h");2331}23322333void Disassembler::DisassembleNEON3SameNoD(const Instruction *instr) {2334const char *mnemonic = mnemonic_.c_str();2335const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";2336static const NEONFormatMap map =2337{{23, 22, 30},2338{NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_UNDEF}};2339NEONFormatDecoder nfd(instr, &map);2340Format(instr, mnemonic, nfd.Substitute(form));2341}23422343void Disassembler::VisitNEON3Same(const Instruction *instr) {2344const char *mnemonic = mnemonic_.c_str();2345const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";2346NEONFormatDecoder nfd(instr);23472348if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {2349nfd.SetFormatMaps(nfd.FPFormatMap());2350}23512352VectorFormat vform_dst = nfd.GetVectorFormat(0);2353if (vform_dst != kFormatUndefined) {2354uint32_t ls_dst = LaneSizeInBitsFromFormat(vform_dst);2355switch (form_hash_) {2356case "sqdmulh_asimdsame_only"_h:2357case "sqrdmulh_asimdsame_only"_h:2358if ((ls_dst == kBRegSize) || (ls_dst == kDRegSize)) {2359mnemonic = NULL;2360}2361break;2362}2363}2364Format(instr, mnemonic, nfd.Substitute(form));2365}23662367void Disassembler::VisitNEON3SameFP16(const Instruction *instr) {2368const char *mnemonic = mnemonic_.c_str();2369const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";2370NEONFormatDecoder nfd(instr);2371nfd.SetFormatMaps(nfd.FP16FormatMap());2372Format(instr, mnemonic, nfd.Substitute(form));2373}23742375void Disassembler::VisitNEON3SameExtra(const Instruction *instr) {2376static const NEONFormatMap map_dot =2377{{23, 22, 30}, {NF_UNDEF, NF_UNDEF, NF_UNDEF, NF_UNDEF, NF_2S, NF_4S}};2378static const NEONFormatMap map_fc =2379{{23, 22, 30},2380{NF_UNDEF, NF_UNDEF, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D}};2381static const NEONFormatMap map_rdm =2382{{23, 22, 30}, {NF_UNDEF, NF_UNDEF, NF_4H, NF_8H, NF_2S, NF_4S}};23832384const char *mnemonic = mnemonic_.c_str();2385const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";2386const char *suffix = NULL;23872388NEONFormatDecoder nfd(instr, &map_fc);23892390switch (form_hash_) {2391case "fcmla_asimdsame2_c"_h:2392suffix = ", #'u1211*90";2393break;2394case "fcadd_asimdsame2_c"_h:2395// Bit 10 is always set, so this gives 90 * 1 or 3.2396suffix = ", #'u1212:1010*90";2397break;2398case "sdot_asimdsame2_d"_h:2399case "udot_asimdsame2_d"_h:2400case "usdot_asimdsame2_d"_h:2401nfd.SetFormatMaps(nfd.LogicalFormatMap());2402nfd.SetFormatMap(0, &map_dot);2403break;2404default:2405nfd.SetFormatMaps(&map_rdm);2406break;2407}24082409Format(instr, mnemonic, nfd.Substitute(form), suffix);2410}241124122413void Disassembler::VisitNEON3Different(const Instruction *instr) {2414const char *mnemonic = mnemonic_.c_str();2415const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s";24162417NEONFormatDecoder nfd(instr);2418nfd.SetFormatMap(0, nfd.LongIntegerFormatMap());24192420switch (form_hash_) {2421case "saddw_asimddiff_w"_h:2422case "ssubw_asimddiff_w"_h:2423case "uaddw_asimddiff_w"_h:2424case "usubw_asimddiff_w"_h:2425nfd.SetFormatMap(1, nfd.LongIntegerFormatMap());2426break;2427case "addhn_asimddiff_n"_h:2428case "raddhn_asimddiff_n"_h:2429case "rsubhn_asimddiff_n"_h:2430case "subhn_asimddiff_n"_h:2431nfd.SetFormatMaps(nfd.LongIntegerFormatMap());2432nfd.SetFormatMap(0, nfd.IntegerFormatMap());2433break;2434case "sqdmlal_asimddiff_l"_h:2435case "sqdmlsl_asimddiff_l"_h:2436case "sqdmull_asimddiff_l"_h:2437if (nfd.GetVectorFormat(0) == kFormat8H) {2438mnemonic = NULL;2439}2440break;2441}2442Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));2443}24442445void Disassembler::DisassembleNEONPolynomialMul(const Instruction *instr) {2446const char *mnemonic = instr->ExtractBit(30) ? "pmull2" : "pmull";2447const char *form = NULL;2448int size = instr->ExtractBits(23, 22);2449if (size == 0) {2450// Bits 30:27 of the instruction are x001, where x is the Q bit. Map2451// this to "8" and "16" by adding 7.2452form = "'Vd.8h, 'Vn.'u3127+7b, 'Vm.'u3127+7b";2453} else if (size == 3) {2454form = "'Vd.1q, 'Vn.'?30:21d, 'Vm.'?30:21d";2455} else {2456mnemonic = NULL;2457}2458Format(instr, mnemonic, form);2459}24602461void Disassembler::DisassembleNEONFPAcrossLanes(const Instruction *instr) {2462const char *mnemonic = mnemonic_.c_str();2463const char *form = "'Sd, 'Vn.4s";2464if ((instr->GetNEONQ() == 0) || (instr->ExtractBit(22) == 1)) {2465mnemonic = NULL;2466}2467Format(instr, mnemonic, form);2468}24692470void Disassembler::DisassembleNEONFP16AcrossLanes(const Instruction *instr) {2471FormatWithDecodedMnemonic(instr, "'Hd, 'Vn.'?30:84h");2472}24732474void Disassembler::VisitNEONAcrossLanes(const Instruction *instr) {2475const char *mnemonic = mnemonic_.c_str();2476const char *form = "%sd, 'Vn.%s";24772478NEONFormatDecoder nfd(instr,2479NEONFormatDecoder::ScalarFormatMap(),2480NEONFormatDecoder::IntegerFormatMap());24812482switch (form_hash_) {2483case "saddlv_asimdall_only"_h:2484case "uaddlv_asimdall_only"_h:2485nfd.SetFormatMap(0, nfd.LongScalarFormatMap());2486}24872488VectorFormat vform_src = nfd.GetVectorFormat(1);2489if ((vform_src == kFormat2S) || (vform_src == kFormat2D)) {2490mnemonic = NULL;2491}24922493Format(instr,2494mnemonic,2495nfd.Substitute(form,2496NEONFormatDecoder::kPlaceholder,2497NEONFormatDecoder::kFormat));2498}24992500void Disassembler::VisitNEONByIndexedElement(const Instruction *instr) {2501const char *form = "'Vd.%s, 'Vn.%s, 'Vf.%s['IVByElemIndex]";2502static const NEONFormatMap map_v =2503{{23, 22, 30},2504{NF_UNDEF, NF_UNDEF, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_UNDEF}};2505static const NEONFormatMap map_s = {{23, 22},2506{NF_UNDEF, NF_H, NF_S, NF_UNDEF}};2507NEONFormatDecoder nfd(instr, &map_v, &map_v, &map_s);2508Format(instr, mnemonic_.c_str(), nfd.Substitute(form));2509}25102511void Disassembler::DisassembleNEONMulByElementLong(const Instruction *instr) {2512const char *form = "'Vd.%s, 'Vn.%s, 'Vf.%s['IVByElemIndex]";2513// TODO: Disallow undefined element types for this instruction.2514static const NEONFormatMap map_ta = {{23, 22}, {NF_UNDEF, NF_4S, NF_2D}};2515NEONFormatDecoder nfd(instr,2516&map_ta,2517NEONFormatDecoder::IntegerFormatMap(),2518NEONFormatDecoder::ScalarFormatMap());2519Format(instr, nfd.Mnemonic(mnemonic_.c_str()), nfd.Substitute(form));2520}25212522void Disassembler::DisassembleNEONDotProdByElement(const Instruction *instr) {2523const char *form = instr->ExtractBit(30) ? "'Vd.4s, 'Vn.16" : "'Vd.2s, 'Vn.8";2524const char *suffix = "b, 'Vm.4b['u1111:2121]";2525Format(instr, mnemonic_.c_str(), form, suffix);2526}25272528void Disassembler::DisassembleNEONFPMulByElement(const Instruction *instr) {2529const char *form = "'Vd.%s, 'Vn.%s, 'Vf.%s['IVByElemIndex]";2530NEONFormatDecoder nfd(instr,2531NEONFormatDecoder::FPFormatMap(),2532NEONFormatDecoder::FPFormatMap(),2533NEONFormatDecoder::FPScalarFormatMap());2534Format(instr, mnemonic_.c_str(), nfd.Substitute(form));2535}25362537void Disassembler::DisassembleNEONHalfFPMulByElement(const Instruction *instr) {2538FormatWithDecodedMnemonic(instr,2539"'Vd.'?30:84h, 'Vn.'?30:84h, "2540"'Ve.h['IVByElemIndex]");2541}25422543void Disassembler::DisassembleNEONFPMulByElementLong(const Instruction *instr) {2544FormatWithDecodedMnemonic(instr,2545"'Vd.'?30:42s, 'Vn.'?30:42h, "2546"'Ve.h['IVByElemIndexFHM]");2547}25482549void Disassembler::DisassembleNEONComplexMulByElement(2550const Instruction *instr) {2551const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s['IVByElemIndexRot], #'u1413*90";2552// TODO: Disallow undefined element types for this instruction.2553static const NEONFormatMap map_cn =2554{{23, 22, 30},2555{NF_UNDEF, NF_UNDEF, NF_4H, NF_8H, NF_UNDEF, NF_4S, NF_UNDEF, NF_UNDEF}};2556NEONFormatDecoder nfd(instr,2557&map_cn,2558&map_cn,2559NEONFormatDecoder::ScalarFormatMap());2560Format(instr, mnemonic_.c_str(), nfd.Substitute(form));2561}25622563void Disassembler::VisitNEONCopy(const Instruction *instr) {2564const char *mnemonic = mnemonic_.c_str();2565const char *form = "(NEONCopy)";25662567NEONFormatDecoder nfd(instr,2568NEONFormatDecoder::TriangularFormatMap(),2569NEONFormatDecoder::TriangularScalarFormatMap());25702571switch (form_hash_) {2572case "ins_asimdins_iv_v"_h:2573mnemonic = "mov";2574nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());2575form = "'Vd.%s['IVInsIndex1], 'Vn.%s['IVInsIndex2]";2576break;2577case "ins_asimdins_ir_r"_h:2578mnemonic = "mov";2579nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());2580if (nfd.GetVectorFormat() == kFormatD) {2581form = "'Vd.%s['IVInsIndex1], 'Xn";2582} else {2583form = "'Vd.%s['IVInsIndex1], 'Wn";2584}2585break;2586case "umov_asimdins_w_w"_h:2587case "umov_asimdins_x_x"_h:2588if (instr->Mask(NEON_Q) || ((instr->GetImmNEON5() & 7) == 4)) {2589mnemonic = "mov";2590}2591nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());2592if (nfd.GetVectorFormat() == kFormatD) {2593form = "'Xd, 'Vn.%s['IVInsIndex1]";2594} else {2595form = "'Wd, 'Vn.%s['IVInsIndex1]";2596}2597break;2598case "smov_asimdins_w_w"_h:2599case "smov_asimdins_x_x"_h: {2600nfd.SetFormatMap(0, nfd.TriangularScalarFormatMap());2601VectorFormat vform = nfd.GetVectorFormat();2602if ((vform == kFormatD) ||2603((vform == kFormatS) && (instr->ExtractBit(30) == 0))) {2604mnemonic = NULL;2605}2606form = "'R30d, 'Vn.%s['IVInsIndex1]";2607break;2608}2609case "dup_asimdins_dv_v"_h:2610form = "'Vd.%s, 'Vn.%s['IVInsIndex1]";2611break;2612case "dup_asimdins_dr_r"_h:2613if (nfd.GetVectorFormat() == kFormat2D) {2614form = "'Vd.%s, 'Xn";2615} else {2616form = "'Vd.%s, 'Wn";2617}2618}2619Format(instr, mnemonic, nfd.Substitute(form));2620}262126222623void Disassembler::VisitNEONExtract(const Instruction *instr) {2624const char *mnemonic = mnemonic_.c_str();2625const char *form = "'Vd.%s, 'Vn.%s, 'Vm.%s, 'IVExtract";2626NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());2627if ((instr->GetImmNEONExt() > 7) && (instr->GetNEONQ() == 0)) {2628mnemonic = NULL;2629}2630Format(instr, mnemonic, nfd.Substitute(form));2631}263226332634void Disassembler::VisitNEONLoadStoreMultiStruct(const Instruction *instr) {2635const char *mnemonic = NULL;2636const char *form = NULL;2637const char *form_1v = "{'Vt.%1$s}, ['Xns]";2638const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns]";2639const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns]";2640const char *form_4v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]";2641NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());26422643switch (instr->Mask(NEONLoadStoreMultiStructMask)) {2644case NEON_LD1_1v:2645mnemonic = "ld1";2646form = form_1v;2647break;2648case NEON_LD1_2v:2649mnemonic = "ld1";2650form = form_2v;2651break;2652case NEON_LD1_3v:2653mnemonic = "ld1";2654form = form_3v;2655break;2656case NEON_LD1_4v:2657mnemonic = "ld1";2658form = form_4v;2659break;2660case NEON_LD2:2661mnemonic = "ld2";2662form = form_2v;2663break;2664case NEON_LD3:2665mnemonic = "ld3";2666form = form_3v;2667break;2668case NEON_LD4:2669mnemonic = "ld4";2670form = form_4v;2671break;2672case NEON_ST1_1v:2673mnemonic = "st1";2674form = form_1v;2675break;2676case NEON_ST1_2v:2677mnemonic = "st1";2678form = form_2v;2679break;2680case NEON_ST1_3v:2681mnemonic = "st1";2682form = form_3v;2683break;2684case NEON_ST1_4v:2685mnemonic = "st1";2686form = form_4v;2687break;2688case NEON_ST2:2689mnemonic = "st2";2690form = form_2v;2691break;2692case NEON_ST3:2693mnemonic = "st3";2694form = form_3v;2695break;2696case NEON_ST4:2697mnemonic = "st4";2698form = form_4v;2699break;2700default:2701break;2702}27032704// Work out unallocated encodings.2705bool allocated = (mnemonic != NULL);2706switch (instr->Mask(NEONLoadStoreMultiStructMask)) {2707case NEON_LD2:2708case NEON_LD3:2709case NEON_LD4:2710case NEON_ST2:2711case NEON_ST3:2712case NEON_ST4:2713// LD[2-4] and ST[2-4] cannot use .1d format.2714allocated = (instr->GetNEONQ() != 0) || (instr->GetNEONLSSize() != 3);2715break;2716default:2717break;2718}2719if (allocated) {2720VIXL_ASSERT(mnemonic != NULL);2721VIXL_ASSERT(form != NULL);2722} else {2723mnemonic = "unallocated";2724form = "(NEONLoadStoreMultiStruct)";2725}27262727Format(instr, mnemonic, nfd.Substitute(form));2728}272927302731void Disassembler::VisitNEONLoadStoreMultiStructPostIndex(2732const Instruction *instr) {2733const char *mnemonic = NULL;2734const char *form = NULL;2735const char *form_1v = "{'Vt.%1$s}, ['Xns], 'Xmr1";2736const char *form_2v = "{'Vt.%1$s, 'Vt2.%1$s}, ['Xns], 'Xmr2";2737const char *form_3v = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s}, ['Xns], 'Xmr3";2738const char *form_4v =2739"{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmr4";2740NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());27412742switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {2743case NEON_LD1_1v_post:2744mnemonic = "ld1";2745form = form_1v;2746break;2747case NEON_LD1_2v_post:2748mnemonic = "ld1";2749form = form_2v;2750break;2751case NEON_LD1_3v_post:2752mnemonic = "ld1";2753form = form_3v;2754break;2755case NEON_LD1_4v_post:2756mnemonic = "ld1";2757form = form_4v;2758break;2759case NEON_LD2_post:2760mnemonic = "ld2";2761form = form_2v;2762break;2763case NEON_LD3_post:2764mnemonic = "ld3";2765form = form_3v;2766break;2767case NEON_LD4_post:2768mnemonic = "ld4";2769form = form_4v;2770break;2771case NEON_ST1_1v_post:2772mnemonic = "st1";2773form = form_1v;2774break;2775case NEON_ST1_2v_post:2776mnemonic = "st1";2777form = form_2v;2778break;2779case NEON_ST1_3v_post:2780mnemonic = "st1";2781form = form_3v;2782break;2783case NEON_ST1_4v_post:2784mnemonic = "st1";2785form = form_4v;2786break;2787case NEON_ST2_post:2788mnemonic = "st2";2789form = form_2v;2790break;2791case NEON_ST3_post:2792mnemonic = "st3";2793form = form_3v;2794break;2795case NEON_ST4_post:2796mnemonic = "st4";2797form = form_4v;2798break;2799default:2800break;2801}28022803// Work out unallocated encodings.2804bool allocated = (mnemonic != NULL);2805switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {2806case NEON_LD2_post:2807case NEON_LD3_post:2808case NEON_LD4_post:2809case NEON_ST2_post:2810case NEON_ST3_post:2811case NEON_ST4_post:2812// LD[2-4] and ST[2-4] cannot use .1d format.2813allocated = (instr->GetNEONQ() != 0) || (instr->GetNEONLSSize() != 3);2814break;2815default:2816break;2817}2818if (allocated) {2819VIXL_ASSERT(mnemonic != NULL);2820VIXL_ASSERT(form != NULL);2821} else {2822mnemonic = "unallocated";2823form = "(NEONLoadStoreMultiStructPostIndex)";2824}28252826Format(instr, mnemonic, nfd.Substitute(form));2827}282828292830void Disassembler::VisitNEONLoadStoreSingleStruct(const Instruction *instr) {2831const char *mnemonic = NULL;2832const char *form = NULL;28332834const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns]";2835const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns]";2836const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns]";2837const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns]";2838NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());28392840switch (instr->Mask(NEONLoadStoreSingleStructMask)) {2841case NEON_LD1_b:2842mnemonic = "ld1";2843form = form_1b;2844break;2845case NEON_LD1_h:2846mnemonic = "ld1";2847form = form_1h;2848break;2849case NEON_LD1_s:2850mnemonic = "ld1";2851VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);2852form = ((instr->GetNEONLSSize() & 1) == 0) ? form_1s : form_1d;2853break;2854case NEON_ST1_b:2855mnemonic = "st1";2856form = form_1b;2857break;2858case NEON_ST1_h:2859mnemonic = "st1";2860form = form_1h;2861break;2862case NEON_ST1_s:2863mnemonic = "st1";2864VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);2865form = ((instr->GetNEONLSSize() & 1) == 0) ? form_1s : form_1d;2866break;2867case NEON_LD1R:2868mnemonic = "ld1r";2869form = "{'Vt.%s}, ['Xns]";2870break;2871case NEON_LD2_b:2872case NEON_ST2_b:2873mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";2874form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns]";2875break;2876case NEON_LD2_h:2877case NEON_ST2_h:2878mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";2879form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns]";2880break;2881case NEON_LD2_s:2882case NEON_ST2_s:2883VIXL_STATIC_ASSERT((NEON_ST2_s | (1 << NEONLSSize_offset)) == NEON_ST2_d);2884VIXL_STATIC_ASSERT((NEON_LD2_s | (1 << NEONLSSize_offset)) == NEON_LD2_d);2885mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";2886if ((instr->GetNEONLSSize() & 1) == 0) {2887form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns]";2888} else {2889form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns]";2890}2891break;2892case NEON_LD2R:2893mnemonic = "ld2r";2894form = "{'Vt.%s, 'Vt2.%s}, ['Xns]";2895break;2896case NEON_LD3_b:2897case NEON_ST3_b:2898mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";2899form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns]";2900break;2901case NEON_LD3_h:2902case NEON_ST3_h:2903mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";2904form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns]";2905break;2906case NEON_LD3_s:2907case NEON_ST3_s:2908mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";2909if ((instr->GetNEONLSSize() & 1) == 0) {2910form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns]";2911} else {2912form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns]";2913}2914break;2915case NEON_LD3R:2916mnemonic = "ld3r";2917form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns]";2918break;2919case NEON_LD4_b:2920case NEON_ST4_b:2921mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";2922form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns]";2923break;2924case NEON_LD4_h:2925case NEON_ST4_h:2926mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";2927form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns]";2928break;2929case NEON_LD4_s:2930case NEON_ST4_s:2931VIXL_STATIC_ASSERT((NEON_LD4_s | (1 << NEONLSSize_offset)) == NEON_LD4_d);2932VIXL_STATIC_ASSERT((NEON_ST4_s | (1 << NEONLSSize_offset)) == NEON_ST4_d);2933mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";2934if ((instr->GetNEONLSSize() & 1) == 0) {2935form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns]";2936} else {2937form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns]";2938}2939break;2940case NEON_LD4R:2941mnemonic = "ld4r";2942form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns]";2943break;2944default:2945break;2946}29472948// Work out unallocated encodings.2949bool allocated = (mnemonic != NULL);2950switch (instr->Mask(NEONLoadStoreSingleStructMask)) {2951case NEON_LD1_h:2952case NEON_LD2_h:2953case NEON_LD3_h:2954case NEON_LD4_h:2955case NEON_ST1_h:2956case NEON_ST2_h:2957case NEON_ST3_h:2958case NEON_ST4_h:2959VIXL_ASSERT(allocated);2960allocated = ((instr->GetNEONLSSize() & 1) == 0);2961break;2962case NEON_LD1_s:2963case NEON_LD2_s:2964case NEON_LD3_s:2965case NEON_LD4_s:2966case NEON_ST1_s:2967case NEON_ST2_s:2968case NEON_ST3_s:2969case NEON_ST4_s:2970VIXL_ASSERT(allocated);2971allocated = (instr->GetNEONLSSize() <= 1) &&2972((instr->GetNEONLSSize() == 0) || (instr->GetNEONS() == 0));2973break;2974case NEON_LD1R:2975case NEON_LD2R:2976case NEON_LD3R:2977case NEON_LD4R:2978VIXL_ASSERT(allocated);2979allocated = (instr->GetNEONS() == 0);2980break;2981default:2982break;2983}2984if (allocated) {2985VIXL_ASSERT(mnemonic != NULL);2986VIXL_ASSERT(form != NULL);2987} else {2988mnemonic = "unallocated";2989form = "(NEONLoadStoreSingleStruct)";2990}29912992Format(instr, mnemonic, nfd.Substitute(form));2993}299429952996void Disassembler::VisitNEONLoadStoreSingleStructPostIndex(2997const Instruction *instr) {2998const char *mnemonic = NULL;2999const char *form = NULL;30003001const char *form_1b = "{'Vt.b}['IVLSLane0], ['Xns], 'Xmb1";3002const char *form_1h = "{'Vt.h}['IVLSLane1], ['Xns], 'Xmb2";3003const char *form_1s = "{'Vt.s}['IVLSLane2], ['Xns], 'Xmb4";3004const char *form_1d = "{'Vt.d}['IVLSLane3], ['Xns], 'Xmb8";3005NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());30063007switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {3008case NEON_LD1_b_post:3009mnemonic = "ld1";3010form = form_1b;3011break;3012case NEON_LD1_h_post:3013mnemonic = "ld1";3014form = form_1h;3015break;3016case NEON_LD1_s_post:3017mnemonic = "ld1";3018VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);3019form = ((instr->GetNEONLSSize() & 1) == 0) ? form_1s : form_1d;3020break;3021case NEON_ST1_b_post:3022mnemonic = "st1";3023form = form_1b;3024break;3025case NEON_ST1_h_post:3026mnemonic = "st1";3027form = form_1h;3028break;3029case NEON_ST1_s_post:3030mnemonic = "st1";3031VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);3032form = ((instr->GetNEONLSSize() & 1) == 0) ? form_1s : form_1d;3033break;3034case NEON_LD1R_post:3035mnemonic = "ld1r";3036form = "{'Vt.%s}, ['Xns], 'Xmz1";3037break;3038case NEON_LD2_b_post:3039case NEON_ST2_b_post:3040mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";3041form = "{'Vt.b, 'Vt2.b}['IVLSLane0], ['Xns], 'Xmb2";3042break;3043case NEON_ST2_h_post:3044case NEON_LD2_h_post:3045mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";3046form = "{'Vt.h, 'Vt2.h}['IVLSLane1], ['Xns], 'Xmb4";3047break;3048case NEON_LD2_s_post:3049case NEON_ST2_s_post:3050mnemonic = (instr->GetLdStXLoad() == 1) ? "ld2" : "st2";3051if ((instr->GetNEONLSSize() & 1) == 0)3052form = "{'Vt.s, 'Vt2.s}['IVLSLane2], ['Xns], 'Xmb8";3053else3054form = "{'Vt.d, 'Vt2.d}['IVLSLane3], ['Xns], 'Xmb16";3055break;3056case NEON_LD2R_post:3057mnemonic = "ld2r";3058form = "{'Vt.%s, 'Vt2.%s}, ['Xns], 'Xmz2";3059break;3060case NEON_LD3_b_post:3061case NEON_ST3_b_post:3062mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";3063form = "{'Vt.b, 'Vt2.b, 'Vt3.b}['IVLSLane0], ['Xns], 'Xmb3";3064break;3065case NEON_LD3_h_post:3066case NEON_ST3_h_post:3067mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";3068form = "{'Vt.h, 'Vt2.h, 'Vt3.h}['IVLSLane1], ['Xns], 'Xmb6";3069break;3070case NEON_LD3_s_post:3071case NEON_ST3_s_post:3072mnemonic = (instr->GetLdStXLoad() == 1) ? "ld3" : "st3";3073if ((instr->GetNEONLSSize() & 1) == 0)3074form = "{'Vt.s, 'Vt2.s, 'Vt3.s}['IVLSLane2], ['Xns], 'Xmb12";3075else3076form = "{'Vt.d, 'Vt2.d, 'Vt3.d}['IVLSLane3], ['Xns], 'Xmb24";3077break;3078case NEON_LD3R_post:3079mnemonic = "ld3r";3080form = "{'Vt.%s, 'Vt2.%s, 'Vt3.%s}, ['Xns], 'Xmz3";3081break;3082case NEON_LD4_b_post:3083case NEON_ST4_b_post:3084mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";3085form = "{'Vt.b, 'Vt2.b, 'Vt3.b, 'Vt4.b}['IVLSLane0], ['Xns], 'Xmb4";3086break;3087case NEON_LD4_h_post:3088case NEON_ST4_h_post:3089mnemonic = (instr->GetLdStXLoad()) == 1 ? "ld4" : "st4";3090form = "{'Vt.h, 'Vt2.h, 'Vt3.h, 'Vt4.h}['IVLSLane1], ['Xns], 'Xmb8";3091break;3092case NEON_LD4_s_post:3093case NEON_ST4_s_post:3094mnemonic = (instr->GetLdStXLoad() == 1) ? "ld4" : "st4";3095if ((instr->GetNEONLSSize() & 1) == 0)3096form = "{'Vt.s, 'Vt2.s, 'Vt3.s, 'Vt4.s}['IVLSLane2], ['Xns], 'Xmb16";3097else3098form = "{'Vt.d, 'Vt2.d, 'Vt3.d, 'Vt4.d}['IVLSLane3], ['Xns], 'Xmb32";3099break;3100case NEON_LD4R_post:3101mnemonic = "ld4r";3102form = "{'Vt.%1$s, 'Vt2.%1$s, 'Vt3.%1$s, 'Vt4.%1$s}, ['Xns], 'Xmz4";3103break;3104default:3105break;3106}31073108// Work out unallocated encodings.3109bool allocated = (mnemonic != NULL);3110switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {3111case NEON_LD1_h_post:3112case NEON_LD2_h_post:3113case NEON_LD3_h_post:3114case NEON_LD4_h_post:3115case NEON_ST1_h_post:3116case NEON_ST2_h_post:3117case NEON_ST3_h_post:3118case NEON_ST4_h_post:3119VIXL_ASSERT(allocated);3120allocated = ((instr->GetNEONLSSize() & 1) == 0);3121break;3122case NEON_LD1_s_post:3123case NEON_LD2_s_post:3124case NEON_LD3_s_post:3125case NEON_LD4_s_post:3126case NEON_ST1_s_post:3127case NEON_ST2_s_post:3128case NEON_ST3_s_post:3129case NEON_ST4_s_post:3130VIXL_ASSERT(allocated);3131allocated = (instr->GetNEONLSSize() <= 1) &&3132((instr->GetNEONLSSize() == 0) || (instr->GetNEONS() == 0));3133break;3134case NEON_LD1R_post:3135case NEON_LD2R_post:3136case NEON_LD3R_post:3137case NEON_LD4R_post:3138VIXL_ASSERT(allocated);3139allocated = (instr->GetNEONS() == 0);3140break;3141default:3142break;3143}3144if (allocated) {3145VIXL_ASSERT(mnemonic != NULL);3146VIXL_ASSERT(form != NULL);3147} else {3148mnemonic = "unallocated";3149form = "(NEONLoadStoreSingleStructPostIndex)";3150}31513152Format(instr, mnemonic, nfd.Substitute(form));3153}315431553156void Disassembler::VisitNEONModifiedImmediate(const Instruction *instr) {3157const char *mnemonic = mnemonic_.c_str();3158const char *form = "'Vt.%s, 'IVMIImm8, lsl 'IVMIShiftAmt1";31593160static const NEONFormatMap map_h = {{30}, {NF_4H, NF_8H}};3161static const NEONFormatMap map_s = {{30}, {NF_2S, NF_4S}};3162NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());31633164switch (form_hash_) {3165case "movi_asimdimm_n_b"_h:3166form = "'Vt.%s, 'IVMIImm8";3167break;3168case "bic_asimdimm_l_hl"_h:3169case "movi_asimdimm_l_hl"_h:3170case "mvni_asimdimm_l_hl"_h:3171case "orr_asimdimm_l_hl"_h:3172nfd.SetFormatMap(0, &map_h);3173break;3174case "movi_asimdimm_m_sm"_h:3175case "mvni_asimdimm_m_sm"_h:3176form = "'Vt.%s, 'IVMIImm8, msl 'IVMIShiftAmt2";3177VIXL_FALLTHROUGH();3178case "bic_asimdimm_l_sl"_h:3179case "movi_asimdimm_l_sl"_h:3180case "mvni_asimdimm_l_sl"_h:3181case "orr_asimdimm_l_sl"_h:3182nfd.SetFormatMap(0, &map_s);3183break;3184case "movi_asimdimm_d_ds"_h:3185form = "'Dd, 'IVMIImm";3186break;3187case "movi_asimdimm_d2_d"_h:3188form = "'Vt.2d, 'IVMIImm";3189break;3190case "fmov_asimdimm_h_h"_h:3191form = "'Vt.%s, 'IFPNeon";3192nfd.SetFormatMap(0, &map_h);3193break;3194case "fmov_asimdimm_s_s"_h:3195form = "'Vt.%s, 'IFPNeon";3196nfd.SetFormatMap(0, &map_s);3197break;3198case "fmov_asimdimm_d2_d"_h:3199form = "'Vt.2d, 'IFPNeon";3200break;3201}32023203Format(instr, mnemonic, nfd.Substitute(form));3204}32053206void Disassembler::DisassembleNEONScalar2RegMiscOnlyD(3207const Instruction *instr) {3208const char *mnemonic = mnemonic_.c_str();3209const char *form = "'Dd, 'Dn";3210const char *suffix = ", #0";3211if (instr->GetNEONSize() != 3) {3212mnemonic = NULL;3213}3214switch (form_hash_) {3215case "abs_asisdmisc_r"_h:3216case "neg_asisdmisc_r"_h:3217suffix = NULL;3218}3219Format(instr, mnemonic, form, suffix);3220}32213222void Disassembler::DisassembleNEONFPScalar2RegMisc(const Instruction *instr) {3223const char *mnemonic = mnemonic_.c_str();3224const char *form = "%sd, %sn";3225const char *suffix = NULL;3226NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap());3227switch (form_hash_) {3228case "fcmeq_asisdmisc_fz"_h:3229case "fcmge_asisdmisc_fz"_h:3230case "fcmgt_asisdmisc_fz"_h:3231case "fcmle_asisdmisc_fz"_h:3232case "fcmlt_asisdmisc_fz"_h:3233suffix = ", #0.0";3234break;3235case "fcvtxn_asisdmisc_n"_h:3236if (nfd.GetVectorFormat(0) == kFormatS) { // Source format.3237mnemonic = NULL;3238}3239form = "'Sd, 'Dn";3240}3241Format(instr, mnemonic, nfd.SubstitutePlaceholders(form), suffix);3242}32433244void Disassembler::VisitNEONScalar2RegMisc(const Instruction *instr) {3245const char *mnemonic = mnemonic_.c_str();3246const char *form = "%sd, %sn";3247NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());3248switch (form_hash_) {3249case "sqxtn_asisdmisc_n"_h:3250case "sqxtun_asisdmisc_n"_h:3251case "uqxtn_asisdmisc_n"_h:3252nfd.SetFormatMap(1, nfd.LongScalarFormatMap());3253}3254Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));3255}32563257void Disassembler::VisitNEONScalar2RegMiscFP16(const Instruction *instr) {3258const char *mnemonic = mnemonic_.c_str();3259const char *form = "'Hd, 'Hn";3260const char *suffix = NULL;32613262switch (form_hash_) {3263case "fcmeq_asisdmiscfp16_fz"_h:3264case "fcmge_asisdmiscfp16_fz"_h:3265case "fcmgt_asisdmiscfp16_fz"_h:3266case "fcmle_asisdmiscfp16_fz"_h:3267case "fcmlt_asisdmiscfp16_fz"_h:3268suffix = ", #0.0";3269}3270Format(instr, mnemonic, form, suffix);3271}327232733274void Disassembler::VisitNEONScalar3Diff(const Instruction *instr) {3275const char *mnemonic = mnemonic_.c_str();3276const char *form = "%sd, %sn, %sm";3277NEONFormatDecoder nfd(instr,3278NEONFormatDecoder::LongScalarFormatMap(),3279NEONFormatDecoder::ScalarFormatMap());3280if (nfd.GetVectorFormat(0) == kFormatH) {3281mnemonic = NULL;3282}3283Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));3284}32853286void Disassembler::DisassembleNEONFPScalar3Same(const Instruction *instr) {3287const char *mnemonic = mnemonic_.c_str();3288const char *form = "%sd, %sn, %sm";3289NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap());3290Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));3291}32923293void Disassembler::DisassembleNEONScalar3SameOnlyD(const Instruction *instr) {3294const char *mnemonic = mnemonic_.c_str();3295const char *form = "'Dd, 'Dn, 'Dm";3296if (instr->GetNEONSize() != 3) {3297mnemonic = NULL;3298}3299Format(instr, mnemonic, form);3300}33013302void Disassembler::VisitNEONScalar3Same(const Instruction *instr) {3303const char *mnemonic = mnemonic_.c_str();3304const char *form = "%sd, %sn, %sm";3305NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());3306VectorFormat vform = nfd.GetVectorFormat(0);3307switch (form_hash_) {3308case "srshl_asisdsame_only"_h:3309case "urshl_asisdsame_only"_h:3310case "sshl_asisdsame_only"_h:3311case "ushl_asisdsame_only"_h:3312if (vform != kFormatD) {3313mnemonic = NULL;3314}3315break;3316case "sqdmulh_asisdsame_only"_h:3317case "sqrdmulh_asisdsame_only"_h:3318if ((vform == kFormatB) || (vform == kFormatD)) {3319mnemonic = NULL;3320}3321}3322Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));3323}33243325void Disassembler::VisitNEONScalar3SameFP16(const Instruction *instr) {3326FormatWithDecodedMnemonic(instr, "'Hd, 'Hn, 'Hm");3327}33283329void Disassembler::VisitNEONScalar3SameExtra(const Instruction *instr) {3330USE(instr);3331// Nothing to do - handled by VisitNEONScalar3Same.3332VIXL_UNREACHABLE();3333}33343335void Disassembler::DisassembleNEONScalarSatMulLongIndex(3336const Instruction *instr) {3337const char *mnemonic = mnemonic_.c_str();3338const char *form = "%sd, %sn, 'Vf.%s['IVByElemIndex]";3339NEONFormatDecoder nfd(instr,3340NEONFormatDecoder::LongScalarFormatMap(),3341NEONFormatDecoder::ScalarFormatMap());3342if (nfd.GetVectorFormat(0) == kFormatH) {3343mnemonic = NULL;3344}3345Format(instr,3346mnemonic,3347nfd.Substitute(form, nfd.kPlaceholder, nfd.kPlaceholder, nfd.kFormat));3348}33493350void Disassembler::DisassembleNEONFPScalarMulIndex(const Instruction *instr) {3351const char *mnemonic = mnemonic_.c_str();3352const char *form = "%sd, %sn, 'Vf.%s['IVByElemIndex]";3353static const NEONFormatMap map = {{23, 22}, {NF_H, NF_UNDEF, NF_S, NF_D}};3354NEONFormatDecoder nfd(instr, &map);3355Format(instr,3356mnemonic,3357nfd.Substitute(form, nfd.kPlaceholder, nfd.kPlaceholder, nfd.kFormat));3358}33593360void Disassembler::VisitNEONScalarByIndexedElement(const Instruction *instr) {3361const char *mnemonic = mnemonic_.c_str();3362const char *form = "%sd, %sn, 'Vf.%s['IVByElemIndex]";3363NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());3364VectorFormat vform_dst = nfd.GetVectorFormat(0);3365if ((vform_dst == kFormatB) || (vform_dst == kFormatD)) {3366mnemonic = NULL;3367}3368Format(instr,3369mnemonic,3370nfd.Substitute(form, nfd.kPlaceholder, nfd.kPlaceholder, nfd.kFormat));3371}337233733374void Disassembler::VisitNEONScalarCopy(const Instruction *instr) {3375const char *mnemonic = "unimplemented";3376const char *form = "(NEONScalarCopy)";33773378NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());33793380if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) {3381mnemonic = "mov";3382form = "%sd, 'Vn.%s['IVInsIndex1]";3383}33843385Format(instr, mnemonic, nfd.Substitute(form, nfd.kPlaceholder, nfd.kFormat));3386}338733883389void Disassembler::VisitNEONScalarPairwise(const Instruction *instr) {3390const char *mnemonic = mnemonic_.c_str();3391if (form_hash_ == "addp_asisdpair_only"_h) {3392// All pairwise operations except ADDP use bit U to differentiate FP163393// from FP32/FP64 variations.3394if (instr->GetNEONSize() != 3) {3395mnemonic = NULL;3396}3397Format(instr, mnemonic, "'Dd, 'Vn.2d");3398} else {3399const char *form = "%sd, 'Vn.2%s";3400NEONFormatDecoder nfd(instr,3401NEONFormatDecoder::FPScalarPairwiseFormatMap());34023403Format(instr,3404mnemonic,3405nfd.Substitute(form,3406NEONFormatDecoder::kPlaceholder,3407NEONFormatDecoder::kFormat));3408}3409}34103411void Disassembler::DisassembleNEONScalarShiftImmOnlyD(3412const Instruction *instr) {3413const char *mnemonic = mnemonic_.c_str();3414const char *form = "'Dd, 'Dn, ";3415const char *suffix = "'IsR";34163417if (instr->ExtractBit(22) == 0) {3418// Only D registers are supported.3419mnemonic = NULL;3420}34213422switch (form_hash_) {3423case "shl_asisdshf_r"_h:3424case "sli_asisdshf_r"_h:3425suffix = "'IsL";3426}34273428Format(instr, mnemonic, form, suffix);3429}34303431void Disassembler::DisassembleNEONScalarShiftRightNarrowImm(3432const Instruction *instr) {3433const char *mnemonic = mnemonic_.c_str();3434const char *form = "%sd, %sn, 'IsR";3435static const NEONFormatMap map_dst =3436{{22, 21, 20, 19}, {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S}};3437static const NEONFormatMap map_src =3438{{22, 21, 20, 19}, {NF_UNDEF, NF_H, NF_S, NF_S, NF_D, NF_D, NF_D, NF_D}};3439NEONFormatDecoder nfd(instr, &map_dst, &map_src);3440Format(instr, mnemonic, nfd.SubstitutePlaceholders(form));3441}34423443void Disassembler::VisitNEONScalarShiftImmediate(const Instruction *instr) {3444const char *mnemonic = mnemonic_.c_str();3445const char *form = "%sd, %sn, ";3446const char *suffix = "'IsR";34473448// clang-format off3449static const NEONFormatMap map = {{22, 21, 20, 19},3450{NF_UNDEF, NF_B, NF_H, NF_H,3451NF_S, NF_S, NF_S, NF_S,3452NF_D, NF_D, NF_D, NF_D,3453NF_D, NF_D, NF_D, NF_D}};3454// clang-format on3455NEONFormatDecoder nfd(instr, &map);3456switch (form_hash_) {3457case "sqshlu_asisdshf_r"_h:3458case "sqshl_asisdshf_r"_h:3459case "uqshl_asisdshf_r"_h:3460suffix = "'IsL";3461break;3462default:3463if (nfd.GetVectorFormat(0) == kFormatB) {3464mnemonic = NULL;3465}3466}3467Format(instr, mnemonic, nfd.SubstitutePlaceholders(form), suffix);3468}34693470void Disassembler::DisassembleNEONShiftLeftLongImm(const Instruction *instr) {3471const char *mnemonic = mnemonic_.c_str();3472const char *form = "'Vd.%s, 'Vn.%s";3473const char *suffix = ", 'IsL";34743475NEONFormatDecoder nfd(instr,3476NEONFormatDecoder::ShiftLongNarrowImmFormatMap(),3477NEONFormatDecoder::ShiftImmFormatMap());34783479if (instr->GetImmNEONImmb() == 0 &&3480CountSetBits(instr->GetImmNEONImmh(), 32) == 1) { // xtl variant.3481VIXL_ASSERT((form_hash_ == "sshll_asimdshf_l"_h) ||3482(form_hash_ == "ushll_asimdshf_l"_h));3483mnemonic = (form_hash_ == "sshll_asimdshf_l"_h) ? "sxtl" : "uxtl";3484suffix = NULL;3485}3486Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form), suffix);3487}34883489void Disassembler::DisassembleNEONShiftRightImm(const Instruction *instr) {3490const char *mnemonic = mnemonic_.c_str();3491const char *form = "'Vd.%s, 'Vn.%s, 'IsR";3492NEONFormatDecoder nfd(instr, NEONFormatDecoder::ShiftImmFormatMap());34933494VectorFormat vform_dst = nfd.GetVectorFormat(0);3495if (vform_dst != kFormatUndefined) {3496uint32_t ls_dst = LaneSizeInBitsFromFormat(vform_dst);3497switch (form_hash_) {3498case "scvtf_asimdshf_c"_h:3499case "ucvtf_asimdshf_c"_h:3500case "fcvtzs_asimdshf_c"_h:3501case "fcvtzu_asimdshf_c"_h:3502if (ls_dst == kBRegSize) {3503mnemonic = NULL;3504}3505break;3506}3507}3508Format(instr, mnemonic, nfd.Substitute(form));3509}35103511void Disassembler::DisassembleNEONShiftRightNarrowImm(3512const Instruction *instr) {3513const char *mnemonic = mnemonic_.c_str();3514const char *form = "'Vd.%s, 'Vn.%s, 'IsR";35153516NEONFormatDecoder nfd(instr,3517NEONFormatDecoder::ShiftImmFormatMap(),3518NEONFormatDecoder::ShiftLongNarrowImmFormatMap());3519Format(instr, nfd.Mnemonic(mnemonic), nfd.Substitute(form));3520}35213522void Disassembler::VisitNEONShiftImmediate(const Instruction *instr) {3523const char *mnemonic = mnemonic_.c_str();3524const char *form = "'Vd.%s, 'Vn.%s, 'IsL";3525NEONFormatDecoder nfd(instr, NEONFormatDecoder::ShiftImmFormatMap());3526Format(instr, mnemonic, nfd.Substitute(form));3527}352835293530void Disassembler::VisitNEONTable(const Instruction *instr) {3531const char *mnemonic = mnemonic_.c_str();3532const char form_1v[] = "'Vd.%%s, {'Vn.16b}, 'Vm.%%s";3533const char form_2v[] = "'Vd.%%s, {'Vn.16b, v%d.16b}, 'Vm.%%s";3534const char form_3v[] = "'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b}, 'Vm.%%s";3535const char form_4v[] =3536"'Vd.%%s, {'Vn.16b, v%d.16b, v%d.16b, v%d.16b}, 'Vm.%%s";3537const char *form = form_1v;35383539NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());35403541switch (form_hash_) {3542case "tbl_asimdtbl_l2_2"_h:3543case "tbx_asimdtbl_l2_2"_h:3544form = form_2v;3545break;3546case "tbl_asimdtbl_l3_3"_h:3547case "tbx_asimdtbl_l3_3"_h:3548form = form_3v;3549break;3550case "tbl_asimdtbl_l4_4"_h:3551case "tbx_asimdtbl_l4_4"_h:3552form = form_4v;3553break;3554}3555VIXL_ASSERT(form != NULL);35563557char re_form[sizeof(form_4v) + 6]; // 3 * two-digit substitutions => 63558int reg_num = instr->GetRn();3559snprintf(re_form,3560sizeof(re_form),3561form,3562(reg_num + 1) % kNumberOfVRegisters,3563(reg_num + 2) % kNumberOfVRegisters,3564(reg_num + 3) % kNumberOfVRegisters);35653566Format(instr, mnemonic, nfd.Substitute(re_form));3567}356835693570void Disassembler::VisitNEONPerm(const Instruction *instr) {3571NEONFormatDecoder nfd(instr);3572FormatWithDecodedMnemonic(instr, nfd.Substitute("'Vd.%s, 'Vn.%s, 'Vm.%s"));3573}35743575void Disassembler::Disassemble_Vd4S_Vn16B_Vm16B(const Instruction *instr) {3576FormatWithDecodedMnemonic(instr, "'Vd.4s, 'Vn.16b, 'Vm.16b");3577}35783579void Disassembler::3580VisitSVE32BitGatherLoadHalfwords_ScalarPlus32BitScaledOffsets(3581const Instruction *instr) {3582FormatWithDecodedMnemonic(instr,3583"{'Zt.s}, 'Pgl/z, ['Xns, 'Zm.s, '?22:suxtw #1]");3584}35853586void Disassembler::VisitSVE32BitGatherLoadWords_ScalarPlus32BitScaledOffsets(3587const Instruction *instr) {3588FormatWithDecodedMnemonic(instr,3589"{'Zt.s}, 'Pgl/z, ['Xns, 'Zm.s, '?22:suxtw #2]");3590}35913592void Disassembler::VisitSVE32BitGatherLoad_ScalarPlus32BitUnscaledOffsets(3593const Instruction *instr) {3594FormatWithDecodedMnemonic(instr,3595"{'Zt.s}, 'Pgl/z, ['Xns, 'Zm.s, '?22:suxtw]");3596}35973598void Disassembler::VisitSVE32BitGatherLoad_VectorPlusImm(3599const Instruction *instr) {3600const char *form = "{'Zt.s}, 'Pgl/z, ['Zn.s]";3601const char *form_imm = "{'Zt.s}, 'Pgl/z, ['Zn.s, #'u2016]";3602const char *form_imm_h = "{'Zt.s}, 'Pgl/z, ['Zn.s, #'u2016*2]";3603const char *form_imm_w = "{'Zt.s}, 'Pgl/z, ['Zn.s, #'u2016*4]";36043605const char *mnemonic = mnemonic_.c_str();3606switch (form_hash_) {3607case "ld1h_z_p_ai_s"_h:3608case "ld1sh_z_p_ai_s"_h:3609case "ldff1h_z_p_ai_s"_h:3610case "ldff1sh_z_p_ai_s"_h:3611form_imm = form_imm_h;3612break;3613case "ld1w_z_p_ai_s"_h:3614case "ldff1w_z_p_ai_s"_h:3615form_imm = form_imm_w;3616break;3617}3618if (instr->ExtractBits(20, 16) != 0) form = form_imm;36193620Format(instr, mnemonic, form);3621}36223623void Disassembler::VisitSVE32BitGatherPrefetch_ScalarPlus32BitScaledOffsets(3624const Instruction *instr) {3625const char *mnemonic = "unimplemented";3626const char *form = "'prefSVEOp, 'Pgl, ['Xns, 'Zm.s, '?22:suxtw";3627const char *suffix = NULL;36283629switch (3630instr->Mask(SVE32BitGatherPrefetch_ScalarPlus32BitScaledOffsetsMask)) {3631case PRFB_i_p_bz_s_x32_scaled:3632mnemonic = "prfb";3633suffix = "]";3634break;3635case PRFD_i_p_bz_s_x32_scaled:3636mnemonic = "prfd";3637suffix = " #3]";3638break;3639case PRFH_i_p_bz_s_x32_scaled:3640mnemonic = "prfh";3641suffix = " #1]";3642break;3643case PRFW_i_p_bz_s_x32_scaled:3644mnemonic = "prfw";3645suffix = " #2]";3646break;3647default:3648form = "(SVE32BitGatherPrefetch_ScalarPlus32BitScaledOffsets)";3649break;3650}3651Format(instr, mnemonic, form, suffix);3652}36533654void Disassembler::VisitSVE32BitGatherPrefetch_VectorPlusImm(3655const Instruction *instr) {3656const char *form = (instr->ExtractBits(20, 16) != 0)3657? "'prefSVEOp, 'Pgl, ['Zn.s, #'u2016]"3658: "'prefSVEOp, 'Pgl, ['Zn.s]";3659FormatWithDecodedMnemonic(instr, form);3660}36613662void Disassembler::VisitSVE32BitScatterStore_ScalarPlus32BitScaledOffsets(3663const Instruction *instr) {3664FormatWithDecodedMnemonic(instr,3665"{'Zt.s}, 'Pgl, ['Xns, 'Zm.s, '?14:suxtw #'u2423]");3666}36673668void Disassembler::VisitSVE32BitScatterStore_ScalarPlus32BitUnscaledOffsets(3669const Instruction *instr) {3670FormatWithDecodedMnemonic(instr, "{'Zt.s}, 'Pgl, ['Xns, 'Zm.s, '?14:suxtw]");3671}36723673void Disassembler::VisitSVE32BitScatterStore_VectorPlusImm(3674const Instruction *instr) {3675const char *mnemonic = "unimplemented";3676const char *form = "{'Zt.s}, 'Pgl, ['Zn.s";3677const char *suffix = NULL;36783679bool is_zero = instr->ExtractBits(20, 16) == 0;36803681switch (instr->Mask(SVE32BitScatterStore_VectorPlusImmMask)) {3682case ST1B_z_p_ai_s:3683mnemonic = "st1b";3684suffix = is_zero ? "]" : ", #'u2016]";3685break;3686case ST1H_z_p_ai_s:3687mnemonic = "st1h";3688suffix = is_zero ? "]" : ", #'u2016*2]";3689break;3690case ST1W_z_p_ai_s:3691mnemonic = "st1w";3692suffix = is_zero ? "]" : ", #'u2016*4]";3693break;3694default:3695form = "(SVE32BitScatterStore_VectorPlusImm)";3696break;3697}3698Format(instr, mnemonic, form, suffix);3699}37003701void Disassembler::VisitSVE64BitGatherLoad_ScalarPlus32BitUnpackedScaledOffsets(3702const Instruction *instr) {3703FormatWithDecodedMnemonic(instr,3704"{'Zt.d}, 'Pgl/z, ['Xns, 'Zm.d, '?22:suxtw "3705"#'u2423]");3706}37073708void Disassembler::VisitSVE64BitGatherLoad_ScalarPlus64BitScaledOffsets(3709const Instruction *instr) {3710FormatWithDecodedMnemonic(instr,3711"{'Zt.d}, 'Pgl/z, ['Xns, 'Zm.d, lsl #'u2423]");3712}37133714void Disassembler::VisitSVE64BitGatherLoad_ScalarPlus64BitUnscaledOffsets(3715const Instruction *instr) {3716FormatWithDecodedMnemonic(instr, "{'Zt.d}, 'Pgl/z, ['Xns, 'Zm.d]");3717}37183719void Disassembler::3720VisitSVE64BitGatherLoad_ScalarPlusUnpacked32BitUnscaledOffsets(3721const Instruction *instr) {3722FormatWithDecodedMnemonic(instr,3723"{'Zt.d}, 'Pgl/z, ['Xns, 'Zm.d, '?22:suxtw]");3724}37253726void Disassembler::VisitSVE64BitGatherLoad_VectorPlusImm(3727const Instruction *instr) {3728const char *form = "{'Zt.d}, 'Pgl/z, ['Zn.d]";3729const char *form_imm[4] = {"{'Zt.d}, 'Pgl/z, ['Zn.d, #'u2016]",3730"{'Zt.d}, 'Pgl/z, ['Zn.d, #'u2016*2]",3731"{'Zt.d}, 'Pgl/z, ['Zn.d, #'u2016*4]",3732"{'Zt.d}, 'Pgl/z, ['Zn.d, #'u2016*8]"};37333734if (instr->ExtractBits(20, 16) != 0) {3735unsigned msz = instr->ExtractBits(24, 23);3736bool sign_extend = instr->ExtractBit(14) == 0;3737if ((msz == kDRegSizeInBytesLog2) && sign_extend) {3738form = "(SVE64BitGatherLoad_VectorPlusImm)";3739} else {3740VIXL_ASSERT(msz < ArrayLength(form_imm));3741form = form_imm[msz];3742}3743}37443745FormatWithDecodedMnemonic(instr, form);3746}37473748void Disassembler::VisitSVE64BitGatherPrefetch_ScalarPlus64BitScaledOffsets(3749const Instruction *instr) {3750const char *form = "'prefSVEOp, 'Pgl, ['Xns, 'Zm.d";3751const char *suffix = "]";37523753switch (form_hash_) {3754case "prfh_i_p_bz_d_64_scaled"_h:3755suffix = ", lsl #1]";3756break;3757case "prfs_i_p_bz_d_64_scaled"_h:3758suffix = ", lsl #2]";3759break;3760case "prfd_i_p_bz_d_64_scaled"_h:3761suffix = ", lsl #3]";3762break;3763}3764FormatWithDecodedMnemonic(instr, form, suffix);3765}37663767void Disassembler::3768VisitSVE64BitGatherPrefetch_ScalarPlusUnpacked32BitScaledOffsets(3769const Instruction *instr) {3770const char *form = "'prefSVEOp, 'Pgl, ['Xns, 'Zm.d, '?22:suxtw ";3771const char *suffix = "]";37723773switch (form_hash_) {3774case "prfh_i_p_bz_d_x32_scaled"_h:3775suffix = "#1]";3776break;3777case "prfs_i_p_bz_d_x32_scaled"_h:3778suffix = "#2]";3779break;3780case "prfd_i_p_bz_d_x32_scaled"_h:3781suffix = "#3]";3782break;3783}3784FormatWithDecodedMnemonic(instr, form, suffix);3785}37863787void Disassembler::VisitSVE64BitGatherPrefetch_VectorPlusImm(3788const Instruction *instr) {3789const char *form = (instr->ExtractBits(20, 16) != 0)3790? "'prefSVEOp, 'Pgl, ['Zn.d, #'u2016]"3791: "'prefSVEOp, 'Pgl, ['Zn.d]";37923793FormatWithDecodedMnemonic(instr, form);3794}37953796void Disassembler::VisitSVE64BitScatterStore_ScalarPlus64BitScaledOffsets(3797const Instruction *instr) {3798FormatWithDecodedMnemonic(instr, "{'Zt.d}, 'Pgl, ['Xns, 'Zm.d, lsl #'u2423]");3799}38003801void Disassembler::VisitSVE64BitScatterStore_ScalarPlus64BitUnscaledOffsets(3802const Instruction *instr) {3803FormatWithDecodedMnemonic(instr, "{'Zt.d}, 'Pgl, ['Xns, 'Zm.d]");3804}38053806void Disassembler::3807VisitSVE64BitScatterStore_ScalarPlusUnpacked32BitScaledOffsets(3808const Instruction *instr) {3809FormatWithDecodedMnemonic(instr,3810"{'Zt.d}, 'Pgl, ['Xns, 'Zm.d, '?14:suxtw #'u2423]");3811}38123813void Disassembler::3814VisitSVE64BitScatterStore_ScalarPlusUnpacked32BitUnscaledOffsets(3815const Instruction *instr) {3816FormatWithDecodedMnemonic(instr, "{'Zt.d}, 'Pgl, ['Xns, 'Zm.d, '?14:suxtw]");3817}38183819void Disassembler::VisitSVE64BitScatterStore_VectorPlusImm(3820const Instruction *instr) {3821const char *form = "{'Zt.d}, 'Pgl, ['Zn.d";3822const char *suffix = "]";38233824if (instr->ExtractBits(20, 16) != 0) {3825switch (form_hash_) {3826case "st1b_z_p_ai_d"_h:3827suffix = ", #'u2016]";3828break;3829case "st1h_z_p_ai_d"_h:3830suffix = ", #'u2016*2]";3831break;3832case "st1w_z_p_ai_d"_h:3833suffix = ", #'u2016*4]";3834break;3835case "st1d_z_p_ai_d"_h:3836suffix = ", #'u2016*8]";3837break;3838}3839}3840FormatWithDecodedMnemonic(instr, form, suffix);3841}38423843void Disassembler::VisitSVEBitwiseLogicalWithImm_Unpredicated(3844const Instruction *instr) {3845if (instr->GetSVEImmLogical() == 0) {3846// The immediate encoded in the instruction is not in the expected format.3847Format(instr, "unallocated", "(SVEBitwiseImm)");3848} else {3849FormatWithDecodedMnemonic(instr, "'Zd.'tl, 'Zd.'tl, 'ITriSvel");3850}3851}38523853void Disassembler::VisitSVEBitwiseLogical_Predicated(const Instruction *instr) {3854FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");3855}38563857void Disassembler::VisitSVEBitwiseShiftByImm_Predicated(3858const Instruction *instr) {3859const char *mnemonic = mnemonic_.c_str();3860const char *form = "'Zd.'tszp, 'Pgl/m, 'Zd.'tszp, ";3861const char *suffix = NULL;3862unsigned tsize = (instr->ExtractBits(23, 22) << 2) | instr->ExtractBits(9, 8);38633864if (tsize == 0) {3865mnemonic = "unimplemented";3866form = "(SVEBitwiseShiftByImm_Predicated)";3867} else {3868switch (form_hash_) {3869case "lsl_z_p_zi"_h:3870case "sqshl_z_p_zi"_h:3871case "sqshlu_z_p_zi"_h:3872case "uqshl_z_p_zi"_h:3873suffix = "'ITriSvep";3874break;3875case "asrd_z_p_zi"_h:3876case "asr_z_p_zi"_h:3877case "lsr_z_p_zi"_h:3878case "srshr_z_p_zi"_h:3879case "urshr_z_p_zi"_h:3880suffix = "'ITriSveq";3881break;3882default:3883mnemonic = "unimplemented";3884form = "(SVEBitwiseShiftByImm_Predicated)";3885break;3886}3887}3888Format(instr, mnemonic, form, suffix);3889}38903891void Disassembler::VisitSVEBitwiseShiftByVector_Predicated(3892const Instruction *instr) {3893FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");3894}38953896void Disassembler::VisitSVEBitwiseShiftByWideElements_Predicated(3897const Instruction *instr) {3898if (instr->GetSVESize() == kDRegSizeInBytesLog2) {3899Format(instr, "unallocated", "(SVEBitwiseShiftByWideElements_Predicated)");3900} else {3901FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.d");3902}3903}39043905static bool SVEMoveMaskPreferred(uint64_t value, int lane_bytes_log2) {3906VIXL_ASSERT(IsUintN(8 << lane_bytes_log2, value));39073908// Duplicate lane-sized value across double word.3909switch (lane_bytes_log2) {3910case 0:3911value *= 0x0101010101010101;3912break;3913case 1:3914value *= 0x0001000100010001;3915break;3916case 2:3917value *= 0x0000000100000001;3918break;3919case 3: // Nothing to do3920break;3921default:3922VIXL_UNREACHABLE();3923}39243925if ((value & 0xff) == 0) {3926// Check for 16-bit patterns. Set least-significant 16 bits, to make tests3927// easier; we already checked least-significant byte is zero above.3928uint64_t generic_value = value | 0xffff;39293930// Check 0x00000000_0000pq00 or 0xffffffff_ffffpq00.3931if ((generic_value == 0xffff) || (generic_value == UINT64_MAX)) {3932return false;3933}39343935// Check 0x0000pq00_0000pq00 or 0xffffpq00_ffffpq00.3936uint64_t rotvalue = RotateRight(value, 32, 64);3937if (value == rotvalue) {3938generic_value &= 0xffffffff;3939if ((generic_value == 0xffff) || (generic_value == UINT32_MAX)) {3940return false;3941}3942}39433944// Check 0xpq00pq00_pq00pq00.3945rotvalue = RotateRight(value, 16, 64);3946if (value == rotvalue) {3947return false;3948}3949} else {3950// Check for 8-bit patterns. Set least-significant byte, to make tests3951// easier.3952uint64_t generic_value = value | 0xff;39533954// Check 0x00000000_000000pq or 0xffffffff_ffffffpq.3955if ((generic_value == 0xff) || (generic_value == UINT64_MAX)) {3956return false;3957}39583959// Check 0x000000pq_000000pq or 0xffffffpq_ffffffpq.3960uint64_t rotvalue = RotateRight(value, 32, 64);3961if (value == rotvalue) {3962generic_value &= 0xffffffff;3963if ((generic_value == 0xff) || (generic_value == UINT32_MAX)) {3964return false;3965}3966}39673968// Check 0x00pq00pq_00pq00pq or 0xffpqffpq_ffpqffpq.3969rotvalue = RotateRight(value, 16, 64);3970if (value == rotvalue) {3971generic_value &= 0xffff;3972if ((generic_value == 0xff) || (generic_value == UINT16_MAX)) {3973return false;3974}3975}39763977// Check 0xpqpqpqpq_pqpqpqpq.3978rotvalue = RotateRight(value, 8, 64);3979if (value == rotvalue) {3980return false;3981}3982}3983return true;3984}39853986void Disassembler::VisitSVEBroadcastBitmaskImm(const Instruction *instr) {3987const char *mnemonic = "unimplemented";3988const char *form = "(SVEBroadcastBitmaskImm)";39893990switch (instr->Mask(SVEBroadcastBitmaskImmMask)) {3991case DUPM_z_i: {3992uint64_t imm = instr->GetSVEImmLogical();3993if (imm != 0) {3994int lane_size = instr->GetSVEBitwiseImmLaneSizeInBytesLog2();3995mnemonic = SVEMoveMaskPreferred(imm, lane_size) ? "mov" : "dupm";3996form = "'Zd.'tl, 'ITriSvel";3997}3998break;3999}4000default:4001break;4002}4003Format(instr, mnemonic, form);4004}40054006void Disassembler::VisitSVEBroadcastFPImm_Unpredicated(4007const Instruction *instr) {4008const char *mnemonic = "unimplemented";4009const char *form = "(SVEBroadcastFPImm_Unpredicated)";40104011if (instr->GetSVEVectorFormat() != kFormatVnB) {4012switch (instr->Mask(SVEBroadcastFPImm_UnpredicatedMask)) {4013case FDUP_z_i:4014// The preferred disassembly for fdup is "fmov".4015mnemonic = "fmov";4016form = "'Zd.'t, 'IFPSve";4017break;4018default:4019break;4020}4021}4022Format(instr, mnemonic, form);4023}40244025void Disassembler::VisitSVEBroadcastGeneralRegister(const Instruction *instr) {4026const char *mnemonic = "unimplemented";4027const char *form = "(SVEBroadcastGeneralRegister)";40284029switch (instr->Mask(SVEBroadcastGeneralRegisterMask)) {4030case DUP_z_r:4031// The preferred disassembly for dup is "mov".4032mnemonic = "mov";4033if (instr->GetSVESize() == kDRegSizeInBytesLog2) {4034form = "'Zd.'t, 'Xns";4035} else {4036form = "'Zd.'t, 'Wns";4037}4038break;4039default:4040break;4041}4042Format(instr, mnemonic, form);4043}40444045void Disassembler::VisitSVEBroadcastIndexElement(const Instruction *instr) {4046const char *mnemonic = "unimplemented";4047const char *form = "(SVEBroadcastIndexElement)";40484049switch (instr->Mask(SVEBroadcastIndexElementMask)) {4050case DUP_z_zi: {4051// The tsz field must not be zero.4052int tsz = instr->ExtractBits(20, 16);4053if (tsz != 0) {4054// The preferred disassembly for dup is "mov".4055mnemonic = "mov";4056int imm2 = instr->ExtractBits(23, 22);4057if ((CountSetBits(imm2) + CountSetBits(tsz)) == 1) {4058// If imm2:tsz has one set bit, the index is zero. This is4059// disassembled as a mov from a b/h/s/d/q scalar register.4060form = "'Zd.'ti, 'ti'u0905";4061} else {4062form = "'Zd.'ti, 'Zn.'ti['IVInsSVEIndex]";4063}4064}4065break;4066}4067default:4068break;4069}4070Format(instr, mnemonic, form);4071}40724073void Disassembler::VisitSVEBroadcastIntImm_Unpredicated(4074const Instruction *instr) {4075const char *mnemonic = "unimplemented";4076const char *form = "(SVEBroadcastIntImm_Unpredicated)";40774078switch (instr->Mask(SVEBroadcastIntImm_UnpredicatedMask)) {4079case DUP_z_i:4080// The encoding of byte-sized lanes with lsl #8 is undefined.4081if ((instr->GetSVEVectorFormat() == kFormatVnB) &&4082(instr->ExtractBit(13) == 1))4083break;40844085// The preferred disassembly for dup is "mov".4086mnemonic = "mov";4087form = (instr->ExtractBit(13) == 0) ? "'Zd.'t, #'s1205"4088: "'Zd.'t, #'s1205, lsl #8";4089break;4090default:4091break;4092}4093Format(instr, mnemonic, form);4094}40954096void Disassembler::VisitSVECompressActiveElements(const Instruction *instr) {4097// The top bit of size is always set for compact, so 't can only be4098// substituted with types S and D.4099if (instr->ExtractBit(23) == 1) {4100FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl, 'Zn.'t");4101} else {4102VisitUnallocated(instr);4103}4104}41054106void Disassembler::VisitSVEConditionallyBroadcastElementToVector(4107const Instruction *instr) {4108FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl, 'Zd.'t, 'Zn.'t");4109}41104111void Disassembler::VisitSVEConditionallyExtractElementToGeneralRegister(4112const Instruction *instr) {4113const char *form = "'Wd, 'Pgl, 'Wd, 'Zn.'t";41144115if (instr->GetSVESize() == kDRegSizeInBytesLog2) {4116form = "'Xd, p'u1210, 'Xd, 'Zn.'t";4117}4118FormatWithDecodedMnemonic(instr, form);4119}41204121void Disassembler::VisitSVEConditionallyExtractElementToSIMDFPScalar(4122const Instruction *instr) {4123FormatWithDecodedMnemonic(instr, "'t'u0400, 'Pgl, 't'u0400, 'Zn.'t");4124}41254126void Disassembler::VisitSVEConditionallyTerminateScalars(4127const Instruction *instr) {4128const char *form = (instr->ExtractBit(22) == 0) ? "'Wn, 'Wm" : "'Xn, 'Xm";4129FormatWithDecodedMnemonic(instr, form);4130}41314132void Disassembler::VisitSVEConstructivePrefix_Unpredicated(4133const Instruction *instr) {4134FormatWithDecodedMnemonic(instr, "'Zd, 'Zn");4135}41364137void Disassembler::VisitSVEContiguousFirstFaultLoad_ScalarPlusScalar(4138const Instruction *instr) {4139const char *form = "{'Zt.'tlss}, 'Pgl/z, ['Xns";4140const char *suffix = "]";41414142if (instr->GetRm() != kZeroRegCode) {4143switch (form_hash_) {4144case "ldff1b_z_p_br_u8"_h:4145case "ldff1b_z_p_br_u16"_h:4146case "ldff1b_z_p_br_u32"_h:4147case "ldff1b_z_p_br_u64"_h:4148case "ldff1sb_z_p_br_s16"_h:4149case "ldff1sb_z_p_br_s32"_h:4150case "ldff1sb_z_p_br_s64"_h:4151suffix = ", 'Xm]";4152break;4153case "ldff1h_z_p_br_u16"_h:4154case "ldff1h_z_p_br_u32"_h:4155case "ldff1h_z_p_br_u64"_h:4156case "ldff1sh_z_p_br_s32"_h:4157case "ldff1sh_z_p_br_s64"_h:4158suffix = ", 'Xm, lsl #1]";4159break;4160case "ldff1w_z_p_br_u32"_h:4161case "ldff1w_z_p_br_u64"_h:4162case "ldff1sw_z_p_br_s64"_h:4163suffix = ", 'Xm, lsl #2]";4164break;4165case "ldff1d_z_p_br_u64"_h:4166suffix = ", 'Xm, lsl #3]";4167break;4168}4169}41704171FormatWithDecodedMnemonic(instr, form, suffix);4172}41734174void Disassembler::VisitSVEContiguousNonFaultLoad_ScalarPlusImm(4175const Instruction *instr) {4176const char *form = "{'Zt.'tlss}, 'Pgl/z, ['Xns";4177const char *suffix =4178(instr->ExtractBits(19, 16) == 0) ? "]" : ", #'s1916, mul vl]";4179FormatWithDecodedMnemonic(instr, form, suffix);4180}41814182void Disassembler::VisitSVEContiguousNonTemporalLoad_ScalarPlusImm(4183const Instruction *instr) {4184const char *form = "{'Zt.b}, 'Pgl/z, ['Xns";4185const char *suffix =4186(instr->ExtractBits(19, 16) == 0) ? "]" : ", #'s1916, mul vl]";4187switch (form_hash_) {4188case "ldnt1d_z_p_bi_contiguous"_h:4189form = "{'Zt.d}, 'Pgl/z, ['Xns";4190break;4191case "ldnt1h_z_p_bi_contiguous"_h:4192form = "{'Zt.h}, 'Pgl/z, ['Xns";4193break;4194case "ldnt1w_z_p_bi_contiguous"_h:4195form = "{'Zt.s}, 'Pgl/z, ['Xns";4196break;4197}4198FormatWithDecodedMnemonic(instr, form, suffix);4199}42004201void Disassembler::VisitSVEContiguousNonTemporalLoad_ScalarPlusScalar(4202const Instruction *instr) {4203const char *form = "{'Zt.b}, 'Pgl/z, ['Xns, 'Rm]";4204switch (form_hash_) {4205case "ldnt1d_z_p_br_contiguous"_h:4206form = "{'Zt.d}, 'Pgl/z, ['Xns, 'Rm, lsl #3]";4207break;4208case "ldnt1h_z_p_br_contiguous"_h:4209form = "{'Zt.h}, 'Pgl/z, ['Xns, 'Rm, lsl #1]";4210break;4211case "ldnt1w_z_p_br_contiguous"_h:4212form = "{'Zt.s}, 'Pgl/z, ['Xns, 'Rm, lsl #2]";4213break;4214}4215FormatWithDecodedMnemonic(instr, form);4216}42174218void Disassembler::VisitSVEContiguousNonTemporalStore_ScalarPlusImm(4219const Instruction *instr) {4220const char *form = "{'Zt.b}, 'Pgl, ['Xns";4221const char *suffix =4222(instr->ExtractBits(19, 16) == 0) ? "]" : ", #'s1916, mul vl]";42234224switch (form_hash_) {4225case "stnt1d_z_p_bi_contiguous"_h:4226form = "{'Zt.d}, 'Pgl, ['Xns";4227break;4228case "stnt1h_z_p_bi_contiguous"_h:4229form = "{'Zt.h}, 'Pgl, ['Xns";4230break;4231case "stnt1w_z_p_bi_contiguous"_h:4232form = "{'Zt.s}, 'Pgl, ['Xns";4233break;4234}4235FormatWithDecodedMnemonic(instr, form, suffix);4236}42374238void Disassembler::VisitSVEContiguousNonTemporalStore_ScalarPlusScalar(4239const Instruction *instr) {4240const char *mnemonic = "unimplemented";4241const char *form = "(SVEContiguousNonTemporalStore_ScalarPlusScalar)";42424243switch (instr->Mask(SVEContiguousNonTemporalStore_ScalarPlusScalarMask)) {4244case STNT1B_z_p_br_contiguous:4245mnemonic = "stnt1b";4246form = "{'Zt.b}, 'Pgl, ['Xns, 'Rm]";4247break;4248case STNT1D_z_p_br_contiguous:4249mnemonic = "stnt1d";4250form = "{'Zt.d}, 'Pgl, ['Xns, 'Rm, lsl #3]";4251break;4252case STNT1H_z_p_br_contiguous:4253mnemonic = "stnt1h";4254form = "{'Zt.h}, 'Pgl, ['Xns, 'Rm, lsl #1]";4255break;4256case STNT1W_z_p_br_contiguous:4257mnemonic = "stnt1w";4258form = "{'Zt.s}, 'Pgl, ['Xns, 'Rm, lsl #2]";4259break;4260default:4261break;4262}4263Format(instr, mnemonic, form);4264}42654266void Disassembler::VisitSVEContiguousPrefetch_ScalarPlusImm(4267const Instruction *instr) {4268const char *form = (instr->ExtractBits(21, 16) != 0)4269? "'prefSVEOp, 'Pgl, ['Xns, #'s2116, mul vl]"4270: "'prefSVEOp, 'Pgl, ['Xns]";4271FormatWithDecodedMnemonic(instr, form);4272}42734274void Disassembler::VisitSVEContiguousPrefetch_ScalarPlusScalar(4275const Instruction *instr) {4276const char *mnemonic = "unimplemented";4277const char *form = "(SVEContiguousPrefetch_ScalarPlusScalar)";42784279if (instr->GetRm() != kZeroRegCode) {4280switch (instr->Mask(SVEContiguousPrefetch_ScalarPlusScalarMask)) {4281case PRFB_i_p_br_s:4282mnemonic = "prfb";4283form = "'prefSVEOp, 'Pgl, ['Xns, 'Rm]";4284break;4285case PRFD_i_p_br_s:4286mnemonic = "prfd";4287form = "'prefSVEOp, 'Pgl, ['Xns, 'Rm, lsl #3]";4288break;4289case PRFH_i_p_br_s:4290mnemonic = "prfh";4291form = "'prefSVEOp, 'Pgl, ['Xns, 'Rm, lsl #1]";4292break;4293case PRFW_i_p_br_s:4294mnemonic = "prfw";4295form = "'prefSVEOp, 'Pgl, ['Xns, 'Rm, lsl #2]";4296break;4297default:4298break;4299}4300}4301Format(instr, mnemonic, form);4302}43034304void Disassembler::VisitSVEContiguousStore_ScalarPlusImm(4305const Instruction *instr) {4306// The 'size' field isn't in the usual place here.4307const char *form = "{'Zt.'tls}, 'Pgl, ['Xns, #'s1916, mul vl]";4308if (instr->ExtractBits(19, 16) == 0) {4309form = "{'Zt.'tls}, 'Pgl, ['Xns]";4310}4311FormatWithDecodedMnemonic(instr, form);4312}43134314void Disassembler::VisitSVEContiguousStore_ScalarPlusScalar(4315const Instruction *instr) {4316// The 'size' field isn't in the usual place here.4317FormatWithDecodedMnemonic(instr, "{'Zt.'tls}, 'Pgl, ['Xns, 'Xm'NSveS]");4318}43194320void Disassembler::VisitSVECopyFPImm_Predicated(const Instruction *instr) {4321const char *mnemonic = "unimplemented";4322const char *form = "(SVECopyFPImm_Predicated)";43234324if (instr->GetSVEVectorFormat() != kFormatVnB) {4325switch (instr->Mask(SVECopyFPImm_PredicatedMask)) {4326case FCPY_z_p_i:4327// The preferred disassembly for fcpy is "fmov".4328mnemonic = "fmov";4329form = "'Zd.'t, 'Pm/m, 'IFPSve";4330break;4331default:4332break;4333}4334}4335Format(instr, mnemonic, form);4336}43374338void Disassembler::VisitSVECopyGeneralRegisterToVector_Predicated(4339const Instruction *instr) {4340const char *mnemonic = "unimplemented";4341const char *form = "(SVECopyGeneralRegisterToVector_Predicated)";43424343switch (instr->Mask(SVECopyGeneralRegisterToVector_PredicatedMask)) {4344case CPY_z_p_r:4345// The preferred disassembly for cpy is "mov".4346mnemonic = "mov";4347form = "'Zd.'t, 'Pgl/m, 'Wns";4348if (instr->GetSVESize() == kXRegSizeInBytesLog2) {4349form = "'Zd.'t, 'Pgl/m, 'Xns";4350}4351break;4352default:4353break;4354}4355Format(instr, mnemonic, form);4356}43574358void Disassembler::VisitSVECopyIntImm_Predicated(const Instruction *instr) {4359const char *mnemonic = "unimplemented";4360const char *form = "(SVECopyIntImm_Predicated)";4361const char *suffix = NULL;43624363switch (instr->Mask(SVECopyIntImm_PredicatedMask)) {4364case CPY_z_p_i: {4365// The preferred disassembly for cpy is "mov".4366mnemonic = "mov";4367form = "'Zd.'t, 'Pm/'?14:mz, #'s1205";4368if (instr->ExtractBit(13) != 0) suffix = ", lsl #8";4369break;4370}4371default:4372break;4373}4374Format(instr, mnemonic, form, suffix);4375}43764377void Disassembler::VisitSVECopySIMDFPScalarRegisterToVector_Predicated(4378const Instruction *instr) {4379const char *mnemonic = "unimplemented";4380const char *form = "(SVECopySIMDFPScalarRegisterToVector_Predicated)";43814382switch (instr->Mask(SVECopySIMDFPScalarRegisterToVector_PredicatedMask)) {4383case CPY_z_p_v:4384// The preferred disassembly for cpy is "mov".4385mnemonic = "mov";4386form = "'Zd.'t, 'Pgl/m, 'Vnv";4387break;4388default:4389break;4390}4391Format(instr, mnemonic, form);4392}43934394void Disassembler::VisitSVEExtractElementToGeneralRegister(4395const Instruction *instr) {4396const char *form = "'Wd, 'Pgl, 'Zn.'t";4397if (instr->GetSVESize() == kDRegSizeInBytesLog2) {4398form = "'Xd, p'u1210, 'Zn.'t";4399}4400FormatWithDecodedMnemonic(instr, form);4401}44024403void Disassembler::VisitSVEExtractElementToSIMDFPScalarRegister(4404const Instruction *instr) {4405FormatWithDecodedMnemonic(instr, "'t'u0400, 'Pgl, 'Zn.'t");4406}44074408void Disassembler::VisitSVEFFRInitialise(const Instruction *instr) {4409DisassembleNoArgs(instr);4410}44114412void Disassembler::VisitSVEFFRWriteFromPredicate(const Instruction *instr) {4413FormatWithDecodedMnemonic(instr, "'Pn.b");4414}44154416void Disassembler::VisitSVEFPArithmeticWithImm_Predicated(4417const Instruction *instr) {4418const char *form = "'Zd.'t, 'Pgl/m, 'Zd.'t, #";4419const char *suffix00 = "0.0";4420const char *suffix05 = "0.5";4421const char *suffix10 = "1.0";4422const char *suffix20 = "2.0";4423int i1 = instr->ExtractBit(5);4424const char *suffix = i1 ? suffix10 : suffix00;44254426if (instr->GetSVEVectorFormat() == kFormatVnB) {4427VisitUnallocated(instr);4428return;4429}44304431switch (form_hash_) {4432case "fadd_z_p_zs"_h:4433case "fsubr_z_p_zs"_h:4434case "fsub_z_p_zs"_h:4435suffix = i1 ? suffix10 : suffix05;4436break;4437case "fmul_z_p_zs"_h:4438suffix = i1 ? suffix20 : suffix05;4439break;4440}4441FormatWithDecodedMnemonic(instr, form, suffix);4442}44434444void Disassembler::VisitSVEFPArithmetic_Predicated(const Instruction *instr) {4445if (instr->GetSVEVectorFormat() == kFormatVnB) {4446VisitUnallocated(instr);4447} else {4448FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");4449}4450}44514452void Disassembler::VisitSVEFPConvertPrecision(const Instruction *instr) {4453const char *form = NULL;44544455switch (form_hash_) {4456case "fcvt_z_p_z_d2h"_h:4457form = "'Zd.h, 'Pgl/m, 'Zn.d";4458break;4459case "fcvt_z_p_z_d2s"_h:4460form = "'Zd.s, 'Pgl/m, 'Zn.d";4461break;4462case "fcvt_z_p_z_h2d"_h:4463form = "'Zd.d, 'Pgl/m, 'Zn.h";4464break;4465case "fcvt_z_p_z_h2s"_h:4466form = "'Zd.s, 'Pgl/m, 'Zn.h";4467break;4468case "fcvt_z_p_z_s2d"_h:4469form = "'Zd.d, 'Pgl/m, 'Zn.s";4470break;4471case "fcvt_z_p_z_s2h"_h:4472form = "'Zd.h, 'Pgl/m, 'Zn.s";4473break;4474}4475FormatWithDecodedMnemonic(instr, form);4476}44774478void Disassembler::VisitSVEFPConvertToInt(const Instruction *instr) {4479const char *form = NULL;44804481switch (form_hash_) {4482case "fcvtzs_z_p_z_d2w"_h:4483case "fcvtzu_z_p_z_d2w"_h:4484form = "'Zd.s, 'Pgl/m, 'Zn.d";4485break;4486case "fcvtzs_z_p_z_d2x"_h:4487case "fcvtzu_z_p_z_d2x"_h:4488form = "'Zd.d, 'Pgl/m, 'Zn.d";4489break;4490case "fcvtzs_z_p_z_fp162h"_h:4491case "fcvtzu_z_p_z_fp162h"_h:4492form = "'Zd.h, 'Pgl/m, 'Zn.h";4493break;4494case "fcvtzs_z_p_z_fp162w"_h:4495case "fcvtzu_z_p_z_fp162w"_h:4496form = "'Zd.s, 'Pgl/m, 'Zn.h";4497break;4498case "fcvtzs_z_p_z_fp162x"_h:4499case "fcvtzu_z_p_z_fp162x"_h:4500form = "'Zd.d, 'Pgl/m, 'Zn.h";4501break;4502case "fcvtzs_z_p_z_s2w"_h:4503case "fcvtzu_z_p_z_s2w"_h:4504form = "'Zd.s, 'Pgl/m, 'Zn.s";4505break;4506case "fcvtzs_z_p_z_s2x"_h:4507case "fcvtzu_z_p_z_s2x"_h:4508form = "'Zd.d, 'Pgl/m, 'Zn.s";4509break;4510}4511FormatWithDecodedMnemonic(instr, form);4512}45134514void Disassembler::VisitSVEFPExponentialAccelerator(const Instruction *instr) {4515unsigned size = instr->GetSVESize();4516if ((size == kHRegSizeInBytesLog2) || (size == kSRegSizeInBytesLog2) ||4517(size == kDRegSizeInBytesLog2)) {4518FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t");4519} else {4520VisitUnallocated(instr);4521}4522}45234524void Disassembler::VisitSVEFPRoundToIntegralValue(const Instruction *instr) {4525if (instr->GetSVEVectorFormat() == kFormatVnB) {4526VisitUnallocated(instr);4527} else {4528FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zn.'t");4529}4530}45314532void Disassembler::VisitSVEFPTrigMulAddCoefficient(const Instruction *instr) {4533unsigned size = instr->GetSVESize();4534if ((size == kHRegSizeInBytesLog2) || (size == kSRegSizeInBytesLog2) ||4535(size == kDRegSizeInBytesLog2)) {4536FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zd.'t, 'Zn.'t, #'u1816");4537} else {4538VisitUnallocated(instr);4539}4540}45414542void Disassembler::VisitSVEFPTrigSelectCoefficient(const Instruction *instr) {4543unsigned size = instr->GetSVESize();4544if ((size == kHRegSizeInBytesLog2) || (size == kSRegSizeInBytesLog2) ||4545(size == kDRegSizeInBytesLog2)) {4546FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t, 'Zm.'t");4547} else {4548VisitUnallocated(instr);4549}4550}45514552void Disassembler::VisitSVEFPUnaryOp(const Instruction *instr) {4553if (instr->GetSVESize() == kBRegSizeInBytesLog2) {4554VisitUnallocated(instr);4555} else {4556FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zn.'t");4557}4558}45594560static const char *IncDecFormHelper(const Instruction *instr,4561const char *reg_pat_mul_form,4562const char *reg_pat_form,4563const char *reg_form) {4564if (instr->ExtractBits(19, 16) == 0) {4565if (instr->ExtractBits(9, 5) == SVE_ALL) {4566// Use the register only form if the multiplier is one (encoded as zero)4567// and the pattern is SVE_ALL.4568return reg_form;4569}4570// Use the register and pattern form if the multiplier is one.4571return reg_pat_form;4572}4573return reg_pat_mul_form;4574}45754576void Disassembler::VisitSVEIncDecRegisterByElementCount(4577const Instruction *instr) {4578const char *form =4579IncDecFormHelper(instr, "'Xd, 'Ipc, mul #'u1916+1", "'Xd, 'Ipc", "'Xd");4580FormatWithDecodedMnemonic(instr, form);4581}45824583void Disassembler::VisitSVEIncDecVectorByElementCount(4584const Instruction *instr) {4585const char *form = IncDecFormHelper(instr,4586"'Zd.'t, 'Ipc, mul #'u1916+1",4587"'Zd.'t, 'Ipc",4588"'Zd.'t");4589FormatWithDecodedMnemonic(instr, form);4590}45914592void Disassembler::VisitSVEInsertGeneralRegister(const Instruction *instr) {4593const char *form = "'Zd.'t, 'Wn";4594if (instr->GetSVESize() == kDRegSizeInBytesLog2) {4595form = "'Zd.'t, 'Xn";4596}4597FormatWithDecodedMnemonic(instr, form);4598}45994600void Disassembler::VisitSVEInsertSIMDFPScalarRegister(4601const Instruction *instr) {4602FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Vnv");4603}46044605void Disassembler::VisitSVEIntAddSubtractImm_Unpredicated(4606const Instruction *instr) {4607const char *form = (instr->ExtractBit(13) == 0)4608? "'Zd.'t, 'Zd.'t, #'u1205"4609: "'Zd.'t, 'Zd.'t, #'u1205, lsl #8";4610FormatWithDecodedMnemonic(instr, form);4611}46124613void Disassembler::VisitSVEIntAddSubtractVectors_Predicated(4614const Instruction *instr) {4615FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");4616}46174618void Disassembler::VisitSVEIntCompareScalarCountAndLimit(4619const Instruction *instr) {4620const char *form =4621(instr->ExtractBit(12) == 0) ? "'Pd.'t, 'Wn, 'Wm" : "'Pd.'t, 'Xn, 'Xm";4622FormatWithDecodedMnemonic(instr, form);4623}46244625void Disassembler::VisitSVEIntConvertToFP(const Instruction *instr) {4626const char *form = NULL;4627switch (form_hash_) {4628case "scvtf_z_p_z_h2fp16"_h:4629case "ucvtf_z_p_z_h2fp16"_h:4630form = "'Zd.h, 'Pgl/m, 'Zn.h";4631break;4632case "scvtf_z_p_z_w2d"_h:4633case "ucvtf_z_p_z_w2d"_h:4634form = "'Zd.d, 'Pgl/m, 'Zn.s";4635break;4636case "scvtf_z_p_z_w2fp16"_h:4637case "ucvtf_z_p_z_w2fp16"_h:4638form = "'Zd.h, 'Pgl/m, 'Zn.s";4639break;4640case "scvtf_z_p_z_w2s"_h:4641case "ucvtf_z_p_z_w2s"_h:4642form = "'Zd.s, 'Pgl/m, 'Zn.s";4643break;4644case "scvtf_z_p_z_x2d"_h:4645case "ucvtf_z_p_z_x2d"_h:4646form = "'Zd.d, 'Pgl/m, 'Zn.d";4647break;4648case "scvtf_z_p_z_x2fp16"_h:4649case "ucvtf_z_p_z_x2fp16"_h:4650form = "'Zd.h, 'Pgl/m, 'Zn.d";4651break;4652case "scvtf_z_p_z_x2s"_h:4653case "ucvtf_z_p_z_x2s"_h:4654form = "'Zd.s, 'Pgl/m, 'Zn.d";4655break;4656}4657FormatWithDecodedMnemonic(instr, form);4658}46594660void Disassembler::VisitSVEIntDivideVectors_Predicated(4661const Instruction *instr) {4662unsigned size = instr->GetSVESize();4663if ((size == kSRegSizeInBytesLog2) || (size == kDRegSizeInBytesLog2)) {4664FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");4665} else {4666VisitUnallocated(instr);4667}4668}46694670void Disassembler::VisitSVEIntMinMaxDifference_Predicated(4671const Instruction *instr) {4672FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");4673}46744675void Disassembler::VisitSVEIntMinMaxImm_Unpredicated(const Instruction *instr) {4676const char *form = "'Zd.'t, 'Zd.'t, #";4677const char *suffix = "'u1205";46784679switch (form_hash_) {4680case "smax_z_zi"_h:4681case "smin_z_zi"_h:4682suffix = "'s1205";4683break;4684}4685FormatWithDecodedMnemonic(instr, form, suffix);4686}46874688void Disassembler::VisitSVEIntMulImm_Unpredicated(const Instruction *instr) {4689FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zd.'t, #'s1205");4690}46914692void Disassembler::VisitSVEIntMulVectors_Predicated(const Instruction *instr) {4693FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");4694}46954696void Disassembler::VisitSVELoadAndBroadcastElement(const Instruction *instr) {4697const char *form = "(SVELoadAndBroadcastElement)";4698const char *suffix_b = ", #'u2116]";4699const char *suffix_h = ", #'u2116*2]";4700const char *suffix_w = ", #'u2116*4]";4701const char *suffix_d = ", #'u2116*8]";4702const char *suffix = NULL;47034704switch (form_hash_) {4705case "ld1rb_z_p_bi_u8"_h:4706form = "{'Zt.b}, 'Pgl/z, ['Xns";4707suffix = suffix_b;4708break;4709case "ld1rb_z_p_bi_u16"_h:4710case "ld1rsb_z_p_bi_s16"_h:4711form = "{'Zt.h}, 'Pgl/z, ['Xns";4712suffix = suffix_b;4713break;4714case "ld1rb_z_p_bi_u32"_h:4715case "ld1rsb_z_p_bi_s32"_h:4716form = "{'Zt.s}, 'Pgl/z, ['Xns";4717suffix = suffix_b;4718break;4719case "ld1rb_z_p_bi_u64"_h:4720case "ld1rsb_z_p_bi_s64"_h:4721form = "{'Zt.d}, 'Pgl/z, ['Xns";4722suffix = suffix_b;4723break;4724case "ld1rh_z_p_bi_u16"_h:4725form = "{'Zt.h}, 'Pgl/z, ['Xns";4726suffix = suffix_h;4727break;4728case "ld1rh_z_p_bi_u32"_h:4729case "ld1rsh_z_p_bi_s32"_h:4730form = "{'Zt.s}, 'Pgl/z, ['Xns";4731suffix = suffix_h;4732break;4733case "ld1rh_z_p_bi_u64"_h:4734case "ld1rsh_z_p_bi_s64"_h:4735form = "{'Zt.d}, 'Pgl/z, ['Xns";4736suffix = suffix_h;4737break;4738case "ld1rw_z_p_bi_u32"_h:4739form = "{'Zt.s}, 'Pgl/z, ['Xns";4740suffix = suffix_w;4741break;4742case "ld1rsw_z_p_bi_s64"_h:4743case "ld1rw_z_p_bi_u64"_h:4744form = "{'Zt.d}, 'Pgl/z, ['Xns";4745suffix = suffix_w;4746break;4747case "ld1rd_z_p_bi_u64"_h:4748form = "{'Zt.d}, 'Pgl/z, ['Xns";4749suffix = suffix_d;4750break;4751}47524753// Hide curly brackets if immediate is zero.4754if (instr->ExtractBits(21, 16) == 0) {4755suffix = "]";4756}47574758FormatWithDecodedMnemonic(instr, form, suffix);4759}47604761void Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm(4762const Instruction *instr) {4763const char *form = "{'Zt.'tmsz}, 'Pgl/z, ['Xns";4764const char *suffix = ", #'s1916*16]";47654766switch (form_hash_) {4767case "ld1rob_z_p_bi_u8"_h:4768case "ld1rod_z_p_bi_u64"_h:4769case "ld1roh_z_p_bi_u16"_h:4770case "ld1row_z_p_bi_u32"_h:4771suffix = ", #'s1916*32]";4772break;4773}4774if (instr->ExtractBits(19, 16) == 0) suffix = "]";47754776FormatWithDecodedMnemonic(instr, form, suffix);4777}47784779void Disassembler::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar(4780const Instruction *instr) {4781const char *form = "{'Zt.'tmsz}, 'Pgl/z, ['Xns, ";4782const char *suffix = "'Rm, lsl #'u2423]";47834784switch (form_hash_) {4785case "ld1rqb_z_p_br_contiguous"_h:4786case "ld1rob_z_p_br_contiguous"_h:4787suffix = "'Rm]";4788break;4789}4790FormatWithDecodedMnemonic(instr, form, suffix);4791}47924793void Disassembler::VisitSVELoadMultipleStructures_ScalarPlusImm(4794const Instruction *instr) {4795const char *form = "{'Zt.'tmsz, 'Zt2.'tmsz}";4796const char *form_3 = "{'Zt.'tmsz, 'Zt2.'tmsz, 'Zt3.'tmsz}";4797const char *form_4 = "{'Zt.'tmsz, 'Zt2.'tmsz, 'Zt3.'tmsz, 'Zt4.'tmsz}";4798const char *suffix = ", 'Pgl/z, ['Xns'ISveSvl]";47994800switch (form_hash_) {4801case "ld3b_z_p_bi_contiguous"_h:4802case "ld3d_z_p_bi_contiguous"_h:4803case "ld3h_z_p_bi_contiguous"_h:4804case "ld3w_z_p_bi_contiguous"_h:4805form = form_3;4806break;4807case "ld4b_z_p_bi_contiguous"_h:4808case "ld4d_z_p_bi_contiguous"_h:4809case "ld4h_z_p_bi_contiguous"_h:4810case "ld4w_z_p_bi_contiguous"_h:4811form = form_4;4812break;4813}4814FormatWithDecodedMnemonic(instr, form, suffix);4815}48164817void Disassembler::VisitSVELoadMultipleStructures_ScalarPlusScalar(4818const Instruction *instr) {4819const char *form = "{'Zt.'tmsz, 'Zt2.'tmsz}";4820const char *form_3 = "{'Zt.'tmsz, 'Zt2.'tmsz, 'Zt3.'tmsz}";4821const char *form_4 = "{'Zt.'tmsz, 'Zt2.'tmsz, 'Zt3.'tmsz, 'Zt4.'tmsz}";4822const char *suffix = ", 'Pgl/z, ['Xns, 'Xm'NSveS]";48234824switch (form_hash_) {4825case "ld3b_z_p_br_contiguous"_h:4826case "ld3d_z_p_br_contiguous"_h:4827case "ld3h_z_p_br_contiguous"_h:4828case "ld3w_z_p_br_contiguous"_h:4829form = form_3;4830break;4831case "ld4b_z_p_br_contiguous"_h:4832case "ld4d_z_p_br_contiguous"_h:4833case "ld4h_z_p_br_contiguous"_h:4834case "ld4w_z_p_br_contiguous"_h:4835form = form_4;4836break;4837}4838FormatWithDecodedMnemonic(instr, form, suffix);4839}48404841void Disassembler::VisitSVELoadPredicateRegister(const Instruction *instr) {4842const char *form = "'Pd, ['Xns, #'s2116:1210, mul vl]";4843if (instr->Mask(0x003f1c00) == 0) {4844form = "'Pd, ['Xns]";4845}4846FormatWithDecodedMnemonic(instr, form);4847}48484849void Disassembler::VisitSVELoadVectorRegister(const Instruction *instr) {4850const char *form = "'Zt, ['Xns, #'s2116:1210, mul vl]";4851if (instr->Mask(0x003f1c00) == 0) {4852form = "'Zd, ['Xns]";4853}4854FormatWithDecodedMnemonic(instr, form);4855}48564857void Disassembler::VisitSVEPartitionBreakCondition(const Instruction *instr) {4858FormatWithDecodedMnemonic(instr, "'Pd.b, p'u1310/'?04:mz, 'Pn.b");4859}48604861void Disassembler::VisitSVEPermutePredicateElements(const Instruction *instr) {4862FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pn.'t, 'Pm.'t");4863}48644865void Disassembler::VisitSVEPredicateFirstActive(const Instruction *instr) {4866FormatWithDecodedMnemonic(instr, "'Pd.b, 'Pn, 'Pd.b");4867}48684869void Disassembler::VisitSVEPredicateReadFromFFR_Unpredicated(4870const Instruction *instr) {4871FormatWithDecodedMnemonic(instr, "'Pd.b");4872}48734874void Disassembler::VisitSVEPredicateTest(const Instruction *instr) {4875FormatWithDecodedMnemonic(instr, "p'u1310, 'Pn.b");4876}48774878void Disassembler::VisitSVEPredicateZero(const Instruction *instr) {4879FormatWithDecodedMnemonic(instr, "'Pd.b");4880}48814882void Disassembler::VisitSVEPropagateBreakToNextPartition(4883const Instruction *instr) {4884FormatWithDecodedMnemonic(instr, "'Pd.b, p'u1310/z, 'Pn.b, 'Pd.b");4885}48864887void Disassembler::VisitSVEReversePredicateElements(const Instruction *instr) {4888FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pn.'t");4889}48904891void Disassembler::VisitSVEReverseVectorElements(const Instruction *instr) {4892FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t");4893}48944895void Disassembler::VisitSVEReverseWithinElements(const Instruction *instr) {4896const char *mnemonic = "unimplemented";4897const char *form = "'Zd.'t, 'Pgl/m, 'Zn.'t";48984899unsigned size = instr->GetSVESize();4900switch (instr->Mask(SVEReverseWithinElementsMask)) {4901case RBIT_z_p_z:4902mnemonic = "rbit";4903break;4904case REVB_z_z:4905if ((size == kHRegSizeInBytesLog2) || (size == kSRegSizeInBytesLog2) ||4906(size == kDRegSizeInBytesLog2)) {4907mnemonic = "revb";4908} else {4909form = "(SVEReverseWithinElements)";4910}4911break;4912case REVH_z_z:4913if ((size == kSRegSizeInBytesLog2) || (size == kDRegSizeInBytesLog2)) {4914mnemonic = "revh";4915} else {4916form = "(SVEReverseWithinElements)";4917}4918break;4919case REVW_z_z:4920if (size == kDRegSizeInBytesLog2) {4921mnemonic = "revw";4922} else {4923form = "(SVEReverseWithinElements)";4924}4925break;4926default:4927break;4928}4929Format(instr, mnemonic, form);4930}49314932void Disassembler::VisitSVESaturatingIncDecRegisterByElementCount(4933const Instruction *instr) {4934const char *form = IncDecFormHelper(instr,4935"'R20d, 'Ipc, mul #'u1916+1",4936"'R20d, 'Ipc",4937"'R20d");4938const char *form_sx = IncDecFormHelper(instr,4939"'Xd, 'Wd, 'Ipc, mul #'u1916+1",4940"'Xd, 'Wd, 'Ipc",4941"'Xd, 'Wd");49424943switch (form_hash_) {4944case "sqdecb_r_rs_sx"_h:4945case "sqdecd_r_rs_sx"_h:4946case "sqdech_r_rs_sx"_h:4947case "sqdecw_r_rs_sx"_h:4948case "sqincb_r_rs_sx"_h:4949case "sqincd_r_rs_sx"_h:4950case "sqinch_r_rs_sx"_h:4951case "sqincw_r_rs_sx"_h:4952form = form_sx;4953break;4954}4955FormatWithDecodedMnemonic(instr, form);4956}49574958void Disassembler::VisitSVESaturatingIncDecVectorByElementCount(4959const Instruction *instr) {4960const char *form = IncDecFormHelper(instr,4961"'Zd.'t, 'Ipc, mul #'u1916+1",4962"'Zd.'t, 'Ipc",4963"'Zd.'t");4964FormatWithDecodedMnemonic(instr, form);4965}49664967void Disassembler::VisitSVEStoreMultipleStructures_ScalarPlusImm(4968const Instruction *instr) {4969const char *form = "{'Zt.'tmsz, 'Zt2.'tmsz}";4970const char *form_3 = "{'Zt.'tmsz, 'Zt2.'tmsz, 'Zt3.'tmsz}";4971const char *form_4 = "{'Zt.'tmsz, 'Zt2.'tmsz, 'Zt3.'tmsz, 'Zt4.'tmsz}";4972const char *suffix = ", 'Pgl, ['Xns'ISveSvl]";49734974switch (form_hash_) {4975case "st3b_z_p_bi_contiguous"_h:4976case "st3h_z_p_bi_contiguous"_h:4977case "st3w_z_p_bi_contiguous"_h:4978case "st3d_z_p_bi_contiguous"_h:4979form = form_3;4980break;4981case "st4b_z_p_bi_contiguous"_h:4982case "st4h_z_p_bi_contiguous"_h:4983case "st4w_z_p_bi_contiguous"_h:4984case "st4d_z_p_bi_contiguous"_h:4985form = form_4;4986break;4987}4988FormatWithDecodedMnemonic(instr, form, suffix);4989}49904991void Disassembler::VisitSVEStoreMultipleStructures_ScalarPlusScalar(4992const Instruction *instr) {4993const char *form = "{'Zt.'tmsz, 'Zt2.'tmsz}";4994const char *form_3 = "{'Zt.'tmsz, 'Zt2.'tmsz, 'Zt3.'tmsz}";4995const char *form_4 = "{'Zt.'tmsz, 'Zt2.'tmsz, 'Zt3.'tmsz, 'Zt4.'tmsz}";4996const char *suffix = ", 'Pgl, ['Xns, 'Xm'NSveS]";49974998switch (form_hash_) {4999case "st3b_z_p_br_contiguous"_h:5000case "st3d_z_p_br_contiguous"_h:5001case "st3h_z_p_br_contiguous"_h:5002case "st3w_z_p_br_contiguous"_h:5003form = form_3;5004break;5005case "st4b_z_p_br_contiguous"_h:5006case "st4d_z_p_br_contiguous"_h:5007case "st4h_z_p_br_contiguous"_h:5008case "st4w_z_p_br_contiguous"_h:5009form = form_4;5010break;5011}5012FormatWithDecodedMnemonic(instr, form, suffix);5013}50145015void Disassembler::VisitSVEStorePredicateRegister(const Instruction *instr) {5016const char *form = "'Pd, ['Xns, #'s2116:1210, mul vl]";5017if (instr->Mask(0x003f1c00) == 0) {5018form = "'Pd, ['Xns]";5019}5020FormatWithDecodedMnemonic(instr, form);5021}50225023void Disassembler::VisitSVEStoreVectorRegister(const Instruction *instr) {5024const char *form = "'Zt, ['Xns, #'s2116:1210, mul vl]";5025if (instr->Mask(0x003f1c00) == 0) {5026form = "'Zd, ['Xns]";5027}5028FormatWithDecodedMnemonic(instr, form);5029}50305031void Disassembler::VisitSVETableLookup(const Instruction *instr) {5032FormatWithDecodedMnemonic(instr, "'Zd.'t, {'Zn.'t}, 'Zm.'t");5033}50345035void Disassembler::VisitSVEUnpackPredicateElements(const Instruction *instr) {5036FormatWithDecodedMnemonic(instr, "'Pd.h, 'Pn.b");5037}50385039void Disassembler::VisitSVEUnpackVectorElements(const Instruction *instr) {5040if (instr->GetSVESize() == 0) {5041// The lowest lane size of the destination vector is H-sized lane.5042VisitUnallocated(instr);5043} else {5044FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'th");5045}5046}50475048void Disassembler::VisitSVEVectorSplice(const Instruction *instr) {5049FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl, 'Zd.'t, 'Zn.'t");5050}50515052void Disassembler::VisitSVEAddressGeneration(const Instruction *instr) {5053const char *mnemonic = "adr";5054const char *form = "'Zd.d, ['Zn.d, 'Zm.d";5055const char *suffix = NULL;50565057bool msz_is_zero = (instr->ExtractBits(11, 10) == 0);50585059switch (instr->Mask(SVEAddressGenerationMask)) {5060case ADR_z_az_d_s32_scaled:5061suffix = msz_is_zero ? ", sxtw]" : ", sxtw #'u1110]";5062break;5063case ADR_z_az_d_u32_scaled:5064suffix = msz_is_zero ? ", uxtw]" : ", uxtw #'u1110]";5065break;5066case ADR_z_az_s_same_scaled:5067case ADR_z_az_d_same_scaled:5068form = "'Zd.'t, ['Zn.'t, 'Zm.'t";5069suffix = msz_is_zero ? "]" : ", lsl #'u1110]";5070break;5071default:5072mnemonic = "unimplemented";5073form = "(SVEAddressGeneration)";5074break;5075}5076Format(instr, mnemonic, form, suffix);5077}50785079void Disassembler::VisitSVEBitwiseLogicalUnpredicated(5080const Instruction *instr) {5081const char *mnemonic = "unimplemented";5082const char *form = "'Zd.d, 'Zn.d, 'Zm.d";50835084switch (instr->Mask(SVEBitwiseLogicalUnpredicatedMask)) {5085case AND_z_zz:5086mnemonic = "and";5087break;5088case BIC_z_zz:5089mnemonic = "bic";5090break;5091case EOR_z_zz:5092mnemonic = "eor";5093break;5094case ORR_z_zz:5095mnemonic = "orr";5096if (instr->GetRn() == instr->GetRm()) {5097mnemonic = "mov";5098form = "'Zd.d, 'Zn.d";5099}5100break;5101default:5102break;5103}5104Format(instr, mnemonic, form);5105}51065107void Disassembler::VisitSVEBitwiseShiftUnpredicated(const Instruction *instr) {5108const char *mnemonic = "unimplemented";5109const char *form = "(SVEBitwiseShiftUnpredicated)";5110unsigned tsize =5111(instr->ExtractBits(23, 22) << 2) | instr->ExtractBits(20, 19);5112unsigned lane_size = instr->GetSVESize();51135114const char *suffix = NULL;5115const char *form_i = "'Zd.'tszs, 'Zn.'tszs, ";51165117switch (form_hash_) {5118case "asr_z_zi"_h:5119case "lsr_z_zi"_h:5120case "sri_z_zzi"_h:5121case "srsra_z_zi"_h:5122case "ssra_z_zi"_h:5123case "ursra_z_zi"_h:5124case "usra_z_zi"_h:5125if (tsize != 0) {5126// The tsz field must not be zero.5127mnemonic = mnemonic_.c_str();5128form = form_i;5129suffix = "'ITriSves";5130}5131break;5132case "lsl_z_zi"_h:5133case "sli_z_zzi"_h:5134if (tsize != 0) {5135// The tsz field must not be zero.5136mnemonic = mnemonic_.c_str();5137form = form_i;5138suffix = "'ITriSver";5139}5140break;5141case "asr_z_zw"_h:5142case "lsl_z_zw"_h:5143case "lsr_z_zw"_h:5144if (lane_size <= kSRegSizeInBytesLog2) {5145mnemonic = mnemonic_.c_str();5146form = "'Zd.'t, 'Zn.'t, 'Zm.d";5147}5148break;5149default:5150break;5151}51525153Format(instr, mnemonic, form, suffix);5154}51555156void Disassembler::VisitSVEElementCount(const Instruction *instr) {5157const char *form =5158IncDecFormHelper(instr, "'Xd, 'Ipc, mul #'u1916+1", "'Xd, 'Ipc", "'Xd");5159FormatWithDecodedMnemonic(instr, form);5160}51615162void Disassembler::VisitSVEFPAccumulatingReduction(const Instruction *instr) {5163if (instr->GetSVEVectorFormat() == kFormatVnB) {5164VisitUnallocated(instr);5165} else {5166FormatWithDecodedMnemonic(instr, "'t'u0400, 'Pgl, 't'u0400, 'Zn.'t");5167}5168}51695170void Disassembler::VisitSVEFPArithmeticUnpredicated(const Instruction *instr) {5171if (instr->GetSVEVectorFormat() == kFormatVnB) {5172VisitUnallocated(instr);5173} else {5174FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t, 'Zm.'t");5175}5176}51775178void Disassembler::VisitSVEFPCompareVectors(const Instruction *instr) {5179if (instr->GetSVEVectorFormat() == kFormatVnB) {5180VisitUnallocated(instr);5181} else {5182FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pgl/z, 'Zn.'t, 'Zm.'t");5183}5184}51855186void Disassembler::VisitSVEFPCompareWithZero(const Instruction *instr) {5187if (instr->GetSVEVectorFormat() == kFormatVnB) {5188VisitUnallocated(instr);5189} else {5190FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pgl/z, 'Zn.'t, #0.0");5191}5192}51935194void Disassembler::VisitSVEFPComplexAddition(const Instruction *instr) {5195// Bit 15 is always set, so this gives 90 * 1 or 3.5196const char *form = "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t, #'u1615*90";5197if (instr->GetSVEVectorFormat() == kFormatVnB) {5198VisitUnallocated(instr);5199} else {5200FormatWithDecodedMnemonic(instr, form);5201}5202}52035204void Disassembler::VisitSVEFPComplexMulAdd(const Instruction *instr) {5205const char *form = "'Zd.'t, 'Pgl/m, 'Zn.'t, 'Zm.'t, #'u1413*90";5206if (instr->GetSVEVectorFormat() == kFormatVnB) {5207VisitUnallocated(instr);5208} else {5209FormatWithDecodedMnemonic(instr, form);5210}5211}52125213void Disassembler::VisitSVEFPComplexMulAddIndex(const Instruction *instr) {5214const char *form = "'Zd.h, 'Zn.h, z'u1816.h['u2019]";5215const char *suffix = ", #'u1110*90";5216switch (form_hash_) {5217case "fcmla_z_zzzi_s"_h:5218form = "'Zd.s, 'Zn.s, z'u1916.s['u2020]";5219break;5220}5221FormatWithDecodedMnemonic(instr, form, suffix);5222}52235224void Disassembler::VisitSVEFPFastReduction(const Instruction *instr) {5225if (instr->GetSVEVectorFormat() == kFormatVnB) {5226VisitUnallocated(instr);5227} else {5228FormatWithDecodedMnemonic(instr, "'t'u0400, 'Pgl, 'Zn.'t");5229}5230}52315232void Disassembler::VisitSVEFPMulIndex(const Instruction *instr) {5233const char *form = "'Zd.h, 'Zn.h, z'u1816.h['u2222:2019]";5234switch (form_hash_) {5235case "fmul_z_zzi_d"_h:5236form = "'Zd.d, 'Zn.d, z'u1916.d['u2020]";5237break;5238case "fmul_z_zzi_s"_h:5239form = "'Zd.s, 'Zn.s, z'u1816.s['u2019]";5240break;5241}5242FormatWithDecodedMnemonic(instr, form);5243}52445245void Disassembler::VisitSVEFPMulAdd(const Instruction *instr) {5246if (instr->GetSVEVectorFormat() == kFormatVnB) {5247VisitUnallocated(instr);5248} else {5249FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zn.'t, 'Zm.'t");5250}5251}52525253void Disassembler::VisitSVEFPMulAddIndex(const Instruction *instr) {5254const char *form = "'Zd.h, 'Zn.h, z'u1816.h['u2222:2019]";5255switch (form_hash_) {5256case "fmla_z_zzzi_s"_h:5257case "fmls_z_zzzi_s"_h:5258form = "'Zd.s, 'Zn.s, z'u1816.s['u2019]";5259break;5260case "fmla_z_zzzi_d"_h:5261case "fmls_z_zzzi_d"_h:5262form = "'Zd.d, 'Zn.d, z'u1916.d['u2020]";5263break;5264}5265FormatWithDecodedMnemonic(instr, form);5266}52675268void Disassembler::VisitSVEFPUnaryOpUnpredicated(const Instruction *instr) {5269if (instr->GetSVEVectorFormat() == kFormatVnB) {5270VisitUnallocated(instr);5271} else {5272FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t");5273}5274}52755276void Disassembler::VisitSVEIncDecByPredicateCount(const Instruction *instr) {5277const char *form = "'Zd.'t, 'Pn";5278switch (form_hash_) {5279// <Xdn>, <Pg>.<T>5280case "decp_r_p_r"_h:5281case "incp_r_p_r"_h:5282form = "'Xd, 'Pn.'t";5283break;5284// <Xdn>, <Pg>.<T>, <Wdn>5285case "sqdecp_r_p_r_sx"_h:5286case "sqincp_r_p_r_sx"_h:5287form = "'Xd, 'Pn.'t, 'Wd";5288break;5289// <Xdn>, <Pg>.<T>5290case "sqdecp_r_p_r_x"_h:5291case "sqincp_r_p_r_x"_h:5292case "uqdecp_r_p_r_x"_h:5293case "uqincp_r_p_r_x"_h:5294form = "'Xd, 'Pn.'t";5295break;5296// <Wdn>, <Pg>.<T>5297case "uqdecp_r_p_r_uw"_h:5298case "uqincp_r_p_r_uw"_h:5299form = "'Wd, 'Pn.'t";5300break;5301}5302FormatWithDecodedMnemonic(instr, form);5303}53045305void Disassembler::VisitSVEIndexGeneration(const Instruction *instr) {5306const char *form = "'Zd.'t, #'s0905, #'s2016";5307bool w_inputs =5308static_cast<unsigned>(instr->GetSVESize()) <= kWRegSizeInBytesLog2;53095310switch (form_hash_) {5311case "index_z_ir"_h:5312form = w_inputs ? "'Zd.'t, #'s0905, 'Wm" : "'Zd.'t, #'s0905, 'Xm";5313break;5314case "index_z_ri"_h:5315form = w_inputs ? "'Zd.'t, 'Wn, #'s2016" : "'Zd.'t, 'Xn, #'s2016";5316break;5317case "index_z_rr"_h:5318form = w_inputs ? "'Zd.'t, 'Wn, 'Wm" : "'Zd.'t, 'Xn, 'Xm";5319break;5320}5321FormatWithDecodedMnemonic(instr, form);5322}53235324void Disassembler::VisitSVEIntArithmeticUnpredicated(const Instruction *instr) {5325FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t, 'Zm.'t");5326}53275328void Disassembler::VisitSVEIntCompareSignedImm(const Instruction *instr) {5329FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pgl/z, 'Zn.'t, #'s2016");5330}53315332void Disassembler::VisitSVEIntCompareUnsignedImm(const Instruction *instr) {5333FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pgl/z, 'Zn.'t, #'u2014");5334}53355336void Disassembler::VisitSVEIntCompareVectors(const Instruction *instr) {5337const char *form = "'Pd.'t, 'Pgl/z, 'Zn.'t, 'Zm.";5338const char *suffix = "d";5339switch (form_hash_) {5340case "cmpeq_p_p_zz"_h:5341case "cmpge_p_p_zz"_h:5342case "cmpgt_p_p_zz"_h:5343case "cmphi_p_p_zz"_h:5344case "cmphs_p_p_zz"_h:5345case "cmpne_p_p_zz"_h:5346suffix = "'t";5347break;5348}5349FormatWithDecodedMnemonic(instr, form, suffix);5350}53515352void Disassembler::VisitSVEIntMulAddPredicated(const Instruction *instr) {5353const char *form = "'Zd.'t, 'Pgl/m, ";5354const char *suffix = "'Zn.'t, 'Zm.'t";5355switch (form_hash_) {5356case "mad_z_p_zzz"_h:5357case "msb_z_p_zzz"_h:5358suffix = "'Zm.'t, 'Zn.'t";5359break;5360}5361FormatWithDecodedMnemonic(instr, form, suffix);5362}53635364void Disassembler::VisitSVEIntMulAddUnpredicated(const Instruction *instr) {5365if (static_cast<unsigned>(instr->GetSVESize()) >= kSRegSizeInBytesLog2) {5366FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'tq, 'Zm.'tq");5367} else {5368VisitUnallocated(instr);5369}5370}53715372void Disassembler::VisitSVEMovprfx(const Instruction *instr) {5373FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/'?16:mz, 'Zn.'t");5374}53755376void Disassembler::VisitSVEIntReduction(const Instruction *instr) {5377const char *form = "'Vdv, 'Pgl, 'Zn.'t";5378switch (form_hash_) {5379case "saddv_r_p_z"_h:5380case "uaddv_r_p_z"_h:5381form = "'Dd, 'Pgl, 'Zn.'t";5382break;5383}5384FormatWithDecodedMnemonic(instr, form);5385}53865387void Disassembler::VisitSVEIntUnaryArithmeticPredicated(5388const Instruction *instr) {5389VectorFormat vform = instr->GetSVEVectorFormat();53905391switch (form_hash_) {5392case "sxtw_z_p_z"_h:5393case "uxtw_z_p_z"_h:5394if (vform == kFormatVnS) {5395VisitUnallocated(instr);5396return;5397}5398VIXL_FALLTHROUGH();5399case "sxth_z_p_z"_h:5400case "uxth_z_p_z"_h:5401if (vform == kFormatVnH) {5402VisitUnallocated(instr);5403return;5404}5405VIXL_FALLTHROUGH();5406case "sxtb_z_p_z"_h:5407case "uxtb_z_p_z"_h:5408case "fabs_z_p_z"_h:5409case "fneg_z_p_z"_h:5410if (vform == kFormatVnB) {5411VisitUnallocated(instr);5412return;5413}5414break;5415}54165417FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zn.'t");5418}54195420void Disassembler::VisitSVEMulIndex(const Instruction *instr) {5421const char *form = "'Zd.s, 'Zn.b, z'u1816.b['u2019]";54225423switch (form_hash_) {5424case "sdot_z_zzzi_d"_h:5425case "udot_z_zzzi_d"_h:5426form = "'Zd.d, 'Zn.h, z'u1916.h['u2020]";5427break;5428}54295430FormatWithDecodedMnemonic(instr, form);5431}54325433void Disassembler::VisitSVEPermuteVectorExtract(const Instruction *instr) {5434FormatWithDecodedMnemonic(instr, "'Zd.b, 'Zd.b, 'Zn.b, #'u2016:1210");5435}54365437void Disassembler::VisitSVEPermuteVectorInterleaving(const Instruction *instr) {5438FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t, 'Zm.'t");5439}54405441void Disassembler::VisitSVEPredicateCount(const Instruction *instr) {5442FormatWithDecodedMnemonic(instr, "'Xd, p'u1310, 'Pn.'t");5443}54445445void Disassembler::VisitSVEPredicateLogical(const Instruction *instr) {5446const char *mnemonic = mnemonic_.c_str();5447const char *form = "'Pd.b, p'u1310/z, 'Pn.b, 'Pm.b";54485449int pd = instr->GetPd();5450int pn = instr->GetPn();5451int pm = instr->GetPm();5452int pg = instr->ExtractBits(13, 10);54535454switch (form_hash_) {5455case "ands_p_p_pp_z"_h:5456if (pn == pm) {5457mnemonic = "movs";5458form = "'Pd.b, p'u1310/z, 'Pn.b";5459}5460break;5461case "and_p_p_pp_z"_h:5462if (pn == pm) {5463mnemonic = "mov";5464form = "'Pd.b, p'u1310/z, 'Pn.b";5465}5466break;5467case "eors_p_p_pp_z"_h:5468if (pm == pg) {5469mnemonic = "nots";5470form = "'Pd.b, 'Pm/z, 'Pn.b";5471}5472break;5473case "eor_p_p_pp_z"_h:5474if (pm == pg) {5475mnemonic = "not";5476form = "'Pd.b, 'Pm/z, 'Pn.b";5477}5478break;5479case "orrs_p_p_pp_z"_h:5480if ((pn == pm) && (pn == pg)) {5481mnemonic = "movs";5482form = "'Pd.b, 'Pn.b";5483}5484break;5485case "orr_p_p_pp_z"_h:5486if ((pn == pm) && (pn == pg)) {5487mnemonic = "mov";5488form = "'Pd.b, 'Pn.b";5489}5490break;5491case "sel_p_p_pp"_h:5492if (pd == pm) {5493mnemonic = "mov";5494form = "'Pd.b, p'u1310/m, 'Pn.b";5495} else {5496form = "'Pd.b, p'u1310, 'Pn.b, 'Pm.b";5497}5498break;5499}5500Format(instr, mnemonic, form);5501}55025503void Disassembler::VisitSVEPredicateInitialize(const Instruction *instr) {5504const char *form = "'Pd.'t, 'Ipc";5505// Omit the pattern if it is the default ('ALL').5506if (instr->ExtractBits(9, 5) == SVE_ALL) form = "'Pd.'t";5507FormatWithDecodedMnemonic(instr, form);5508}55095510void Disassembler::VisitSVEPredicateNextActive(const Instruction *instr) {5511FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pn, 'Pd.'t");5512}55135514void Disassembler::VisitSVEPredicateReadFromFFR_Predicated(5515const Instruction *instr) {5516FormatWithDecodedMnemonic(instr, "'Pd.b, 'Pn/z");5517}55185519void Disassembler::VisitSVEPropagateBreak(const Instruction *instr) {5520FormatWithDecodedMnemonic(instr, "'Pd.b, p'u1310/z, 'Pn.b, 'Pm.b");5521}55225523void Disassembler::VisitSVEStackFrameAdjustment(const Instruction *instr) {5524FormatWithDecodedMnemonic(instr, "'Xds, 'Xms, #'s1005");5525}55265527void Disassembler::VisitSVEStackFrameSize(const Instruction *instr) {5528FormatWithDecodedMnemonic(instr, "'Xd, #'s1005");5529}55305531void Disassembler::VisitSVEVectorSelect(const Instruction *instr) {5532const char *mnemonic = mnemonic_.c_str();5533const char *form = "'Zd.'t, p'u1310, 'Zn.'t, 'Zm.'t";55345535if (instr->GetRd() == instr->GetRm()) {5536mnemonic = "mov";5537form = "'Zd.'t, p'u1310/m, 'Zn.'t";5538}55395540Format(instr, mnemonic, form);5541}55425543void Disassembler::VisitSVEContiguousLoad_ScalarPlusImm(5544const Instruction *instr) {5545const char *form = "{'Zt.'tlss}, 'Pgl/z, ['Xns";5546const char *suffix =5547(instr->ExtractBits(19, 16) == 0) ? "]" : ", #'s1916, mul vl]";5548FormatWithDecodedMnemonic(instr, form, suffix);5549}55505551void Disassembler::VisitSVEContiguousLoad_ScalarPlusScalar(5552const Instruction *instr) {5553const char *form = "{'Zt.'tlss}, 'Pgl/z, ['Xns, 'Xm";5554const char *suffix = "]";55555556switch (form_hash_) {5557case "ld1h_z_p_br_u16"_h:5558case "ld1h_z_p_br_u32"_h:5559case "ld1h_z_p_br_u64"_h:5560case "ld1w_z_p_br_u32"_h:5561case "ld1w_z_p_br_u64"_h:5562case "ld1d_z_p_br_u64"_h:5563suffix = ", lsl #'u2423]";5564break;5565case "ld1sh_z_p_br_s32"_h:5566case "ld1sh_z_p_br_s64"_h:5567suffix = ", lsl #1]";5568break;5569case "ld1sw_z_p_br_s64"_h:5570suffix = ", lsl #2]";5571break;5572}55735574FormatWithDecodedMnemonic(instr, form, suffix);5575}55765577void Disassembler::VisitReserved(const Instruction *instr) {5578// UDF is the only instruction in this group, and the Decoder is precise.5579VIXL_ASSERT(instr->Mask(ReservedMask) == UDF);5580Format(instr, "udf", "'IUdf");5581}55825583void Disassembler::VisitUnimplemented(const Instruction *instr) {5584Format(instr, "unimplemented", "(Unimplemented)");5585}558655875588void Disassembler::VisitUnallocated(const Instruction *instr) {5589Format(instr, "unallocated", "(Unallocated)");5590}55915592void Disassembler::Visit(Metadata *metadata, const Instruction *instr) {5593VIXL_ASSERT(metadata->count("form") > 0);5594const std::string &form = (*metadata)["form"];5595form_hash_ = Hash(form.c_str());5596const FormToVisitorFnMap *fv = Disassembler::GetFormToVisitorFnMap();5597FormToVisitorFnMap::const_iterator it = fv->find(form_hash_);5598if (it == fv->end()) {5599VisitUnimplemented(instr);5600} else {5601SetMnemonicFromForm(form);5602(it->second)(this, instr);5603}5604}56055606void Disassembler::Disassemble_PdT_PgZ_ZnT_ZmT(const Instruction *instr) {5607const char *form = "'Pd.'t, 'Pgl/z, 'Zn.'t, 'Zm.'t";5608VectorFormat vform = instr->GetSVEVectorFormat();56095610if ((vform == kFormatVnS) || (vform == kFormatVnD)) {5611Format(instr, "unimplemented", "(PdT_PgZ_ZnT_ZmT)");5612} else {5613Format(instr, mnemonic_.c_str(), form);5614}5615}56165617void Disassembler::Disassemble_ZdB_Zn1B_Zn2B_imm(const Instruction *instr) {5618const char *form = "'Zd.b, {'Zn.b, 'Zn2.b}, #'u2016:1210";5619Format(instr, mnemonic_.c_str(), form);5620}56215622void Disassembler::Disassemble_ZdB_ZnB_ZmB(const Instruction *instr) {5623const char *form = "'Zd.b, 'Zn.b, 'Zm.b";5624if (instr->GetSVEVectorFormat() == kFormatVnB) {5625Format(instr, mnemonic_.c_str(), form);5626} else {5627Format(instr, "unimplemented", "(ZdB_ZnB_ZmB)");5628}5629}56305631void Disassembler::Disassemble_ZdD_PgM_ZnS(const Instruction *instr) {5632const char *form = "'Zd.d, 'Pgl/m, 'Zn.s";5633Format(instr, mnemonic_.c_str(), form);5634}56355636void Disassembler::Disassemble_ZdD_ZnD_ZmD(const Instruction *instr) {5637const char *form = "'Zd.d, 'Zn.d, 'Zm.d";5638Format(instr, mnemonic_.c_str(), form);5639}56405641void Disassembler::Disassemble_ZdD_ZnD_ZmD_imm(const Instruction *instr) {5642const char *form = "'Zd.d, 'Zn.d, z'u1916.d['u2020]";5643Format(instr, mnemonic_.c_str(), form);5644}56455646void Disassembler::Disassemble_ZdD_ZnS_ZmS_imm(const Instruction *instr) {5647const char *form = "'Zd.d, 'Zn.s, z'u1916.s['u2020:1111]";5648Format(instr, mnemonic_.c_str(), form);5649}56505651void Disassembler::Disassemble_ZdH_PgM_ZnS(const Instruction *instr) {5652const char *form = "'Zd.h, 'Pgl/m, 'Zn.s";5653Format(instr, mnemonic_.c_str(), form);5654}56555656void Disassembler::Disassemble_ZdH_ZnH_ZmH_imm(const Instruction *instr) {5657const char *form = "'Zd.h, 'Zn.h, z'u1816.h['u2222:2019]";5658Format(instr, mnemonic_.c_str(), form);5659}56605661void Disassembler::Disassemble_ZdS_PgM_ZnD(const Instruction *instr) {5662const char *form = "'Zd.s, 'Pgl/m, 'Zn.d";5663Format(instr, mnemonic_.c_str(), form);5664}56655666void Disassembler::Disassemble_ZdS_PgM_ZnH(const Instruction *instr) {5667const char *form = "'Zd.s, 'Pgl/m, 'Zn.h";5668Format(instr, mnemonic_.c_str(), form);5669}56705671void Disassembler::Disassemble_ZdS_PgM_ZnS(const Instruction *instr) {5672const char *form = "'Zd.s, 'Pgl/m, 'Zn.s";5673if (instr->GetSVEVectorFormat() == kFormatVnS) {5674Format(instr, mnemonic_.c_str(), form);5675} else {5676Format(instr, "unimplemented", "(ZdS_PgM_ZnS)");5677}5678}56795680void Disassembler::Disassemble_ZdS_ZnH_ZmH_imm(const Instruction *instr) {5681const char *form = "'Zd.s, 'Zn.h, z'u1816.h['u2019:1111]";5682Format(instr, mnemonic_.c_str(), form);5683}56845685void Disassembler::Disassemble_ZdS_ZnS_ZmS(const Instruction *instr) {5686const char *form = "'Zd.s, 'Zn.s, 'Zm.s";5687Format(instr, mnemonic_.c_str(), form);5688}56895690void Disassembler::Disassemble_ZdS_ZnS_ZmS_imm(const Instruction *instr) {5691const char *form = "'Zd.s, 'Zn.s, z'u1816.s['u2019]";5692Format(instr, mnemonic_.c_str(), form);5693}56945695void Disassembler::DisassembleSVEFlogb(const Instruction *instr) {5696const char *form = "'Zd.'tf, 'Pgl/m, 'Zn.'tf";5697if (instr->GetSVEVectorFormat(17) == kFormatVnB) {5698Format(instr, "unimplemented", "(SVEFlogb)");5699} else {5700Format(instr, mnemonic_.c_str(), form);5701}5702}57035704void Disassembler::Disassemble_ZdT_PgM_ZnT(const Instruction *instr) {5705const char *form = "'Zd.'t, 'Pgl/m, 'Zn.'t";5706Format(instr, mnemonic_.c_str(), form);5707}57085709void Disassembler::Disassemble_ZdT_PgZ_ZnT_ZmT(const Instruction *instr) {5710const char *form = "'Zd.'t, 'Pgl/z, 'Zn.'t, 'Zm.'t";5711VectorFormat vform = instr->GetSVEVectorFormat();5712if ((vform == kFormatVnS) || (vform == kFormatVnD)) {5713Format(instr, mnemonic_.c_str(), form);5714} else {5715Format(instr, "unimplemented", "(ZdT_PgZ_ZnT_ZmT)");5716}5717}57185719void Disassembler::Disassemble_ZdT_Pg_Zn1T_Zn2T(const Instruction *instr) {5720const char *form = "'Zd.'t, 'Pgl, {'Zn.'t, 'Zn2.'t}";5721Format(instr, mnemonic_.c_str(), form);5722}57235724void Disassembler::Disassemble_ZdT_Zn1T_Zn2T_ZmT(const Instruction *instr) {5725const char *form = "'Zd.'t, {'Zn.'t, 'Zn2.'t}, 'Zm.'t";5726Format(instr, mnemonic_.c_str(), form);5727}57285729void Disassembler::Disassemble_ZdT_ZnT_ZmT(const Instruction *instr) {5730const char *form = "'Zd.'t, 'Zn.'t, 'Zm.'t";5731Format(instr, mnemonic_.c_str(), form);5732}57335734void Disassembler::Disassemble_ZdT_ZnT_ZmTb(const Instruction *instr) {5735const char *form = "'Zd.'t, 'Zn.'t, 'Zm.'th";5736if (instr->GetSVEVectorFormat() == kFormatVnB) {5737Format(instr, "unimplemented", "(ZdT_ZnT_ZmTb)");5738} else {5739Format(instr, mnemonic_.c_str(), form);5740}5741}57425743void Disassembler::Disassemble_ZdT_ZnTb(const Instruction *instr) {5744const char *form = "'Zd.'tszs, 'Zn.'tszd";5745std::pair<int, int> shift_and_lane_size =5746instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ false);5747int shift_dist = shift_and_lane_size.first;5748int lane_size = shift_and_lane_size.second;5749// Convert shift_dist from a right to left shift. Valid xtn instructions5750// must have a left shift_dist equivalent of zero.5751shift_dist = (8 << lane_size) - shift_dist;5752if ((lane_size >= static_cast<int>(kBRegSizeInBytesLog2)) &&5753(lane_size <= static_cast<int>(kSRegSizeInBytesLog2)) &&5754(shift_dist == 0)) {5755Format(instr, mnemonic_.c_str(), form);5756} else {5757Format(instr, "unimplemented", "(ZdT_ZnTb)");5758}5759}57605761void Disassembler::Disassemble_ZdT_ZnTb_ZmTb(const Instruction *instr) {5762const char *form = "'Zd.'t, 'Zn.'th, 'Zm.'th";5763if (instr->GetSVEVectorFormat() == kFormatVnB) {5764// TODO: This is correct for saddlbt, ssublbt, subltb, which don't have5765// b-lane sized form, and for pmull[b|t] as feature `SVEPmull128` isn't5766// supported, but may need changes for other instructions reaching here.5767Format(instr, "unimplemented", "(ZdT_ZnTb_ZmTb)");5768} else {5769Format(instr, mnemonic_.c_str(), form);5770}5771}57725773void Disassembler::DisassembleSVEAddSubHigh(const Instruction *instr) {5774const char *form = "'Zd.'th, 'Zn.'t, 'Zm.'t";5775if (instr->GetSVEVectorFormat() == kFormatVnB) {5776Format(instr, "unimplemented", "(SVEAddSubHigh)");5777} else {5778Format(instr, mnemonic_.c_str(), form);5779}5780}57815782void Disassembler::DisassembleSVEShiftLeftImm(const Instruction *instr) {5783const char *form = "'Zd.'tszd, 'Zn.'tszs, 'ITriSver";5784std::pair<int, int> shift_and_lane_size =5785instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ false);5786int lane_size = shift_and_lane_size.second;5787if ((lane_size >= static_cast<int>(kBRegSizeInBytesLog2)) &&5788(lane_size <= static_cast<int>(kSRegSizeInBytesLog2))) {5789Format(instr, mnemonic_.c_str(), form);5790} else {5791Format(instr, "unimplemented", "(SVEShiftLeftImm)");5792}5793}57945795void Disassembler::DisassembleSVEShiftRightImm(const Instruction *instr) {5796const char *form = "'Zd.'tszs, 'Zn.'tszd, 'ITriSves";5797std::pair<int, int> shift_and_lane_size =5798instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ false);5799int lane_size = shift_and_lane_size.second;5800if ((lane_size >= static_cast<int>(kBRegSizeInBytesLog2)) &&5801(lane_size <= static_cast<int>(kSRegSizeInBytesLog2))) {5802Format(instr, mnemonic_.c_str(), form);5803} else {5804Format(instr, "unimplemented", "(SVEShiftRightImm)");5805}5806}58075808void Disassembler::Disassemble_ZdaD_ZnD_ZmD_imm(const Instruction *instr) {5809const char *form = "'Zd.d, 'Zn.d, z'u1916.d['u2020]";5810Format(instr, mnemonic_.c_str(), form);5811}58125813void Disassembler::Disassemble_ZdaD_ZnH_ZmH_imm_const(5814const Instruction *instr) {5815const char *form = "'Zd.d, 'Zn.h, z'u1916.h['u2020], #'u1110*90";5816Format(instr, mnemonic_.c_str(), form);5817}58185819void Disassembler::Disassemble_ZdaD_ZnS_ZmS_imm(const Instruction *instr) {5820const char *form = "'Zd.d, 'Zn.s, z'u1916.s['u2020:1111]";5821Format(instr, mnemonic_.c_str(), form);5822}58235824void Disassembler::Disassemble_ZdaH_ZnH_ZmH_imm(const Instruction *instr) {5825const char *form = "'Zd.h, 'Zn.h, z'u1816.h['u2222:2019]";5826Format(instr, mnemonic_.c_str(), form);5827}58285829void Disassembler::Disassemble_ZdaH_ZnH_ZmH_imm_const(5830const Instruction *instr) {5831const char *form = "'Zd.h, 'Zn.h, z'u1816.h['u2019], #'u1110*90";5832Format(instr, mnemonic_.c_str(), form);5833}58345835void Disassembler::Disassemble_ZdaS_ZnB_ZmB(const Instruction *instr) {5836const char *form = "'Zd.s, 'Zn.b, 'Zm.b";5837Format(instr, mnemonic_.c_str(), form);5838}58395840void Disassembler::Disassemble_ZdaS_ZnB_ZmB_imm_const(5841const Instruction *instr) {5842const char *form = "'Zd.s, 'Zn.b, z'u1816.b['u2019], #'u1110*90";5843Format(instr, mnemonic_.c_str(), form);5844}58455846void Disassembler::Disassemble_ZdaS_ZnH_ZmH(const Instruction *instr) {5847const char *form = "'Zd.s, 'Zn.h, 'Zm.h";5848Format(instr, mnemonic_.c_str(), form);5849}58505851void Disassembler::Disassemble_ZdaS_ZnH_ZmH_imm(const Instruction *instr) {5852const char *form = "'Zd.s, 'Zn.h, z'u1816.h['u2019:1111]";5853Format(instr, mnemonic_.c_str(), form);5854}58555856void Disassembler::Disassemble_ZdaS_ZnS_ZmS_imm(const Instruction *instr) {5857const char *form = "'Zd.s, 'Zn.s, z'u1816.s['u2019]";5858Format(instr, mnemonic_.c_str(), form);5859}58605861void Disassembler::Disassemble_ZdaS_ZnS_ZmS_imm_const(5862const Instruction *instr) {5863const char *form = "'Zd.s, 'Zn.s, z'u1916.s['u2020], #'u1110*90";5864Format(instr, mnemonic_.c_str(), form);5865}58665867void Disassembler::Disassemble_ZdaT_PgM_ZnTb(const Instruction *instr) {5868const char *form = "'Zd.'t, 'Pgl/m, 'Zn.'th";58695870if (instr->GetSVESize() == 0) {5871// The lowest lane size of the destination vector is H-sized lane.5872Format(instr, "unimplemented", "(Disassemble_ZdaT_PgM_ZnTb)");5873return;5874}58755876Format(instr, mnemonic_.c_str(), form);5877}58785879void Disassembler::DisassembleSVEAddSubCarry(const Instruction *instr) {5880const char *form = "'Zd.'?22:ds, 'Zn.'?22:ds, 'Zm.'?22:ds";5881Format(instr, mnemonic_.c_str(), form);5882}58835884void Disassembler::Disassemble_ZdaT_ZnT_ZmT(const Instruction *instr) {5885const char *form = "'Zd.'t, 'Zn.'t, 'Zm.'t";5886Format(instr, mnemonic_.c_str(), form);5887}58885889void Disassembler::Disassemble_ZdaT_ZnT_ZmT_const(const Instruction *instr) {5890const char *form = "'Zd.'t, 'Zn.'t, 'Zm.'t, #'u1110*90";5891Format(instr, mnemonic_.c_str(), form);5892}58935894void Disassembler::Disassemble_ZdaT_ZnTb_ZmTb(const Instruction *instr) {5895const char *form = "'Zd.'t, 'Zn.'th, 'Zm.'th";5896if (instr->GetSVEVectorFormat() == kFormatVnB) {5897Format(instr, "unimplemented", "(ZdaT_ZnTb_ZmTb)");5898} else {5899Format(instr, mnemonic_.c_str(), form);5900}5901}59025903void Disassembler::Disassemble_ZdaT_ZnTb_ZmTb_const(const Instruction *instr) {5904const char *form = "'Zd.'t, 'Zn.'tq, 'Zm.'tq, #'u1110*90";5905VectorFormat vform = instr->GetSVEVectorFormat();59065907if ((vform == kFormatVnB) || (vform == kFormatVnH)) {5908Format(instr, "unimplemented", "(ZdaT_ZnTb_ZmTb_const)");5909} else {5910Format(instr, mnemonic_.c_str(), form);5911}5912}59135914void Disassembler::Disassemble_ZdnB_ZdnB(const Instruction *instr) {5915const char *form = "'Zd.b, 'Zd.b";5916Format(instr, mnemonic_.c_str(), form);5917}59185919void Disassembler::Disassemble_ZdnB_ZdnB_ZmB(const Instruction *instr) {5920const char *form = "'Zd.b, 'Zd.b, 'Zn.b";5921Format(instr, mnemonic_.c_str(), form);5922}59235924void Disassembler::DisassembleSVEBitwiseTernary(const Instruction *instr) {5925const char *form = "'Zd.d, 'Zd.d, 'Zm.d, 'Zn.d";5926Format(instr, mnemonic_.c_str(), form);5927}59285929void Disassembler::Disassemble_ZdnS_ZdnS_ZmS(const Instruction *instr) {5930const char *form = "'Zd.s, 'Zd.s, 'Zn.s";5931Format(instr, mnemonic_.c_str(), form);5932}59335934void Disassembler::DisassembleSVEFPPair(const Instruction *instr) {5935const char *form = "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t";5936if (instr->GetSVEVectorFormat() == kFormatVnB) {5937Format(instr, "unimplemented", "(SVEFPPair)");5938} else {5939Format(instr, mnemonic_.c_str(), form);5940}5941}59425943void Disassembler::Disassemble_ZdnT_PgM_ZdnT_ZmT(const Instruction *instr) {5944const char *form = "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t";5945Format(instr, mnemonic_.c_str(), form);5946}59475948void Disassembler::DisassembleSVEComplexIntAddition(const Instruction *instr) {5949const char *form = "'Zd.'t, 'Zd.'t, 'Zn.'t, #";5950const char *suffix = (instr->ExtractBit(10) == 0) ? "90" : "270";5951Format(instr, mnemonic_.c_str(), form, suffix);5952}59535954void Disassembler::Disassemble_ZdnT_ZdnT_ZmT_const(const Instruction *instr) {5955const char *form = "'Zd.'tszs, 'Zd.'tszs, 'Zn.'tszs, 'ITriSves";5956unsigned tsize =5957(instr->ExtractBits(23, 22) << 2) | instr->ExtractBits(20, 19);59585959if (tsize == 0) {5960Format(instr, "unimplemented", "(ZdnT_ZdnT_ZmT_const)");5961} else {5962Format(instr, mnemonic_.c_str(), form);5963}5964}59655966void Disassembler::Disassemble_ZtD_PgZ_ZnD_Xm(const Instruction *instr) {5967const char *form = "{'Zt.d}, 'Pgl/z, ['Zn.d";5968const char *suffix = instr->GetRm() == 31 ? "]" : ", 'Xm]";5969Format(instr, mnemonic_.c_str(), form, suffix);5970}59715972void Disassembler::Disassemble_ZtD_Pg_ZnD_Xm(const Instruction *instr) {5973const char *form = "{'Zt.d}, 'Pgl, ['Zn.d";5974const char *suffix = instr->GetRm() == 31 ? "]" : ", 'Xm]";5975Format(instr, mnemonic_.c_str(), form, suffix);5976}59775978void Disassembler::Disassemble_ZtS_PgZ_ZnS_Xm(const Instruction *instr) {5979const char *form = "{'Zt.s}, 'Pgl/z, ['Zn.s";5980const char *suffix = instr->GetRm() == 31 ? "]" : ", 'Xm]";5981Format(instr, mnemonic_.c_str(), form, suffix);5982}59835984void Disassembler::Disassemble_ZtS_Pg_ZnS_Xm(const Instruction *instr) {5985const char *form = "{'Zt.s}, 'Pgl, ['Zn.s";5986const char *suffix = instr->GetRm() == 31 ? "]" : ", 'Xm]";5987Format(instr, mnemonic_.c_str(), form, suffix);5988}59895990void Disassembler::Disassemble_XdSP_XnSP_Xm(const Instruction *instr) {5991const char *form = "'Xds, 'Xns";5992const char *suffix = instr->GetRm() == 31 ? "" : ", 'Xm";5993Format(instr, mnemonic_.c_str(), form, suffix);5994}59955996void Disassembler::Disassemble_XdSP_XnSP_uimm6_uimm4(const Instruction *instr) {5997VIXL_STATIC_ASSERT(kMTETagGranuleInBytes == 16);5998const char *form = "'Xds, 'Xns, #'u2116*16, #'u1310";5999Format(instr, mnemonic_.c_str(), form);6000}60016002void Disassembler::Disassemble_Xd_XnSP_Xm(const Instruction *instr) {6003const char *form = "'Rd, 'Xns, 'Rm";6004Format(instr, mnemonic_.c_str(), form);6005}60066007void Disassembler::Disassemble_Xd_XnSP_XmSP(const Instruction *instr) {6008if ((form_hash_ == Hash("subps_64s_dp_2src")) && (instr->GetRd() == 31)) {6009Format(instr, "cmpp", "'Xns, 'Xms");6010} else {6011const char *form = "'Xd, 'Xns, 'Xms";6012Format(instr, mnemonic_.c_str(), form);6013}6014}60156016void Disassembler::DisassembleMTEStoreTagPair(const Instruction *instr) {6017const char *form = "'Xt, 'Xt2, ['Xns";6018const char *suffix = NULL;6019switch (form_hash_) {6020case Hash("stgp_64_ldstpair_off"):6021suffix = ", #'s2115*16]";6022break;6023case Hash("stgp_64_ldstpair_post"):6024suffix = "], #'s2115*16";6025break;6026case Hash("stgp_64_ldstpair_pre"):6027suffix = ", #'s2115*16]!";6028break;6029default:6030mnemonic_ = "unimplemented";6031break;6032}60336034if (instr->GetImmLSPair() == 0) {6035suffix = "]";6036}60376038Format(instr, mnemonic_.c_str(), form, suffix);6039}60406041void Disassembler::DisassembleMTEStoreTag(const Instruction *instr) {6042const char *form = "'Xds, ['Xns";6043const char *suffix = NULL;6044switch (form_hash_) {6045case Hash("st2g_64soffset_ldsttags"):6046case Hash("stg_64soffset_ldsttags"):6047case Hash("stz2g_64soffset_ldsttags"):6048case Hash("stzg_64soffset_ldsttags"):6049suffix = ", #'s2012*16]";6050break;6051case Hash("st2g_64spost_ldsttags"):6052case Hash("stg_64spost_ldsttags"):6053case Hash("stz2g_64spost_ldsttags"):6054case Hash("stzg_64spost_ldsttags"):6055suffix = "], #'s2012*16";6056break;6057case Hash("st2g_64spre_ldsttags"):6058case Hash("stg_64spre_ldsttags"):6059case Hash("stz2g_64spre_ldsttags"):6060case Hash("stzg_64spre_ldsttags"):6061suffix = ", #'s2012*16]!";6062break;6063default:6064mnemonic_ = "unimplemented";6065break;6066}60676068if (instr->GetImmLS() == 0) {6069suffix = "]";6070}60716072Format(instr, mnemonic_.c_str(), form, suffix);6073}60746075void Disassembler::DisassembleMTELoadTag(const Instruction *instr) {6076const char *form =6077(instr->GetImmLS() == 0) ? "'Xt, ['Xns]" : "'Xt, ['Xns, #'s2012*16]";6078Format(instr, mnemonic_.c_str(), form);6079}60806081void Disassembler::DisassembleCpy(const Instruction *instr) {6082const char *form = "['Xd]!, ['Xs]!, 'Xn!";60836084int d = instr->GetRd();6085int n = instr->GetRn();6086int s = instr->GetRs();60876088// Aliased registers and sp/zr are disallowed.6089if ((d == n) || (d == s) || (n == s) || (d == 31) || (n == 31) || (s == 31)) {6090form = NULL;6091}60926093// Bits 31 and 30 must be zero.6094if (instr->ExtractBits(31, 30)) {6095form = NULL;6096}60976098Format(instr, mnemonic_.c_str(), form);6099}61006101void Disassembler::DisassembleSet(const Instruction *instr) {6102const char *form = "['Xd]!, 'Xn!, 'Xs";61036104int d = instr->GetRd();6105int n = instr->GetRn();6106int s = instr->GetRs();61076108// Aliased registers are disallowed. Only Xs may be xzr.6109if ((d == n) || (d == s) || (n == s) || (d == 31) || (n == 31)) {6110form = NULL;6111}61126113// Bits 31 and 30 must be zero.6114if (instr->ExtractBits(31, 30)) {6115form = NULL;6116}61176118Format(instr, mnemonic_.c_str(), form);6119}61206121void Disassembler::ProcessOutput(const Instruction * /*instr*/) {6122// The base disasm does nothing more than disassembling into a buffer.6123}612461256126void Disassembler::AppendRegisterNameToOutput(const Instruction *instr,6127const CPURegister ®) {6128USE(instr);6129VIXL_ASSERT(reg.IsValid());6130char reg_char;61316132if (reg.IsRegister()) {6133reg_char = reg.Is64Bits() ? 'x' : 'w';6134} else {6135VIXL_ASSERT(reg.IsVRegister());6136switch (reg.GetSizeInBits()) {6137case kBRegSize:6138reg_char = 'b';6139break;6140case kHRegSize:6141reg_char = 'h';6142break;6143case kSRegSize:6144reg_char = 's';6145break;6146case kDRegSize:6147reg_char = 'd';6148break;6149default:6150VIXL_ASSERT(reg.Is128Bits());6151reg_char = 'q';6152}6153}61546155if (reg.IsVRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) {6156// A core or scalar/vector register: [wx]0 - 30, [bhsdq]0 - 31.6157AppendToOutput("%c%d", reg_char, reg.GetCode());6158} else if (reg.Aliases(sp)) {6159// Disassemble w31/x31 as stack pointer wsp/sp.6160AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp");6161} else {6162// Disassemble w31/x31 as zero register wzr/xzr.6163AppendToOutput("%czr", reg_char);6164}6165}616661676168void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction *instr,6169int64_t offset) {6170USE(instr);6171if (offset < 0) {6172// Cast to uint64_t so that INT64_MIN is handled in a well-defined way.6173uint64_t abs_offset = UnsignedNegate(static_cast<uint64_t>(offset));6174AppendToOutput("#-0x%" PRIx64, abs_offset);6175} else {6176AppendToOutput("#+0x%" PRIx64, offset);6177}6178}617961806181void Disassembler::AppendAddressToOutput(const Instruction *instr,6182const void *addr) {6183USE(instr);6184AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast<uintptr_t>(addr));6185}618661876188void Disassembler::AppendCodeAddressToOutput(const Instruction *instr,6189const void *addr) {6190AppendAddressToOutput(instr, addr);6191}619261936194void Disassembler::AppendDataAddressToOutput(const Instruction *instr,6195const void *addr) {6196AppendAddressToOutput(instr, addr);6197}619861996200void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction *instr,6201const void *addr) {6202USE(instr);6203int64_t rel_addr = CodeRelativeAddress(addr);6204if (rel_addr >= 0) {6205AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr);6206} else {6207AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr);6208}6209}621062116212void Disassembler::AppendCodeRelativeCodeAddressToOutput(6213const Instruction *instr, const void *addr) {6214AppendCodeRelativeAddressToOutput(instr, addr);6215}621662176218void Disassembler::AppendCodeRelativeDataAddressToOutput(6219const Instruction *instr, const void *addr) {6220AppendCodeRelativeAddressToOutput(instr, addr);6221}622262236224void Disassembler::MapCodeAddress(int64_t base_address,6225const Instruction *instr_address) {6226set_code_address_offset(base_address -6227reinterpret_cast<intptr_t>(instr_address));6228}6229int64_t Disassembler::CodeRelativeAddress(const void *addr) {6230return reinterpret_cast<intptr_t>(addr) + code_address_offset();6231}623262336234void Disassembler::Format(const Instruction *instr,6235const char *mnemonic,6236const char *format0,6237const char *format1) {6238if ((mnemonic == NULL) || (format0 == NULL)) {6239VisitUnallocated(instr);6240} else {6241ResetOutput();6242Substitute(instr, mnemonic);6243if (format0[0] != 0) { // Not a zero-length string.6244VIXL_ASSERT(buffer_pos_ < buffer_size_);6245buffer_[buffer_pos_++] = ' ';6246Substitute(instr, format0);6247// TODO: consider using a zero-length string here, too.6248if (format1 != NULL) {6249Substitute(instr, format1);6250}6251}6252VIXL_ASSERT(buffer_pos_ < buffer_size_);6253buffer_[buffer_pos_] = 0;6254ProcessOutput(instr);6255}6256}62576258void Disassembler::FormatWithDecodedMnemonic(const Instruction *instr,6259const char *format0,6260const char *format1) {6261Format(instr, mnemonic_.c_str(), format0, format1);6262}62636264void Disassembler::Substitute(const Instruction *instr, const char *string) {6265char chr = *string++;6266while (chr != '\0') {6267if (chr == '\'') {6268string += SubstituteField(instr, string);6269} else {6270VIXL_ASSERT(buffer_pos_ < buffer_size_);6271buffer_[buffer_pos_++] = chr;6272}6273chr = *string++;6274}6275}627662776278int Disassembler::SubstituteField(const Instruction *instr,6279const char *format) {6280switch (format[0]) {6281// NB. The remaining substitution prefix upper-case characters are: JU.6282case 'R': // Register. X or W, selected by sf (or alternative) bit.6283case 'F': // FP register. S or D, selected by type field.6284case 'V': // Vector register, V, vector format.6285case 'Z': // Scalable vector register.6286case 'W':6287case 'X':6288case 'B':6289case 'H':6290case 'S':6291case 'D':6292case 'Q':6293return SubstituteRegisterField(instr, format);6294case 'P':6295return SubstitutePredicateRegisterField(instr, format);6296case 'I':6297return SubstituteImmediateField(instr, format);6298case 'L':6299return SubstituteLiteralField(instr, format);6300case 'N':6301return SubstituteShiftField(instr, format);6302case 'C':6303return SubstituteConditionField(instr, format);6304case 'E':6305return SubstituteExtendField(instr, format);6306case 'A':6307return SubstitutePCRelAddressField(instr, format);6308case 'T':6309return SubstituteBranchTargetField(instr, format);6310case 'O':6311return SubstituteLSRegOffsetField(instr, format);6312case 'M':6313return SubstituteBarrierField(instr, format);6314case 'K':6315return SubstituteCrField(instr, format);6316case 'G':6317return SubstituteSysOpField(instr, format);6318case 'p':6319return SubstitutePrefetchField(instr, format);6320case 'u':6321case 's':6322return SubstituteIntField(instr, format);6323case 't':6324return SubstituteSVESize(instr, format);6325case '?':6326return SubstituteTernary(instr, format);6327default: {6328VIXL_UNREACHABLE();6329return 1;6330}6331}6332}63336334std::pair<unsigned, unsigned> Disassembler::GetRegNumForField(6335const Instruction *instr, char reg_prefix, const char *field) {6336unsigned reg_num = UINT_MAX;6337unsigned field_len = 1;63386339switch (field[0]) {6340case 'd':6341reg_num = instr->GetRd();6342break;6343case 'n':6344reg_num = instr->GetRn();6345break;6346case 'm':6347reg_num = instr->GetRm();6348break;6349case 'e':6350// This is register Rm, but using a 4-bit specifier. Used in NEON6351// by-element instructions.6352reg_num = instr->GetRmLow16();6353break;6354case 'f':6355// This is register Rm, but using an element size dependent number of bits6356// in the register specifier.6357reg_num =6358(instr->GetNEONSize() < 2) ? instr->GetRmLow16() : instr->GetRm();6359break;6360case 'a':6361reg_num = instr->GetRa();6362break;6363case 's':6364reg_num = instr->GetRs();6365break;6366case 't':6367reg_num = instr->GetRt();6368break;6369default:6370VIXL_UNREACHABLE();6371}63726373switch (field[1]) {6374case '2':6375case '3':6376case '4':6377if ((reg_prefix == 'V') || (reg_prefix == 'Z')) { // t2/3/4, n2/3/46378VIXL_ASSERT((field[0] == 't') || (field[0] == 'n'));6379reg_num = (reg_num + field[1] - '1') % 32;6380field_len++;6381} else {6382VIXL_ASSERT((field[0] == 't') && (field[1] == '2'));6383reg_num = instr->GetRt2();6384field_len++;6385}6386break;6387case '+': // Rt+, Rs+ (ie. Rt + 1, Rs + 1)6388VIXL_ASSERT((reg_prefix == 'W') || (reg_prefix == 'X'));6389VIXL_ASSERT((field[0] == 's') || (field[0] == 't'));6390reg_num++;6391field_len++;6392break;6393case 's': // Core registers that are (w)sp rather than zr.6394VIXL_ASSERT((reg_prefix == 'W') || (reg_prefix == 'X'));6395reg_num = (reg_num == kZeroRegCode) ? kSPRegInternalCode : reg_num;6396field_len++;6397break;6398}63996400VIXL_ASSERT(reg_num != UINT_MAX);6401return std::make_pair(reg_num, field_len);6402}64036404int Disassembler::SubstituteRegisterField(const Instruction *instr,6405const char *format) {6406unsigned field_len = 1; // Initially, count only the first character.64076408// The first character of the register format field, eg R, X, S, etc.6409char reg_prefix = format[0];64106411// Pointer to the character after the prefix. This may be one of the standard6412// symbols representing a register encoding, or a two digit bit position,6413// handled by the following code.6414const char *reg_field = &format[1];64156416if (reg_prefix == 'R') {6417bool is_x = instr->GetSixtyFourBits() == 1;6418if (strspn(reg_field, "0123456789") == 2) { // r20d, r31n, etc.6419// Core W or X registers where the type is determined by a specified bit6420// position, eg. 'R20d, 'R05n. This is like the 'Rd syntax, where bit 316421// is implicitly used to select between W and X.6422int bitpos = ((reg_field[0] - '0') * 10) + (reg_field[1] - '0');6423VIXL_ASSERT(bitpos <= 31);6424is_x = (instr->ExtractBit(bitpos) == 1);6425reg_field = &format[3];6426field_len += 2;6427}6428reg_prefix = is_x ? 'X' : 'W';6429}64306431std::pair<unsigned, unsigned> rn =6432GetRegNumForField(instr, reg_prefix, reg_field);6433unsigned reg_num = rn.first;6434field_len += rn.second;64356436if (reg_field[0] == 'm') {6437switch (reg_field[1]) {6438// Handle registers tagged with b (bytes), z (instruction), or6439// r (registers), used for address updates in NEON load/store6440// instructions.6441case 'r':6442case 'b':6443case 'z': {6444VIXL_ASSERT(reg_prefix == 'X');6445field_len = 3;6446char *eimm;6447int imm = static_cast<int>(strtol(®_field[2], &eimm, 10));6448field_len += static_cast<unsigned>(eimm - ®_field[2]);6449if (reg_num == 31) {6450switch (reg_field[1]) {6451case 'z':6452imm *= (1 << instr->GetNEONLSSize());6453break;6454case 'r':6455imm *= (instr->GetNEONQ() == 0) ? kDRegSizeInBytes6456: kQRegSizeInBytes;6457break;6458case 'b':6459break;6460}6461AppendToOutput("#%d", imm);6462return field_len;6463}6464break;6465}6466}6467}64686469CPURegister::RegisterType reg_type = CPURegister::kRegister;6470unsigned reg_size = kXRegSize;64716472if (reg_prefix == 'F') {6473switch (instr->GetFPType()) {6474case 3:6475reg_prefix = 'H';6476break;6477case 0:6478reg_prefix = 'S';6479break;6480default:6481reg_prefix = 'D';6482}6483}64846485switch (reg_prefix) {6486case 'W':6487reg_type = CPURegister::kRegister;6488reg_size = kWRegSize;6489break;6490case 'X':6491reg_type = CPURegister::kRegister;6492reg_size = kXRegSize;6493break;6494case 'B':6495reg_type = CPURegister::kVRegister;6496reg_size = kBRegSize;6497break;6498case 'H':6499reg_type = CPURegister::kVRegister;6500reg_size = kHRegSize;6501break;6502case 'S':6503reg_type = CPURegister::kVRegister;6504reg_size = kSRegSize;6505break;6506case 'D':6507reg_type = CPURegister::kVRegister;6508reg_size = kDRegSize;6509break;6510case 'Q':6511reg_type = CPURegister::kVRegister;6512reg_size = kQRegSize;6513break;6514case 'V':6515if (reg_field[1] == 'v') {6516reg_type = CPURegister::kVRegister;6517reg_size = 1 << (instr->GetSVESize() + 3);6518field_len++;6519break;6520}6521AppendToOutput("v%d", reg_num);6522return field_len;6523case 'Z':6524AppendToOutput("z%d", reg_num);6525return field_len;6526default:6527VIXL_UNREACHABLE();6528}65296530AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type));65316532return field_len;6533}65346535int Disassembler::SubstitutePredicateRegisterField(const Instruction *instr,6536const char *format) {6537VIXL_ASSERT(format[0] == 'P');6538switch (format[1]) {6539// This field only supports P register that are always encoded in the same6540// position.6541case 'd':6542case 't':6543AppendToOutput("p%u", instr->GetPt());6544break;6545case 'n':6546AppendToOutput("p%u", instr->GetPn());6547break;6548case 'm':6549AppendToOutput("p%u", instr->GetPm());6550break;6551case 'g':6552VIXL_ASSERT(format[2] == 'l');6553AppendToOutput("p%u", instr->GetPgLow8());6554return 3;6555default:6556VIXL_UNREACHABLE();6557}6558return 2;6559}65606561int Disassembler::SubstituteImmediateField(const Instruction *instr,6562const char *format) {6563VIXL_ASSERT(format[0] == 'I');65646565switch (format[1]) {6566case 'M': { // IMoveImm, IMoveNeg or IMoveLSL.6567if (format[5] == 'L') {6568AppendToOutput("#0x%" PRIx32, instr->GetImmMoveWide());6569if (instr->GetShiftMoveWide() > 0) {6570AppendToOutput(", lsl #%" PRId32, 16 * instr->GetShiftMoveWide());6571}6572} else {6573VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N'));6574uint64_t imm = static_cast<uint64_t>(instr->GetImmMoveWide())6575<< (16 * instr->GetShiftMoveWide());6576if (format[5] == 'N') imm = ~imm;6577if (!instr->GetSixtyFourBits()) imm &= UINT64_C(0xffffffff);6578AppendToOutput("#0x%" PRIx64, imm);6579}6580return 8;6581}6582case 'L': {6583switch (format[2]) {6584case 'L': { // ILLiteral - Immediate Load Literal.6585AppendToOutput("pc%+" PRId32,6586instr->GetImmLLiteral() *6587static_cast<int>(kLiteralEntrySize));6588return 9;6589}6590case 'S': { // ILS - Immediate Load/Store.6591// ILSi - As above, but an index field which must not be6592// omitted even if it is zero.6593bool is_index = format[3] == 'i';6594if (is_index || (instr->GetImmLS() != 0)) {6595AppendToOutput(", #%" PRId32, instr->GetImmLS());6596}6597return is_index ? 4 : 3;6598}6599case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.6600// ILPxi - As above, but an index field which must not be6601// omitted even if it is zero.6602VIXL_ASSERT((format[3] >= '0') && (format[3] <= '9'));6603bool is_index = format[4] == 'i';6604if (is_index || (instr->GetImmLSPair() != 0)) {6605// format[3] is the scale value. Convert to a number.6606int scale = 1 << (format[3] - '0');6607AppendToOutput(", #%" PRId32, instr->GetImmLSPair() * scale);6608}6609return is_index ? 5 : 4;6610}6611case 'U': { // ILU - Immediate Load/Store Unsigned.6612if (instr->GetImmLSUnsigned() != 0) {6613int shift = instr->GetSizeLS();6614AppendToOutput(", #%" PRId32, instr->GetImmLSUnsigned() << shift);6615}6616return 3;6617}6618case 'A': { // ILA - Immediate Load with pointer authentication.6619if (instr->GetImmLSPAC() != 0) {6620AppendToOutput(", #%" PRId32, instr->GetImmLSPAC());6621}6622return 3;6623}6624default: {6625VIXL_UNIMPLEMENTED();6626return 0;6627}6628}6629}6630case 'C': { // ICondB - Immediate Conditional Branch.6631int64_t offset = instr->GetImmCondBranch() << 2;6632AppendPCRelativeOffsetToOutput(instr, offset);6633return 6;6634}6635case 'A': { // IAddSub.6636int64_t imm = instr->GetImmAddSub() << (12 * instr->GetImmAddSubShift());6637AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);6638return 7;6639}6640case 'F': { // IFP, IFPNeon, IFPSve or IFPFBits.6641int imm8 = 0;6642size_t len = strlen("IFP");6643switch (format[3]) {6644case 'F':6645VIXL_ASSERT(strncmp(format, "IFPFBits", strlen("IFPFBits")) == 0);6646AppendToOutput("#%" PRId32, 64 - instr->GetFPScale());6647return static_cast<int>(strlen("IFPFBits"));6648case 'N':6649VIXL_ASSERT(strncmp(format, "IFPNeon", strlen("IFPNeon")) == 0);6650imm8 = instr->GetImmNEONabcdefgh();6651len += strlen("Neon");6652break;6653case 'S':6654VIXL_ASSERT(strncmp(format, "IFPSve", strlen("IFPSve")) == 0);6655imm8 = instr->ExtractBits(12, 5);6656len += strlen("Sve");6657break;6658default:6659VIXL_ASSERT(strncmp(format, "IFP", strlen("IFP")) == 0);6660imm8 = instr->GetImmFP();6661break;6662}6663AppendToOutput("#0x%" PRIx32 " (%.4f)",6664imm8,6665Instruction::Imm8ToFP32(imm8));6666return static_cast<int>(len);6667}6668case 'H': { // IH - ImmHint6669AppendToOutput("#%" PRId32, instr->GetImmHint());6670return 2;6671}6672case 'T': { // ITri - Immediate Triangular Encoded.6673if (format[4] == 'S') {6674VIXL_ASSERT((format[5] == 'v') && (format[6] == 'e'));6675switch (format[7]) {6676case 'l':6677// SVE logical immediate encoding.6678AppendToOutput("#0x%" PRIx64, instr->GetSVEImmLogical());6679return 8;6680case 'p': {6681// SVE predicated shift immediate encoding, lsl.6682std::pair<int, int> shift_and_lane_size =6683instr->GetSVEImmShiftAndLaneSizeLog2(6684/* is_predicated = */ true);6685int lane_bits = 8 << shift_and_lane_size.second;6686AppendToOutput("#%" PRId32, lane_bits - shift_and_lane_size.first);6687return 8;6688}6689case 'q': {6690// SVE predicated shift immediate encoding, asr and lsr.6691std::pair<int, int> shift_and_lane_size =6692instr->GetSVEImmShiftAndLaneSizeLog2(6693/* is_predicated = */ true);6694AppendToOutput("#%" PRId32, shift_and_lane_size.first);6695return 8;6696}6697case 'r': {6698// SVE unpredicated shift immediate encoding, left shifts.6699std::pair<int, int> shift_and_lane_size =6700instr->GetSVEImmShiftAndLaneSizeLog2(6701/* is_predicated = */ false);6702int lane_bits = 8 << shift_and_lane_size.second;6703AppendToOutput("#%" PRId32, lane_bits - shift_and_lane_size.first);6704return 8;6705}6706case 's': {6707// SVE unpredicated shift immediate encoding, right shifts.6708std::pair<int, int> shift_and_lane_size =6709instr->GetSVEImmShiftAndLaneSizeLog2(6710/* is_predicated = */ false);6711AppendToOutput("#%" PRId32, shift_and_lane_size.first);6712return 8;6713}6714default:6715VIXL_UNREACHABLE();6716return 0;6717}6718} else {6719AppendToOutput("#0x%" PRIx64, instr->GetImmLogical());6720return 4;6721}6722}6723case 'N': { // INzcv.6724int nzcv = (instr->GetNzcv() << Flags_offset);6725AppendToOutput("#%c%c%c%c",6726((nzcv & NFlag) == 0) ? 'n' : 'N',6727((nzcv & ZFlag) == 0) ? 'z' : 'Z',6728((nzcv & CFlag) == 0) ? 'c' : 'C',6729((nzcv & VFlag) == 0) ? 'v' : 'V');6730return 5;6731}6732case 'P': { // IP - Conditional compare.6733AppendToOutput("#%" PRId32, instr->GetImmCondCmp());6734return 2;6735}6736case 'B': { // Bitfields.6737return SubstituteBitfieldImmediateField(instr, format);6738}6739case 'E': { // IExtract.6740AppendToOutput("#%" PRId32, instr->GetImmS());6741return 8;6742}6743case 't': { // It - Test and branch bit.6744AppendToOutput("#%" PRId32,6745(instr->GetImmTestBranchBit5() << 5) |6746instr->GetImmTestBranchBit40());6747return 2;6748}6749case 'S': { // ISveSvl - SVE 'mul vl' immediate for structured ld/st.6750VIXL_ASSERT(strncmp(format, "ISveSvl", 7) == 0);6751int imm = instr->ExtractSignedBits(19, 16);6752if (imm != 0) {6753int reg_count = instr->ExtractBits(22, 21) + 1;6754AppendToOutput(", #%d, mul vl", imm * reg_count);6755}6756return 7;6757}6758case 's': { // Is - Shift (immediate).6759switch (format[2]) {6760case 'R': { // IsR - right shifts.6761int shift = 16 << HighestSetBitPosition(instr->GetImmNEONImmh());6762shift -= instr->GetImmNEONImmhImmb();6763AppendToOutput("#%d", shift);6764return 3;6765}6766case 'L': { // IsL - left shifts.6767int shift = instr->GetImmNEONImmhImmb();6768shift -= 8 << HighestSetBitPosition(instr->GetImmNEONImmh());6769AppendToOutput("#%d", shift);6770return 3;6771}6772default: {6773VIXL_UNIMPLEMENTED();6774return 0;6775}6776}6777}6778case 'D': { // IDebug - HLT and BRK instructions.6779AppendToOutput("#0x%" PRIx32, instr->GetImmException());6780return 6;6781}6782case 'U': { // IUdf - UDF immediate.6783AppendToOutput("#0x%" PRIx32, instr->GetImmUdf());6784return 4;6785}6786case 'V': { // Immediate Vector.6787switch (format[2]) {6788case 'E': { // IVExtract.6789AppendToOutput("#%" PRId32, instr->GetImmNEONExt());6790return 9;6791}6792case 'B': { // IVByElemIndex.6793int ret = static_cast<int>(strlen("IVByElemIndex"));6794uint32_t vm_index = instr->GetNEONH() << 2;6795vm_index |= instr->GetNEONL() << 1;6796vm_index |= instr->GetNEONM();67976798static const char *format_rot = "IVByElemIndexRot";6799static const char *format_fhm = "IVByElemIndexFHM";6800if (strncmp(format, format_rot, strlen(format_rot)) == 0) {6801// FCMLA uses 'H' bit index when SIZE is 2, else H:L6802VIXL_ASSERT((instr->GetNEONSize() == 1) ||6803(instr->GetNEONSize() == 2));6804vm_index >>= instr->GetNEONSize();6805ret = static_cast<int>(strlen(format_rot));6806} else if (strncmp(format, format_fhm, strlen(format_fhm)) == 0) {6807// Nothing to do - FMLAL and FMLSL use H:L:M.6808ret = static_cast<int>(strlen(format_fhm));6809} else {6810if (instr->GetNEONSize() == 2) {6811// S-sized elements use H:L.6812vm_index >>= 1;6813} else if (instr->GetNEONSize() == 3) {6814// D-sized elements use H.6815vm_index >>= 2;6816}6817}6818AppendToOutput("%d", vm_index);6819return ret;6820}6821case 'I': { // INS element.6822if (strncmp(format, "IVInsIndex", strlen("IVInsIndex")) == 0) {6823unsigned rd_index, rn_index;6824unsigned imm5 = instr->GetImmNEON5();6825unsigned imm4 = instr->GetImmNEON4();6826int tz = CountTrailingZeros(imm5, 32);6827if (tz <= 3) { // Defined for tz = 0 to 3 only.6828rd_index = imm5 >> (tz + 1);6829rn_index = imm4 >> tz;6830if (strncmp(format, "IVInsIndex1", strlen("IVInsIndex1")) == 0) {6831AppendToOutput("%d", rd_index);6832return static_cast<int>(strlen("IVInsIndex1"));6833} else if (strncmp(format,6834"IVInsIndex2",6835strlen("IVInsIndex2")) == 0) {6836AppendToOutput("%d", rn_index);6837return static_cast<int>(strlen("IVInsIndex2"));6838}6839}6840return 0;6841} else if (strncmp(format,6842"IVInsSVEIndex",6843strlen("IVInsSVEIndex")) == 0) {6844std::pair<int, int> index_and_lane_size =6845instr->GetSVEPermuteIndexAndLaneSizeLog2();6846AppendToOutput("%d", index_and_lane_size.first);6847return static_cast<int>(strlen("IVInsSVEIndex"));6848}6849VIXL_FALLTHROUGH();6850}6851case 'L': { // IVLSLane[0123] - suffix indicates access size shift.6852AppendToOutput("%d", instr->GetNEONLSIndex(format[8] - '0'));6853return 9;6854}6855case 'M': { // Modified Immediate cases.6856if (strncmp(format, "IVMIImm8", strlen("IVMIImm8")) == 0) {6857uint64_t imm8 = instr->GetImmNEONabcdefgh();6858AppendToOutput("#0x%" PRIx64, imm8);6859return static_cast<int>(strlen("IVMIImm8"));6860} else if (strncmp(format, "IVMIImm", strlen("IVMIImm")) == 0) {6861uint64_t imm8 = instr->GetImmNEONabcdefgh();6862uint64_t imm = 0;6863for (int i = 0; i < 8; ++i) {6864if (imm8 & (UINT64_C(1) << i)) {6865imm |= (UINT64_C(0xff) << (8 * i));6866}6867}6868AppendToOutput("#0x%" PRIx64, imm);6869return static_cast<int>(strlen("IVMIImm"));6870} else if (strncmp(format,6871"IVMIShiftAmt1",6872strlen("IVMIShiftAmt1")) == 0) {6873int cmode = instr->GetNEONCmode();6874int shift_amount = 8 * ((cmode >> 1) & 3);6875AppendToOutput("#%d", shift_amount);6876return static_cast<int>(strlen("IVMIShiftAmt1"));6877} else if (strncmp(format,6878"IVMIShiftAmt2",6879strlen("IVMIShiftAmt2")) == 0) {6880int cmode = instr->GetNEONCmode();6881int shift_amount = 8 << (cmode & 1);6882AppendToOutput("#%d", shift_amount);6883return static_cast<int>(strlen("IVMIShiftAmt2"));6884} else {6885VIXL_UNIMPLEMENTED();6886return 0;6887}6888}6889default: {6890VIXL_UNIMPLEMENTED();6891return 0;6892}6893}6894}6895case 'X': { // IX - CLREX instruction.6896AppendToOutput("#0x%" PRIx32, instr->GetCRm());6897return 2;6898}6899case 'Y': { // IY - system register immediate.6900switch (instr->GetImmSystemRegister()) {6901case NZCV:6902AppendToOutput("nzcv");6903break;6904case FPCR:6905AppendToOutput("fpcr");6906break;6907case RNDR:6908AppendToOutput("rndr");6909break;6910case RNDRRS:6911AppendToOutput("rndrrs");6912break;6913default:6914AppendToOutput("S%d_%d_c%d_c%d_%d",6915instr->GetSysOp0(),6916instr->GetSysOp1(),6917instr->GetCRn(),6918instr->GetCRm(),6919instr->GetSysOp2());6920break;6921}6922return 2;6923}6924case 'R': { // IR - Rotate right into flags.6925switch (format[2]) {6926case 'r': { // IRr - Rotate amount.6927AppendToOutput("#%d", instr->GetImmRMIFRotation());6928return 3;6929}6930default: {6931VIXL_UNIMPLEMENTED();6932return 0;6933}6934}6935}6936case 'p': { // Ipc - SVE predicate constraint specifier.6937VIXL_ASSERT(format[2] == 'c');6938unsigned pattern = instr->GetImmSVEPredicateConstraint();6939switch (pattern) {6940// VL1-VL8 are encoded directly.6941case SVE_VL1:6942case SVE_VL2:6943case SVE_VL3:6944case SVE_VL4:6945case SVE_VL5:6946case SVE_VL6:6947case SVE_VL7:6948case SVE_VL8:6949AppendToOutput("vl%u", pattern);6950break;6951// VL16-VL256 are encoded as log2(N) + c.6952case SVE_VL16:6953case SVE_VL32:6954case SVE_VL64:6955case SVE_VL128:6956case SVE_VL256:6957AppendToOutput("vl%u", 16 << (pattern - SVE_VL16));6958break;6959// Special cases.6960case SVE_POW2:6961AppendToOutput("pow2");6962break;6963case SVE_MUL4:6964AppendToOutput("mul4");6965break;6966case SVE_MUL3:6967AppendToOutput("mul3");6968break;6969case SVE_ALL:6970AppendToOutput("all");6971break;6972default:6973AppendToOutput("#0x%x", pattern);6974break;6975}6976return 3;6977}6978default: {6979VIXL_UNIMPLEMENTED();6980return 0;6981}6982}6983}698469856986int Disassembler::SubstituteBitfieldImmediateField(const Instruction *instr,6987const char *format) {6988VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));6989unsigned r = instr->GetImmR();6990unsigned s = instr->GetImmS();69916992switch (format[2]) {6993case 'r': { // IBr.6994AppendToOutput("#%d", r);6995return 3;6996}6997case 's': { // IBs+1 or IBs-r+1.6998if (format[3] == '+') {6999AppendToOutput("#%d", s + 1);7000return 5;7001} else {7002VIXL_ASSERT(format[3] == '-');7003AppendToOutput("#%d", s - r + 1);7004return 7;7005}7006}7007case 'Z': { // IBZ-r.7008VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));7009unsigned reg_size =7010(instr->GetSixtyFourBits() == 1) ? kXRegSize : kWRegSize;7011AppendToOutput("#%d", reg_size - r);7012return 5;7013}7014default: {7015VIXL_UNREACHABLE();7016return 0;7017}7018}7019}702070217022int Disassembler::SubstituteLiteralField(const Instruction *instr,7023const char *format) {7024VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);7025USE(format);70267027const void *address = instr->GetLiteralAddress<const void *>();7028switch (instr->Mask(LoadLiteralMask)) {7029case LDR_w_lit:7030case LDR_x_lit:7031case LDRSW_x_lit:7032case LDR_s_lit:7033case LDR_d_lit:7034case LDR_q_lit:7035AppendCodeRelativeDataAddressToOutput(instr, address);7036break;7037case PRFM_lit: {7038// Use the prefetch hint to decide how to print the address.7039switch (instr->GetPrefetchHint()) {7040case 0x0: // PLD: prefetch for load.7041case 0x2: // PST: prepare for store.7042AppendCodeRelativeDataAddressToOutput(instr, address);7043break;7044case 0x1: // PLI: preload instructions.7045AppendCodeRelativeCodeAddressToOutput(instr, address);7046break;7047case 0x3: // Unallocated hint.7048AppendCodeRelativeAddressToOutput(instr, address);7049break;7050}7051break;7052}7053default:7054VIXL_UNREACHABLE();7055}70567057return 6;7058}705970607061int Disassembler::SubstituteShiftField(const Instruction *instr,7062const char *format) {7063VIXL_ASSERT(format[0] == 'N');7064VIXL_ASSERT(instr->GetShiftDP() <= 0x3);70657066switch (format[1]) {7067case 'D': { // NDP.7068VIXL_ASSERT(instr->GetShiftDP() != ROR);7069VIXL_FALLTHROUGH();7070}7071case 'L': { // NLo.7072if (instr->GetImmDPShift() != 0) {7073const char *shift_type[] = {"lsl", "lsr", "asr", "ror"};7074AppendToOutput(", %s #%" PRId32,7075shift_type[instr->GetShiftDP()],7076instr->GetImmDPShift());7077}7078return 3;7079}7080case 'S': { // NSveS (SVE structured load/store indexing shift).7081VIXL_ASSERT(strncmp(format, "NSveS", 5) == 0);7082int msz = instr->ExtractBits(24, 23);7083if (msz > 0) {7084AppendToOutput(", lsl #%d", msz);7085}7086return 5;7087}7088default:7089VIXL_UNIMPLEMENTED();7090return 0;7091}7092}709370947095int Disassembler::SubstituteConditionField(const Instruction *instr,7096const char *format) {7097VIXL_ASSERT(format[0] == 'C');7098const char *condition_code[] = {"eq",7099"ne",7100"hs",7101"lo",7102"mi",7103"pl",7104"vs",7105"vc",7106"hi",7107"ls",7108"ge",7109"lt",7110"gt",7111"le",7112"al",7113"nv"};7114int cond;7115switch (format[1]) {7116case 'B':7117cond = instr->GetConditionBranch();7118break;7119case 'I': {7120cond = InvertCondition(static_cast<Condition>(instr->GetCondition()));7121break;7122}7123default:7124cond = instr->GetCondition();7125}7126AppendToOutput("%s", condition_code[cond]);7127return 4;7128}712971307131int Disassembler::SubstitutePCRelAddressField(const Instruction *instr,7132const char *format) {7133VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`.7134(strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.71357136int64_t offset = instr->GetImmPCRel();71377138// Compute the target address based on the effective address (after applying7139// code_address_offset). This is required for correct behaviour of adrp.7140const Instruction *base = instr + code_address_offset();7141if (format[9] == 'P') {7142offset *= kPageSize;7143base = AlignDown(base, kPageSize);7144}7145// Strip code_address_offset before printing, so we can use the7146// semantically-correct AppendCodeRelativeAddressToOutput.7147const void *target =7148reinterpret_cast<const void *>(base + offset - code_address_offset());71497150AppendPCRelativeOffsetToOutput(instr, offset);7151AppendToOutput(" ");7152AppendCodeRelativeAddressToOutput(instr, target);7153return 13;7154}715571567157int Disassembler::SubstituteBranchTargetField(const Instruction *instr,7158const char *format) {7159VIXL_ASSERT(strncmp(format, "TImm", 4) == 0);71607161int64_t offset = 0;7162switch (format[5]) {7163// BImmUncn - unconditional branch immediate.7164case 'n':7165offset = instr->GetImmUncondBranch();7166break;7167// BImmCond - conditional branch immediate.7168case 'o':7169offset = instr->GetImmCondBranch();7170break;7171// BImmCmpa - compare and branch immediate.7172case 'm':7173offset = instr->GetImmCmpBranch();7174break;7175// BImmTest - test and branch immediate.7176case 'e':7177offset = instr->GetImmTestBranch();7178break;7179default:7180VIXL_UNIMPLEMENTED();7181}7182offset *= static_cast<int>(kInstructionSize);7183const void *target_address = reinterpret_cast<const void *>(instr + offset);7184VIXL_STATIC_ASSERT(sizeof(*instr) == 1);71857186AppendPCRelativeOffsetToOutput(instr, offset);7187AppendToOutput(" ");7188AppendCodeRelativeCodeAddressToOutput(instr, target_address);71897190return 8;7191}719271937194int Disassembler::SubstituteExtendField(const Instruction *instr,7195const char *format) {7196VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);7197VIXL_ASSERT(instr->GetExtendMode() <= 7);7198USE(format);71997200const char *extend_mode[] =7201{"uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx"};72027203// If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit7204// registers becomes lsl.7205if (((instr->GetRd() == kZeroRegCode) || (instr->GetRn() == kZeroRegCode)) &&7206(((instr->GetExtendMode() == UXTW) && (instr->GetSixtyFourBits() == 0)) ||7207(instr->GetExtendMode() == UXTX))) {7208if (instr->GetImmExtendShift() > 0) {7209AppendToOutput(", lsl #%" PRId32, instr->GetImmExtendShift());7210}7211} else {7212AppendToOutput(", %s", extend_mode[instr->GetExtendMode()]);7213if (instr->GetImmExtendShift() > 0) {7214AppendToOutput(" #%" PRId32, instr->GetImmExtendShift());7215}7216}7217return 3;7218}721972207221int Disassembler::SubstituteLSRegOffsetField(const Instruction *instr,7222const char *format) {7223VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);7224const char *extend_mode[] = {"undefined",7225"undefined",7226"uxtw",7227"lsl",7228"undefined",7229"undefined",7230"sxtw",7231"sxtx"};7232USE(format);72337234unsigned shift = instr->GetImmShiftLS();7235Extend ext = static_cast<Extend>(instr->GetExtendMode());7236char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';72377238unsigned rm = instr->GetRm();7239if (rm == kZeroRegCode) {7240AppendToOutput("%czr", reg_type);7241} else {7242AppendToOutput("%c%d", reg_type, rm);7243}72447245// Extend mode UXTX is an alias for shift mode LSL here.7246if (!((ext == UXTX) && (shift == 0))) {7247AppendToOutput(", %s", extend_mode[ext]);7248if (shift != 0) {7249AppendToOutput(" #%d", instr->GetSizeLS());7250}7251}7252return 9;7253}725472557256int Disassembler::SubstitutePrefetchField(const Instruction *instr,7257const char *format) {7258VIXL_ASSERT(format[0] == 'p');7259USE(format);72607261bool is_sve =7262(strncmp(format, "prefSVEOp", strlen("prefSVEOp")) == 0) ? true : false;7263int placeholder_length = is_sve ? 9 : 6;7264static const char *stream_options[] = {"keep", "strm"};72657266auto get_hints = [](bool want_sve_hint) -> std::vector<std::string> {7267static const std::vector<std::string> sve_hints = {"ld", "st"};7268static const std::vector<std::string> core_hints = {"ld", "li", "st"};7269return (want_sve_hint) ? sve_hints : core_hints;7270};72717272std::vector<std::string> hints = get_hints(is_sve);7273unsigned hint =7274is_sve ? instr->GetSVEPrefetchHint() : instr->GetPrefetchHint();7275unsigned target = instr->GetPrefetchTarget() + 1;7276unsigned stream = instr->GetPrefetchStream();72777278if ((hint >= hints.size()) || (target > 3)) {7279// Unallocated prefetch operations.7280if (is_sve) {7281std::bitset<4> prefetch_mode(instr->GetSVEImmPrefetchOperation());7282AppendToOutput("#0b%s", prefetch_mode.to_string().c_str());7283} else {7284std::bitset<5> prefetch_mode(instr->GetImmPrefetchOperation());7285AppendToOutput("#0b%s", prefetch_mode.to_string().c_str());7286}7287} else {7288VIXL_ASSERT(stream < ArrayLength(stream_options));7289AppendToOutput("p%sl%d%s",7290hints[hint].c_str(),7291target,7292stream_options[stream]);7293}7294return placeholder_length;7295}72967297int Disassembler::SubstituteBarrierField(const Instruction *instr,7298const char *format) {7299VIXL_ASSERT(format[0] == 'M');7300USE(format);73017302static const char *options[4][4] = {{"sy (0b0000)", "oshld", "oshst", "osh"},7303{"sy (0b0100)", "nshld", "nshst", "nsh"},7304{"sy (0b1000)", "ishld", "ishst", "ish"},7305{"sy (0b1100)", "ld", "st", "sy"}};7306int domain = instr->GetImmBarrierDomain();7307int type = instr->GetImmBarrierType();73087309AppendToOutput("%s", options[domain][type]);7310return 1;7311}73127313int Disassembler::SubstituteSysOpField(const Instruction *instr,7314const char *format) {7315VIXL_ASSERT(format[0] == 'G');7316int op = -1;7317switch (format[1]) {7318case '1':7319op = instr->GetSysOp1();7320break;7321case '2':7322op = instr->GetSysOp2();7323break;7324default:7325VIXL_UNREACHABLE();7326}7327AppendToOutput("#%d", op);7328return 2;7329}73307331int Disassembler::SubstituteCrField(const Instruction *instr,7332const char *format) {7333VIXL_ASSERT(format[0] == 'K');7334int cr = -1;7335switch (format[1]) {7336case 'n':7337cr = instr->GetCRn();7338break;7339case 'm':7340cr = instr->GetCRm();7341break;7342default:7343VIXL_UNREACHABLE();7344}7345AppendToOutput("C%d", cr);7346return 2;7347}73487349int Disassembler::SubstituteIntField(const Instruction *instr,7350const char *format) {7351VIXL_ASSERT((format[0] == 'u') || (format[0] == 's'));73527353// A generic signed or unsigned int field uses a placeholder of the form7354// 'sAABB and 'uAABB respectively where AA and BB are two digit bit positions7355// between 00 and 31, and AA >= BB. The placeholder is substituted with the7356// decimal integer represented by the bits in the instruction between7357// positions AA and BB inclusive.7358//7359// In addition, split fields can be represented using 'sAABB:CCDD, where CCDD7360// become the least-significant bits of the result, and bit AA is the sign bit7361// (if 's is used).7362int32_t bits = 0;7363int width = 0;7364const char *c = format;7365do {7366c++; // Skip the 'u', 's' or ':'.7367VIXL_ASSERT(strspn(c, "0123456789") == 4);7368int msb = ((c[0] - '0') * 10) + (c[1] - '0');7369int lsb = ((c[2] - '0') * 10) + (c[3] - '0');7370c += 4; // Skip the characters we just read.7371int chunk_width = msb - lsb + 1;7372VIXL_ASSERT((chunk_width > 0) && (chunk_width < 32));7373bits = (bits << chunk_width) | (instr->ExtractBits(msb, lsb));7374width += chunk_width;7375} while (*c == ':');7376VIXL_ASSERT(IsUintN(width, bits));73777378if (format[0] == 's') {7379bits = ExtractSignedBitfield32(width - 1, 0, bits);7380}73817382if (*c == '+') {7383// A "+n" trailing the format specifier indicates the extracted value should7384// be incremented by n. This is for cases where the encoding is zero-based,7385// but range of values is not, eg. values [1, 16] encoded as [0, 15]7386char *new_c;7387uint64_t value = strtoul(c + 1, &new_c, 10);7388c = new_c;7389VIXL_ASSERT(IsInt32(value));7390bits = static_cast<int32_t>(bits + value);7391} else if (*c == '*') {7392// Similarly, a "*n" trailing the format specifier indicates the extracted7393// value should be multiplied by n. This is for cases where the encoded7394// immediate is scaled, for example by access size.7395char *new_c;7396uint64_t value = strtoul(c + 1, &new_c, 10);7397c = new_c;7398VIXL_ASSERT(IsInt32(value));7399bits = static_cast<int32_t>(bits * value);7400}74017402AppendToOutput("%d", bits);74037404return static_cast<int>(c - format);7405}74067407int Disassembler::SubstituteSVESize(const Instruction *instr,7408const char *format) {7409USE(format);7410VIXL_ASSERT(format[0] == 't');74117412static const char sizes[] = {'b', 'h', 's', 'd', 'q'};7413unsigned size_in_bytes_log2 = instr->GetSVESize();7414int placeholder_length = 1;7415switch (format[1]) {7416case 'f': // 'tf - FP size encoded in <18:17>7417placeholder_length++;7418size_in_bytes_log2 = instr->ExtractBits(18, 17);7419break;7420case 'l':7421placeholder_length++;7422if (format[2] == 's') {7423// 'tls: Loads and stores7424size_in_bytes_log2 = instr->ExtractBits(22, 21);7425placeholder_length++;7426if (format[3] == 's') {7427// Sign extension load.7428unsigned msize = instr->ExtractBits(24, 23);7429if (msize > size_in_bytes_log2) size_in_bytes_log2 ^= 0x3;7430placeholder_length++;7431}7432} else {7433// 'tl: Logical operations7434size_in_bytes_log2 = instr->GetSVEBitwiseImmLaneSizeInBytesLog2();7435}7436break;7437case 'm': // 'tmsz7438VIXL_ASSERT(strncmp(format, "tmsz", 4) == 0);7439placeholder_length += 3;7440size_in_bytes_log2 = instr->ExtractBits(24, 23);7441break;7442case 'i': { // 'ti: indices.7443std::pair<int, int> index_and_lane_size =7444instr->GetSVEPermuteIndexAndLaneSizeLog2();7445placeholder_length++;7446size_in_bytes_log2 = index_and_lane_size.second;7447break;7448}7449case 's':7450if (format[2] == 'z') {7451VIXL_ASSERT((format[3] == 'p') || (format[3] == 's') ||7452(format[3] == 'd'));7453bool is_predicated = (format[3] == 'p');7454std::pair<int, int> shift_and_lane_size =7455instr->GetSVEImmShiftAndLaneSizeLog2(is_predicated);7456size_in_bytes_log2 = shift_and_lane_size.second;7457if (format[3] == 'd') { // Double size lanes.7458size_in_bytes_log2++;7459}7460placeholder_length += 3; // skip "sz(p|s|d)"7461}7462break;7463case 'h':7464// Half size of the lane size field.7465size_in_bytes_log2 -= 1;7466placeholder_length++;7467break;7468case 'q':7469// Quarter size of the lane size field.7470size_in_bytes_log2 -= 2;7471placeholder_length++;7472break;7473default:7474break;7475}74767477VIXL_ASSERT(size_in_bytes_log2 < ArrayLength(sizes));7478AppendToOutput("%c", sizes[size_in_bytes_log2]);74797480return placeholder_length;7481}74827483int Disassembler::SubstituteTernary(const Instruction *instr,7484const char *format) {7485VIXL_ASSERT((format[0] == '?') && (format[3] == ':'));74867487// The ternary substitution of the format "'?bb:TF" is replaced by a single7488// character, either T or F, depending on the value of the bit at position7489// bb in the instruction. For example, "'?31:xw" is substituted with "x" if7490// bit 31 is true, and "w" otherwise.7491VIXL_ASSERT(strspn(&format[1], "0123456789") == 2);7492char *c;7493uint64_t value = strtoul(&format[1], &c, 10);7494VIXL_ASSERT(value < (kInstructionSize * kBitsPerByte));7495VIXL_ASSERT((*c == ':') && (strlen(c) >= 3)); // Minimum of ":TF"7496c++;7497AppendToOutput("%c", c[1 - instr->ExtractBit(static_cast<int>(value))]);7498return 6;7499}75007501void Disassembler::ResetOutput() {7502buffer_pos_ = 0;7503buffer_[buffer_pos_] = 0;7504}750575067507void Disassembler::AppendToOutput(const char *format, ...) {7508va_list args;7509va_start(args, format);7510buffer_pos_ += vsnprintf(&buffer_[buffer_pos_],7511buffer_size_ - buffer_pos_,7512format,7513args);7514va_end(args);7515}751675177518void PrintDisassembler::Disassemble(const Instruction *instr) {7519Decoder decoder;7520if (cpu_features_auditor_ != NULL) {7521decoder.AppendVisitor(cpu_features_auditor_);7522}7523decoder.AppendVisitor(this);7524decoder.Decode(instr);7525}75267527void PrintDisassembler::DisassembleBuffer(const Instruction *start,7528const Instruction *end) {7529Decoder decoder;7530if (cpu_features_auditor_ != NULL) {7531decoder.AppendVisitor(cpu_features_auditor_);7532}7533decoder.AppendVisitor(this);7534decoder.Decode(start, end);7535}75367537void PrintDisassembler::DisassembleBuffer(const Instruction *start,7538uint64_t size) {7539DisassembleBuffer(start, start + size);7540}754175427543void PrintDisassembler::ProcessOutput(const Instruction *instr) {7544int64_t address = CodeRelativeAddress(instr);75457546uint64_t abs_address;7547const char *sign;7548if (signed_addresses_) {7549if (address < 0) {7550sign = "-";7551abs_address = UnsignedNegate(static_cast<uint64_t>(address));7552} else {7553// Leave a leading space, to maintain alignment.7554sign = " ";7555abs_address = address;7556}7557} else {7558sign = "";7559abs_address = address;7560}75617562int bytes_printed = fprintf(stream_,7563"%s0x%016" PRIx64 " %08" PRIx32 "\t\t%s",7564sign,7565abs_address,7566instr->GetInstructionBits(),7567GetOutput());7568if (cpu_features_auditor_ != NULL) {7569CPUFeatures needs = cpu_features_auditor_->GetInstructionFeatures();7570needs.Remove(cpu_features_auditor_->GetAvailableFeatures());7571if (needs != CPUFeatures::None()) {7572// Try to align annotations. This value is arbitrary, but based on looking7573// good with most instructions. Note that, for historical reasons, the7574// disassembly itself is printed with tab characters, so bytes_printed is7575// _not_ equivalent to the number of occupied screen columns. However, the7576// prefix before the tabs is always the same length, so the annotation7577// indentation does not change from one line to the next.7578const int indent_to = 70;7579// Always allow some space between the instruction and the annotation.7580const int min_pad = 2;75817582int pad = std::max(min_pad, (indent_to - bytes_printed));7583fprintf(stream_, "%*s", pad, "");75847585std::stringstream features;7586features << needs;7587fprintf(stream_,7588"%s%s%s",7589cpu_features_prefix_,7590features.str().c_str(),7591cpu_features_suffix_);7592}7593}7594fprintf(stream_, "\n");7595}75967597} // namespace aarch647598} // namespace vixl759976007601