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