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