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