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
34 namespace vixl {
35 namespace aarch64 {
36
GetFormToVisitorFnMap()37 const 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
Disassembler()761 Disassembler::Disassembler() : allocator_(std::make_optional<AllocatorWrapper>()) {
762 #else
763 Disassembler::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
772 Disassembler::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
780 Disassembler::~Disassembler() {
781 if (own_buffer_) {
782 allocator_->Free(buffer_);
783 }
784 }
785
786 char *Disassembler::GetOutput() { return buffer_; }
787
788 void 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
825 void 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
868 void 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
911 void 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
951 void Disassembler::VisitRotateRightIntoFlags(const Instruction *instr) {
952 FormatWithDecodedMnemonic(instr, "'Xn, 'IRr, 'INzcv");
953 }
954
955
956 void Disassembler::VisitEvaluateIntoFlags(const Instruction *instr) {
957 FormatWithDecodedMnemonic(instr, "'Wn");
958 }
959
960
961 void 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
1009 bool 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
1037 void 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
1072 void Disassembler::VisitConditionalCompareRegister(const Instruction *instr) {
1073 FormatWithDecodedMnemonic(instr, "'Rn, 'Rm, 'INzcv, 'Cond");
1074 }
1075
1076
1077 void Disassembler::VisitConditionalCompareImmediate(const Instruction *instr) {
1078 FormatWithDecodedMnemonic(instr, "'Rn, 'IP, 'INzcv, 'Cond");
1079 }
1080
1081
1082 void 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
1138 void 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
1232 void 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
1254 void 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
1268 void 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
1277 void 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
1303 void Disassembler::VisitUnconditionalBranch(const Instruction *instr) {
1304 FormatWithDecodedMnemonic(instr, "'TImmUncn");
1305 }
1306
1307
1308 void 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
1339 void 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
1368 void 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
1446 void Disassembler::DisassembleMinMaxImm(const Instruction *instr) {
1447 const char *suffix = (instr->ExtractBit(18) == 0) ? "'s1710" : "'u1710";
1448 FormatWithDecodedMnemonic(instr, "'Rd, 'Rn, #", suffix);
1449 }
1450
1451 void Disassembler::VisitCompareBranch(const Instruction *instr) {
1452 FormatWithDecodedMnemonic(instr, "'Rt, 'TImmCmpa");
1453 }
1454
1455
1456 void 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
1465 void 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
1531 void 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
1547 void 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
1563 void 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
1581 void 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
1600 void 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
1618 void 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
1658 void 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
1697 void 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
1712 void 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
1727 void 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
1742 void 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
1817 void 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
1849 void 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
1861 void 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
1888 void 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
1903 void Disassembler::VisitFPConditionalCompare(const Instruction *instr) {
1904 FormatWithDecodedMnemonic(instr, "'Fn, 'Fm, 'INzcv, 'Cond");
1905 }
1906
1907
1908 void Disassembler::VisitFPConditionalSelect(const Instruction *instr) {
1909 FormatWithDecodedMnemonic(instr, "'Fd, 'Fn, 'Fm, 'Cond");
1910 }
1911
1912
1913 void 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
1939 void Disassembler::VisitFPDataProcessing2Source(const Instruction *instr) {
1940 FormatWithDecodedMnemonic(instr, "'Fd, 'Fn, 'Fm");
1941 }
1942
1943
1944 void Disassembler::VisitFPDataProcessing3Source(const Instruction *instr) {
1945 FormatWithDecodedMnemonic(instr, "'Fd, 'Fn, 'Fm, 'Fa");
1946 }
1947
1948
1949 void 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
1964 void 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
1996 void 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
2019 void Disassembler::DisassembleNoArgs(const Instruction *instr) {
2020 Format(instr, mnemonic_.c_str(), "");
2021 }
2022
2023 void 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
2115 void 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
2154 void Disassembler::VisitCrypto2RegSHA(const Instruction *instr) {
2155 VisitUnimplemented(instr);
2156 }
2157
2158
2159 void Disassembler::VisitCrypto3RegSHA(const Instruction *instr) {
2160 VisitUnimplemented(instr);
2161 }
2162
2163
2164 void Disassembler::VisitCryptoAES(const Instruction *instr) {
2165 VisitUnimplemented(instr);
2166 }
2167
2168 void 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
2179 void 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
2186 void 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
2193 void 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
2216 void 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
2223 void 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
2233 void 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
2258 void 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
2298 void 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
2314 void 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
2334 void Disassembler::DisassembleNEON3SameFHM(const Instruction *instr) {
2335 FormatWithDecodedMnemonic(instr, "'Vd.'?30:42s, 'Vn.'?30:42h, 'Vm.'?30:42h");
2336 }
2337
2338 void 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
2348 void 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
2372 void 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
2380 void 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
2412 void 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
2449 void 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
2458 void Disassembler::DisassembleNEONFP16AcrossLanes(const Instruction *instr) {
2459 FormatWithDecodedMnemonic(instr, "'Hd, 'Vn.'?30:84h");
2460 }
2461
2462 void 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
2488 void 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
2499 void 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
2510 void 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
2516 void 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
2525 void Disassembler::DisassembleNEONHalfFPMulByElement(const Instruction *instr) {
2526 FormatWithDecodedMnemonic(instr,
2527 "'Vd.'?30:84h, 'Vn.'?30:84h, "
2528 "'Ve.h['IVByElemIndex]");
2529 }
2530
2531 void Disassembler::DisassembleNEONFPMulByElementLong(const Instruction *instr) {
2532 FormatWithDecodedMnemonic(instr,
2533 "'Vd.'?30:42s, 'Vn.'?30:42h, "
2534 "'Ve.h['IVByElemIndexFHM]");
2535 }
2536
2537 void 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
2551 void 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
2611 void 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
2622 void 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
2719 void 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
2818 void 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
2984 void 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
3144 void 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
3194 void 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
3210 void 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
3232 void 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
3245 void 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
3262 void 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
3274 void 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
3281 void 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
3290 void 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
3313 void Disassembler::VisitNEONScalar3SameFP16(const Instruction *instr) {
3314 FormatWithDecodedMnemonic(instr, "'Hd, 'Hn, 'Hm");
3315 }
3316
3317 void Disassembler::VisitNEONScalar3SameExtra(const Instruction *instr) {
3318 USE(instr);
3319 // Nothing to do - handled by VisitNEONScalar3Same.
3320 VIXL_UNREACHABLE();
3321 }
3322
3323 void 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
3338 void 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
3348 void 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
3362 void 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
3377 void 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
3399 void 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
3419 void 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
3431 void 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
3458 void 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
3477 void 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
3499 void 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
3510 void 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
3518 void 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
3558 void Disassembler::VisitNEONPerm(const Instruction *instr) {
3559 NEONFormatDecoder nfd(instr);
3560 FormatWithDecodedMnemonic(instr, nfd.Substitute("'Vd.%s, 'Vn.%s, 'Vm.%s"));
3561 }
3562
3563 void Disassembler::Disassemble_Vd4S_Vn16B_Vm16B(const Instruction *instr) {
3564 FormatWithDecodedMnemonic(instr, "'Vd.4s, 'Vn.16b, 'Vm.16b");
3565 }
3566
3567 void Disassembler::
3568 VisitSVE32BitGatherLoadHalfwords_ScalarPlus32BitScaledOffsets(
3569 const Instruction *instr) {
3570 FormatWithDecodedMnemonic(instr,
3571 "{'Zt.s}, 'Pgl/z, ['Xns, 'Zm.s, '?22:suxtw #1]");
3572 }
3573
3574 void Disassembler::VisitSVE32BitGatherLoadWords_ScalarPlus32BitScaledOffsets(
3575 const Instruction *instr) {
3576 FormatWithDecodedMnemonic(instr,
3577 "{'Zt.s}, 'Pgl/z, ['Xns, 'Zm.s, '?22:suxtw #2]");
3578 }
3579
3580 void Disassembler::VisitSVE32BitGatherLoad_ScalarPlus32BitUnscaledOffsets(
3581 const Instruction *instr) {
3582 FormatWithDecodedMnemonic(instr,
3583 "{'Zt.s}, 'Pgl/z, ['Xns, 'Zm.s, '?22:suxtw]");
3584 }
3585
3586 void 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
3611 void 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
3642 void 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
3650 void Disassembler::VisitSVE32BitScatterStore_ScalarPlus32BitScaledOffsets(
3651 const Instruction *instr) {
3652 FormatWithDecodedMnemonic(instr,
3653 "{'Zt.s}, 'Pgl, ['Xns, 'Zm.s, '?14:suxtw #'u2423]");
3654 }
3655
3656 void Disassembler::VisitSVE32BitScatterStore_ScalarPlus32BitUnscaledOffsets(
3657 const Instruction *instr) {
3658 FormatWithDecodedMnemonic(instr, "{'Zt.s}, 'Pgl, ['Xns, 'Zm.s, '?14:suxtw]");
3659 }
3660
3661 void 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
3689 void Disassembler::VisitSVE64BitGatherLoad_ScalarPlus32BitUnpackedScaledOffsets(
3690 const Instruction *instr) {
3691 FormatWithDecodedMnemonic(instr,
3692 "{'Zt.d}, 'Pgl/z, ['Xns, 'Zm.d, '?22:suxtw "
3693 "#'u2423]");
3694 }
3695
3696 void Disassembler::VisitSVE64BitGatherLoad_ScalarPlus64BitScaledOffsets(
3697 const Instruction *instr) {
3698 FormatWithDecodedMnemonic(instr,
3699 "{'Zt.d}, 'Pgl/z, ['Xns, 'Zm.d, lsl #'u2423]");
3700 }
3701
3702 void Disassembler::VisitSVE64BitGatherLoad_ScalarPlus64BitUnscaledOffsets(
3703 const Instruction *instr) {
3704 FormatWithDecodedMnemonic(instr, "{'Zt.d}, 'Pgl/z, ['Xns, 'Zm.d]");
3705 }
3706
3707 void Disassembler::
3708 VisitSVE64BitGatherLoad_ScalarPlusUnpacked32BitUnscaledOffsets(
3709 const Instruction *instr) {
3710 FormatWithDecodedMnemonic(instr,
3711 "{'Zt.d}, 'Pgl/z, ['Xns, 'Zm.d, '?22:suxtw]");
3712 }
3713
3714 void 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
3736 void 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
3755 void 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
3775 void 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
3784 void Disassembler::VisitSVE64BitScatterStore_ScalarPlus64BitScaledOffsets(
3785 const Instruction *instr) {
3786 FormatWithDecodedMnemonic(instr, "{'Zt.d}, 'Pgl, ['Xns, 'Zm.d, lsl #'u2423]");
3787 }
3788
3789 void Disassembler::VisitSVE64BitScatterStore_ScalarPlus64BitUnscaledOffsets(
3790 const Instruction *instr) {
3791 FormatWithDecodedMnemonic(instr, "{'Zt.d}, 'Pgl, ['Xns, 'Zm.d]");
3792 }
3793
3794 void Disassembler::
3795 VisitSVE64BitScatterStore_ScalarPlusUnpacked32BitScaledOffsets(
3796 const Instruction *instr) {
3797 FormatWithDecodedMnemonic(instr,
3798 "{'Zt.d}, 'Pgl, ['Xns, 'Zm.d, '?14:suxtw #'u2423]");
3799 }
3800
3801 void Disassembler::
3802 VisitSVE64BitScatterStore_ScalarPlusUnpacked32BitUnscaledOffsets(
3803 const Instruction *instr) {
3804 FormatWithDecodedMnemonic(instr, "{'Zt.d}, 'Pgl, ['Xns, 'Zm.d, '?14:suxtw]");
3805 }
3806
3807 void 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
3831 void 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
3841 void Disassembler::VisitSVEBitwiseLogical_Predicated(const Instruction *instr) {
3842 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");
3843 }
3844
3845 void 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
3879 void Disassembler::VisitSVEBitwiseShiftByVector_Predicated(
3880 const Instruction *instr) {
3881 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");
3882 }
3883
3884 void 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
3893 static 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
3974 void 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
3994 void 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
4013 void 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
4033 void 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
4061 void 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
4084 void 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
4094 void Disassembler::VisitSVEConditionallyBroadcastElementToVector(
4095 const Instruction *instr) {
4096 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl, 'Zd.'t, 'Zn.'t");
4097 }
4098
4099 void 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
4109 void Disassembler::VisitSVEConditionallyExtractElementToSIMDFPScalar(
4110 const Instruction *instr) {
4111 FormatWithDecodedMnemonic(instr, "'t'u0400, 'Pgl, 't'u0400, 'Zn.'t");
4112 }
4113
4114 void Disassembler::VisitSVEConditionallyTerminateScalars(
4115 const Instruction *instr) {
4116 const char *form = (instr->ExtractBit(22) == 0) ? "'Wn, 'Wm" : "'Xn, 'Xm";
4117 FormatWithDecodedMnemonic(instr, form);
4118 }
4119
4120 void Disassembler::VisitSVEConstructivePrefix_Unpredicated(
4121 const Instruction *instr) {
4122 FormatWithDecodedMnemonic(instr, "'Zd, 'Zn");
4123 }
4124
4125 void 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
4162 void 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
4170 void 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
4189 void 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
4206 void 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
4226 void 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
4254 void 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
4262 void 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
4292 void 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
4302 void 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
4308 void 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
4326 void 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
4346 void 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
4365 void 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
4382 void 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
4391 void Disassembler::VisitSVEExtractElementToSIMDFPScalarRegister(
4392 const Instruction *instr) {
4393 FormatWithDecodedMnemonic(instr, "'t'u0400, 'Pgl, 'Zn.'t");
4394 }
4395
4396 void Disassembler::VisitSVEFFRInitialise(const Instruction *instr) {
4397 DisassembleNoArgs(instr);
4398 }
4399
4400 void Disassembler::VisitSVEFFRWriteFromPredicate(const Instruction *instr) {
4401 FormatWithDecodedMnemonic(instr, "'Pn.b");
4402 }
4403
4404 void 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
4432 void 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
4440 void 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
4466 void 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
4502 void 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
4512 void 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
4520 void 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
4530 void 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
4540 void 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
4548 static 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
4564 void 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
4571 void 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
4580 void 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
4588 void Disassembler::VisitSVEInsertSIMDFPScalarRegister(
4589 const Instruction *instr) {
4590 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Vnv");
4591 }
4592
4593 void 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
4601 void Disassembler::VisitSVEIntAddSubtractVectors_Predicated(
4602 const Instruction *instr) {
4603 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");
4604 }
4605
4606 void 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
4613 void 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
4648 void 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
4658 void Disassembler::VisitSVEIntMinMaxDifference_Predicated(
4659 const Instruction *instr) {
4660 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");
4661 }
4662
4663 void 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
4676 void Disassembler::VisitSVEIntMulImm_Unpredicated(const Instruction *instr) {
4677 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zd.'t, #'s1205");
4678 }
4679
4680 void Disassembler::VisitSVEIntMulVectors_Predicated(const Instruction *instr) {
4681 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/m, 'Zd.'t, 'Zn.'t");
4682 }
4683
4684 void 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
4749 void 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
4767 void 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
4781 void 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
4805 void 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
4829 void 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
4837 void 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
4845 void Disassembler::VisitSVEPartitionBreakCondition(const Instruction *instr) {
4846 FormatWithDecodedMnemonic(instr, "'Pd.b, p'u1310/'?04:mz, 'Pn.b");
4847 }
4848
4849 void Disassembler::VisitSVEPermutePredicateElements(const Instruction *instr) {
4850 FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pn.'t, 'Pm.'t");
4851 }
4852
4853 void Disassembler::VisitSVEPredicateFirstActive(const Instruction *instr) {
4854 FormatWithDecodedMnemonic(instr, "'Pd.b, 'Pn, 'Pd.b");
4855 }
4856
4857 void Disassembler::VisitSVEPredicateReadFromFFR_Unpredicated(
4858 const Instruction *instr) {
4859 FormatWithDecodedMnemonic(instr, "'Pd.b");
4860 }
4861
4862 void Disassembler::VisitSVEPredicateTest(const Instruction *instr) {
4863 FormatWithDecodedMnemonic(instr, "p'u1310, 'Pn.b");
4864 }
4865
4866 void Disassembler::VisitSVEPredicateZero(const Instruction *instr) {
4867 FormatWithDecodedMnemonic(instr, "'Pd.b");
4868 }
4869
4870 void Disassembler::VisitSVEPropagateBreakToNextPartition(
4871 const Instruction *instr) {
4872 FormatWithDecodedMnemonic(instr, "'Pd.b, p'u1310/z, 'Pn.b, 'Pd.b");
4873 }
4874
4875 void Disassembler::VisitSVEReversePredicateElements(const Instruction *instr) {
4876 FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pn.'t");
4877 }
4878
4879 void Disassembler::VisitSVEReverseVectorElements(const Instruction *instr) {
4880 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t");
4881 }
4882
4883 void 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
4920 void 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
4946 void 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
4955 void 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
4979 void 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
5003 void 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
5011 void 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
5019 void Disassembler::VisitSVETableLookup(const Instruction *instr) {
5020 FormatWithDecodedMnemonic(instr, "'Zd.'t, {'Zn.'t}, 'Zm.'t");
5021 }
5022
5023 void Disassembler::VisitSVEUnpackPredicateElements(const Instruction *instr) {
5024 FormatWithDecodedMnemonic(instr, "'Pd.h, 'Pn.b");
5025 }
5026
5027 void 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
5036 void Disassembler::VisitSVEVectorSplice(const Instruction *instr) {
5037 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl, 'Zd.'t, 'Zn.'t");
5038 }
5039
5040 void 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
5067 void 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
5095 void 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
5144 void 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
5150 void 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
5158 void 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
5166 void 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
5174 void 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
5182 void 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
5192 void 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
5201 void 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
5212 void 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
5220 void 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
5233 void 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
5241 void 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
5256 void 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
5264 void 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
5293 void 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
5312 void Disassembler::VisitSVEIntArithmeticUnpredicated(const Instruction *instr) {
5313 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t, 'Zm.'t");
5314 }
5315
5316 void Disassembler::VisitSVEIntCompareSignedImm(const Instruction *instr) {
5317 FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pgl/z, 'Zn.'t, #'s2016");
5318 }
5319
5320 void Disassembler::VisitSVEIntCompareUnsignedImm(const Instruction *instr) {
5321 FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pgl/z, 'Zn.'t, #'u2014");
5322 }
5323
5324 void 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
5340 void 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
5352 void 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
5360 void Disassembler::VisitSVEMovprfx(const Instruction *instr) {
5361 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Pgl/'?16:mz, 'Zn.'t");
5362 }
5363
5364 void 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
5375 void 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
5408 void 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
5421 void Disassembler::VisitSVEPermuteVectorExtract(const Instruction *instr) {
5422 FormatWithDecodedMnemonic(instr, "'Zd.b, 'Zd.b, 'Zn.b, #'u2016:1210");
5423 }
5424
5425 void Disassembler::VisitSVEPermuteVectorInterleaving(const Instruction *instr) {
5426 FormatWithDecodedMnemonic(instr, "'Zd.'t, 'Zn.'t, 'Zm.'t");
5427 }
5428
5429 void Disassembler::VisitSVEPredicateCount(const Instruction *instr) {
5430 FormatWithDecodedMnemonic(instr, "'Xd, p'u1310, 'Pn.'t");
5431 }
5432
5433 void 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
5491 void 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
5498 void Disassembler::VisitSVEPredicateNextActive(const Instruction *instr) {
5499 FormatWithDecodedMnemonic(instr, "'Pd.'t, 'Pn, 'Pd.'t");
5500 }
5501
5502 void Disassembler::VisitSVEPredicateReadFromFFR_Predicated(
5503 const Instruction *instr) {
5504 FormatWithDecodedMnemonic(instr, "'Pd.b, 'Pn/z");
5505 }
5506
5507 void Disassembler::VisitSVEPropagateBreak(const Instruction *instr) {
5508 FormatWithDecodedMnemonic(instr, "'Pd.b, p'u1310/z, 'Pn.b, 'Pm.b");
5509 }
5510
5511 void Disassembler::VisitSVEStackFrameAdjustment(const Instruction *instr) {
5512 FormatWithDecodedMnemonic(instr, "'Xds, 'Xms, #'s1005");
5513 }
5514
5515 void Disassembler::VisitSVEStackFrameSize(const Instruction *instr) {
5516 FormatWithDecodedMnemonic(instr, "'Xd, #'s1005");
5517 }
5518
5519 void 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
5531 void 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
5539 void 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
5565 void 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
5571 void Disassembler::VisitUnimplemented(const Instruction *instr) {
5572 Format(instr, "unimplemented", "(Unimplemented)");
5573 }
5574
5575
5576 void Disassembler::VisitUnallocated(const Instruction *instr) {
5577 Format(instr, "unallocated", "(Unallocated)");
5578 }
5579
5580 void 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
5594 void 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
5605 void 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
5610 void 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
5619 void 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
5624 void 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
5629 void 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
5634 void 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
5639 void 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
5644 void 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
5649 void 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
5654 void 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
5659 void 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
5668 void 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
5673 void 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
5678 void 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
5683 void 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
5692 void 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
5697 void 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
5707 void 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
5712 void 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
5717 void 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
5722 void 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
5731 void 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
5749 void 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
5761 void 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
5770 void 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
5783 void 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
5796 void 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
5801 void 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
5807 void 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
5812 void 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
5817 void 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
5823 void 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
5828 void 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
5834 void 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
5839 void 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
5844 void 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
5849 void 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
5855 void 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
5867 void 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
5872 void 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
5877 void 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
5882 void 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
5891 void 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
5902 void Disassembler::Disassemble_ZdnB_ZdnB(const Instruction *instr) {
5903 const char *form = "'Zd.b, 'Zd.b";
5904 Format(instr, mnemonic_.c_str(), form);
5905 }
5906
5907 void 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
5912 void 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
5917 void 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
5922 void 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
5931 void 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
5936 void 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
5942 void 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
5954 void 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
5960 void 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
5966 void 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
5972 void 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
5978 void 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
5984 void 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
5990 void Disassembler::Disassemble_Xd_XnSP_Xm(const Instruction *instr) {
5991 const char *form = "'Rd, 'Xns, 'Rm";
5992 Format(instr, mnemonic_.c_str(), form);
5993 }
5994
5995 void 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
6004 void 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
6029 void 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
6063 void 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
6069 void 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
6089 void 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
6109 void Disassembler::ProcessOutput(const Instruction * /*instr*/) {
6110 // The base disasm does nothing more than disassembling into a buffer.
6111 }
6112
6113
6114 void Disassembler::AppendRegisterNameToOutput(const Instruction *instr,
6115 const CPURegister ®) {
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
6156 void 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
6169 void 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
6176 void Disassembler::AppendCodeAddressToOutput(const Instruction *instr,
6177 const void *addr) {
6178 AppendAddressToOutput(instr, addr);
6179 }
6180
6181
6182 void Disassembler::AppendDataAddressToOutput(const Instruction *instr,
6183 const void *addr) {
6184 AppendAddressToOutput(instr, addr);
6185 }
6186
6187
6188 void 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
6200 void Disassembler::AppendCodeRelativeCodeAddressToOutput(
6201 const Instruction *instr, const void *addr) {
6202 AppendCodeRelativeAddressToOutput(instr, addr);
6203 }
6204
6205
6206 void Disassembler::AppendCodeRelativeDataAddressToOutput(
6207 const Instruction *instr, const void *addr) {
6208 AppendCodeRelativeAddressToOutput(instr, addr);
6209 }
6210
6211
6212 void 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 }
6217 int64_t Disassembler::CodeRelativeAddress(const void *addr) {
6218 return reinterpret_cast<intptr_t>(addr) + code_address_offset();
6219 }
6220
6221
6222 void 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
6246 void Disassembler::FormatWithDecodedMnemonic(const Instruction *instr,
6247 const char *format0,
6248 const char *format1) {
6249 Format(instr, mnemonic_.c_str(), format0, format1);
6250 }
6251
6252 void 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
6266 int 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
6322 std::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
6392 int 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(®_field[2], &eimm, 10));
6436 field_len += static_cast<unsigned>(eimm - ®_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
6523 int 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
6549 int 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
6982 int 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
7018 int 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
7057 int 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
7091 int 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
7127 int 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
7153 int 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
7190 int 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
7217 int 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
7252 int 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
7293 int 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
7309 int 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
7327 int 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
7345 int 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
7403 int 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
7479 int 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
7497 void Disassembler::ResetOutput() {
7498 buffer_pos_ = 0;
7499 buffer_[buffer_pos_] = 0;
7500 }
7501
7502
7503 void 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
7514 void 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
7527 void 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
7542 void PrintDisassembler::DisassembleBuffer(const Instruction *start,
7543 uint64_t size) {
7544 DisassembleBuffer(start, start + size);
7545 }
7546
7547
7548 void 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