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