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