blob: c7a29fbf7fad8213d76787dfbb61c1e59e6face6 [file] [log] [blame]
Alexandre Ramesd3832962016-07-04 15:03:43 +01001// 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
Pierre Langlois1e85b7f2016-08-05 14:20:36 +010027#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
Alexandre Ramesd3832962016-07-04 15:03:43 +010028
mmc28a1a2c1d32024-02-01 16:43:49 +000029#include "simulator-aarch64.h"
Jacob Bramley85a9c102019-12-09 17:48:29 +000030
Alexandre Ramesd3832962016-07-04 15:03:43 +010031#include <cmath>
Pierre Langlois1bce0072017-06-06 17:58:58 +010032#include <cstring>
mmc28a1a2c1d32024-02-01 16:43:49 +000033#include <errno.h>
Martyn Capewell5b24fb32016-11-02 18:52:55 +000034#include <limits>
TheLastRar49d6efa2024-10-15 16:37:27 +010035
36#ifdef _WIN32
37#define WIN32_LEAN_AND_MEAN
38#define NOMINMAX
39#include <Windows.h>
40#undef MultiplyHigh
41#include <Memoryapi.h>
42#else
mmc28a1a2c1d32024-02-01 16:43:49 +000043#include <sys/mman.h>
44#include <unistd.h>
TheLastRar49d6efa2024-10-15 16:37:27 +010045#endif
46
47#ifdef _MSC_VER
48#define VIXL_SYNC() MemoryBarrier()
49#else
50#define VIXL_SYNC() __sync_synchronize()
51#endif
Alexandre Ramesd3832962016-07-04 15:03:43 +010052
53namespace vixl {
54namespace aarch64 {
55
Jacob Bramleyca789742018-09-13 14:25:46 +010056using vixl::internal::SimFloat16;
57
Alexandre Ramesd3832962016-07-04 15:03:43 +010058const Instruction* Simulator::kEndOfSimAddress = NULL;
59
Chris Jones3134e252024-02-29 13:44:20 +000060MemoryAccessResult TryMemoryAccess(uintptr_t address, uintptr_t access_size) {
Chris Jones30e7bbd2024-02-15 15:05:25 +000061#ifdef VIXL_ENABLE_IMPLICIT_CHECKS
62 for (uintptr_t i = 0; i < access_size; i++) {
Chris Jones3134e252024-02-29 13:44:20 +000063 if (_vixl_internal_ReadMemory(address, i) == MemoryAccessResult::Failure) {
64 // The memory access failed.
65 return MemoryAccessResult::Failure;
Chris Jones30e7bbd2024-02-15 15:05:25 +000066 }
67 }
68
Chris Jones3134e252024-02-29 13:44:20 +000069 // Either the memory access did not raise a signal or the signal handler did
70 // not correctly return MemoryAccessResult::Failure.
71 return MemoryAccessResult::Success;
Chris Jones30e7bbd2024-02-15 15:05:25 +000072#else
73 USE(address);
74 USE(access_size);
Chris Jones3134e252024-02-29 13:44:20 +000075 return MemoryAccessResult::Success;
Chris Jones30e7bbd2024-02-15 15:05:25 +000076#endif // VIXL_ENABLE_IMPLICIT_CHECKS
77}
78
TatWai Chong6767df02022-03-25 11:33:54 -070079bool MetaDataDepot::MetaDataMTE::is_active = false;
80
Alexandre Ramesd3832962016-07-04 15:03:43 +010081void SimSystemRegister::SetBits(int msb, int lsb, uint32_t bits) {
82 int width = msb - lsb + 1;
83 VIXL_ASSERT(IsUintN(width, bits) || IsIntN(width, bits));
84
85 bits <<= lsb;
86 uint32_t mask = ((1 << width) - 1) << lsb;
87 VIXL_ASSERT((mask & write_ignore_mask_) == 0);
88
89 value_ = (value_ & ~mask) | (bits & mask);
90}
91
92
93SimSystemRegister SimSystemRegister::DefaultValueFor(SystemRegister id) {
94 switch (id) {
95 case NZCV:
96 return SimSystemRegister(0x00000000, NZCVWriteIgnoreMask);
97 case FPCR:
98 return SimSystemRegister(0x00000000, FPCRWriteIgnoreMask);
99 default:
100 VIXL_UNREACHABLE();
101 return SimSystemRegister();
102 }
103}
104
Martyn Capewellea8fa652022-01-26 15:48:07 +0000105const Simulator::FormToVisitorFnMap* Simulator::GetFormToVisitorFnMap() {
106 static const FormToVisitorFnMap form_to_visitor = {
107 DEFAULT_FORM_TO_VISITOR_MAP(Simulator),
108 SIM_AUD_VISITOR_MAP(Simulator),
Martyn Capewell8afff392022-04-19 18:08:39 +0100109 {"smlal_asimdelem_l"_h, &Simulator::SimulateNEONMulByElementLong},
110 {"smlsl_asimdelem_l"_h, &Simulator::SimulateNEONMulByElementLong},
111 {"smull_asimdelem_l"_h, &Simulator::SimulateNEONMulByElementLong},
112 {"sqdmlal_asimdelem_l"_h, &Simulator::SimulateNEONMulByElementLong},
113 {"sqdmlsl_asimdelem_l"_h, &Simulator::SimulateNEONMulByElementLong},
114 {"sqdmull_asimdelem_l"_h, &Simulator::SimulateNEONMulByElementLong},
115 {"umlal_asimdelem_l"_h, &Simulator::SimulateNEONMulByElementLong},
116 {"umlsl_asimdelem_l"_h, &Simulator::SimulateNEONMulByElementLong},
117 {"umull_asimdelem_l"_h, &Simulator::SimulateNEONMulByElementLong},
118 {"fcmla_asimdelem_c_h"_h, &Simulator::SimulateNEONComplexMulByElement},
119 {"fcmla_asimdelem_c_s"_h, &Simulator::SimulateNEONComplexMulByElement},
120 {"fmlal2_asimdelem_lh"_h, &Simulator::SimulateNEONFPMulByElementLong},
121 {"fmlal_asimdelem_lh"_h, &Simulator::SimulateNEONFPMulByElementLong},
122 {"fmlsl2_asimdelem_lh"_h, &Simulator::SimulateNEONFPMulByElementLong},
123 {"fmlsl_asimdelem_lh"_h, &Simulator::SimulateNEONFPMulByElementLong},
124 {"fmla_asimdelem_rh_h"_h, &Simulator::SimulateNEONFPMulByElement},
125 {"fmls_asimdelem_rh_h"_h, &Simulator::SimulateNEONFPMulByElement},
126 {"fmulx_asimdelem_rh_h"_h, &Simulator::SimulateNEONFPMulByElement},
127 {"fmul_asimdelem_rh_h"_h, &Simulator::SimulateNEONFPMulByElement},
128 {"fmla_asimdelem_r_sd"_h, &Simulator::SimulateNEONFPMulByElement},
129 {"fmls_asimdelem_r_sd"_h, &Simulator::SimulateNEONFPMulByElement},
130 {"fmulx_asimdelem_r_sd"_h, &Simulator::SimulateNEONFPMulByElement},
131 {"fmul_asimdelem_r_sd"_h, &Simulator::SimulateNEONFPMulByElement},
132 {"sdot_asimdelem_d"_h, &Simulator::SimulateNEONDotProdByElement},
133 {"udot_asimdelem_d"_h, &Simulator::SimulateNEONDotProdByElement},
134 {"adclb_z_zzz"_h, &Simulator::SimulateSVEAddSubCarry},
135 {"adclt_z_zzz"_h, &Simulator::SimulateSVEAddSubCarry},
136 {"addhnb_z_zz"_h, &Simulator::SimulateSVEAddSubHigh},
137 {"addhnt_z_zz"_h, &Simulator::SimulateSVEAddSubHigh},
138 {"addp_z_p_zz"_h, &Simulator::SimulateSVEIntArithPair},
139 {"bcax_z_zzz"_h, &Simulator::SimulateSVEBitwiseTernary},
140 {"bdep_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
141 {"bext_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
142 {"bgrp_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
143 {"bsl1n_z_zzz"_h, &Simulator::SimulateSVEBitwiseTernary},
144 {"bsl2n_z_zzz"_h, &Simulator::SimulateSVEBitwiseTernary},
145 {"bsl_z_zzz"_h, &Simulator::SimulateSVEBitwiseTernary},
146 {"cadd_z_zz"_h, &Simulator::Simulate_ZdnT_ZdnT_ZmT_const},
147 {"cdot_z_zzz"_h, &Simulator::SimulateSVEComplexDotProduct},
148 {"cdot_z_zzzi_d"_h, &Simulator::SimulateSVEComplexDotProduct},
149 {"cdot_z_zzzi_s"_h, &Simulator::SimulateSVEComplexDotProduct},
150 {"cmla_z_zzz"_h, &Simulator::SimulateSVEComplexIntMulAdd},
151 {"cmla_z_zzzi_h"_h, &Simulator::SimulateSVEComplexIntMulAdd},
152 {"cmla_z_zzzi_s"_h, &Simulator::SimulateSVEComplexIntMulAdd},
153 {"eor3_z_zzz"_h, &Simulator::SimulateSVEBitwiseTernary},
154 {"eorbt_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
155 {"eortb_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
156 {"ext_z_zi_con"_h, &Simulator::Simulate_ZdB_Zn1B_Zn2B_imm},
157 {"faddp_z_p_zz"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_ZmT},
158 {"fcvtlt_z_p_z_h2s"_h, &Simulator::SimulateSVEFPConvertLong},
159 {"fcvtlt_z_p_z_s2d"_h, &Simulator::SimulateSVEFPConvertLong},
160 {"fcvtnt_z_p_z_d2s"_h, &Simulator::Simulate_ZdS_PgM_ZnD},
161 {"fcvtnt_z_p_z_s2h"_h, &Simulator::Simulate_ZdH_PgM_ZnS},
162 {"fcvtx_z_p_z_d2s"_h, &Simulator::Simulate_ZdS_PgM_ZnD},
163 {"fcvtxnt_z_p_z_d2s"_h, &Simulator::Simulate_ZdS_PgM_ZnD},
164 {"flogb_z_p_z"_h, &Simulator::Simulate_ZdT_PgM_ZnT},
165 {"fmaxnmp_z_p_zz"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_ZmT},
166 {"fmaxp_z_p_zz"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_ZmT},
167 {"fminnmp_z_p_zz"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_ZmT},
168 {"fminp_z_p_zz"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_ZmT},
169 {"fmlalb_z_zzz"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH},
170 {"fmlalb_z_zzzi_s"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH_imm},
171 {"fmlalt_z_zzz"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH},
172 {"fmlalt_z_zzzi_s"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH_imm},
173 {"fmlslb_z_zzz"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH},
174 {"fmlslb_z_zzzi_s"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH_imm},
175 {"fmlslt_z_zzz"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH},
176 {"fmlslt_z_zzzi_s"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH_imm},
177 {"histcnt_z_p_zz"_h, &Simulator::Simulate_ZdT_PgZ_ZnT_ZmT},
178 {"histseg_z_zz"_h, &Simulator::Simulate_ZdB_ZnB_ZmB},
179 {"ldnt1b_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_PgZ_ZnD_Xm},
180 {"ldnt1b_z_p_ar_s_x32_unscaled"_h, &Simulator::Simulate_ZtS_PgZ_ZnS_Xm},
181 {"ldnt1d_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_PgZ_ZnD_Xm},
182 {"ldnt1h_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_PgZ_ZnD_Xm},
183 {"ldnt1h_z_p_ar_s_x32_unscaled"_h, &Simulator::Simulate_ZtS_PgZ_ZnS_Xm},
184 {"ldnt1sb_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_PgZ_ZnD_Xm},
185 {"ldnt1sb_z_p_ar_s_x32_unscaled"_h, &Simulator::Simulate_ZtS_PgZ_ZnS_Xm},
186 {"ldnt1sh_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_PgZ_ZnD_Xm},
187 {"ldnt1sh_z_p_ar_s_x32_unscaled"_h, &Simulator::Simulate_ZtS_PgZ_ZnS_Xm},
188 {"ldnt1sw_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_PgZ_ZnD_Xm},
189 {"ldnt1w_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_PgZ_ZnD_Xm},
190 {"ldnt1w_z_p_ar_s_x32_unscaled"_h, &Simulator::Simulate_ZtS_PgZ_ZnS_Xm},
191 {"match_p_p_zz"_h, &Simulator::Simulate_PdT_PgZ_ZnT_ZmT},
192 {"mla_z_zzzi_d"_h, &Simulator::SimulateSVEMlaMlsIndex},
193 {"mla_z_zzzi_h"_h, &Simulator::SimulateSVEMlaMlsIndex},
194 {"mla_z_zzzi_s"_h, &Simulator::SimulateSVEMlaMlsIndex},
195 {"mls_z_zzzi_d"_h, &Simulator::SimulateSVEMlaMlsIndex},
196 {"mls_z_zzzi_h"_h, &Simulator::SimulateSVEMlaMlsIndex},
197 {"mls_z_zzzi_s"_h, &Simulator::SimulateSVEMlaMlsIndex},
198 {"mul_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
199 {"mul_z_zzi_d"_h, &Simulator::SimulateSVEMulIndex},
200 {"mul_z_zzi_h"_h, &Simulator::SimulateSVEMulIndex},
201 {"mul_z_zzi_s"_h, &Simulator::SimulateSVEMulIndex},
202 {"nbsl_z_zzz"_h, &Simulator::SimulateSVEBitwiseTernary},
203 {"nmatch_p_p_zz"_h, &Simulator::Simulate_PdT_PgZ_ZnT_ZmT},
204 {"pmul_z_zz"_h, &Simulator::Simulate_ZdB_ZnB_ZmB},
205 {"pmullb_z_zz"_h, &Simulator::SimulateSVEIntMulLongVec},
206 {"pmullt_z_zz"_h, &Simulator::SimulateSVEIntMulLongVec},
207 {"raddhnb_z_zz"_h, &Simulator::SimulateSVEAddSubHigh},
208 {"raddhnt_z_zz"_h, &Simulator::SimulateSVEAddSubHigh},
209 {"rshrnb_z_zi"_h, &Simulator::SimulateSVENarrow},
210 {"rshrnt_z_zi"_h, &Simulator::SimulateSVENarrow},
211 {"rsubhnb_z_zz"_h, &Simulator::SimulateSVEAddSubHigh},
212 {"rsubhnt_z_zz"_h, &Simulator::SimulateSVEAddSubHigh},
213 {"saba_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnT_ZmT},
214 {"sabalb_z_zzz"_h, &Simulator::SimulateSVEInterleavedArithLong},
215 {"sabalt_z_zzz"_h, &Simulator::SimulateSVEInterleavedArithLong},
216 {"sabdlb_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
217 {"sabdlt_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
218 {"sadalp_z_p_z"_h, &Simulator::Simulate_ZdaT_PgM_ZnTb},
219 {"saddlb_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
220 {"saddlbt_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
221 {"saddlt_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
222 {"saddwb_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmTb},
223 {"saddwt_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmTb},
224 {"sbclb_z_zzz"_h, &Simulator::SimulateSVEAddSubCarry},
225 {"sbclt_z_zzz"_h, &Simulator::SimulateSVEAddSubCarry},
226 {"shadd_z_p_zz"_h, &Simulator::SimulateSVEHalvingAddSub},
227 {"shrnb_z_zi"_h, &Simulator::SimulateSVENarrow},
228 {"shrnt_z_zi"_h, &Simulator::SimulateSVENarrow},
229 {"shsub_z_p_zz"_h, &Simulator::SimulateSVEHalvingAddSub},
230 {"shsubr_z_p_zz"_h, &Simulator::SimulateSVEHalvingAddSub},
231 {"sli_z_zzi"_h, &Simulator::Simulate_ZdT_ZnT_const},
232 {"smaxp_z_p_zz"_h, &Simulator::SimulateSVEIntArithPair},
233 {"sminp_z_p_zz"_h, &Simulator::SimulateSVEIntArithPair},
234 {"smlalb_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
235 {"smlalb_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
236 {"smlalb_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
237 {"smlalt_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
238 {"smlalt_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
239 {"smlalt_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
240 {"smlslb_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
241 {"smlslb_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
242 {"smlslb_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
243 {"smlslt_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
244 {"smlslt_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
245 {"smlslt_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
246 {"smulh_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
247 {"smullb_z_zz"_h, &Simulator::SimulateSVEIntMulLongVec},
248 {"smullb_z_zzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
249 {"smullb_z_zzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
250 {"smullt_z_zz"_h, &Simulator::SimulateSVEIntMulLongVec},
251 {"smullt_z_zzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
252 {"smullt_z_zzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
253 {"splice_z_p_zz_con"_h, &Simulator::VisitSVEVectorSplice},
254 {"sqabs_z_p_z"_h, &Simulator::Simulate_ZdT_PgM_ZnT},
255 {"sqadd_z_p_zz"_h, &Simulator::SimulateSVESaturatingArithmetic},
256 {"sqcadd_z_zz"_h, &Simulator::Simulate_ZdnT_ZdnT_ZmT_const},
257 {"sqdmlalb_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
258 {"sqdmlalb_z_zzzi_d"_h, &Simulator::Simulate_ZdaD_ZnS_ZmS_imm},
259 {"sqdmlalb_z_zzzi_s"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH_imm},
260 {"sqdmlalbt_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
261 {"sqdmlalt_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
262 {"sqdmlalt_z_zzzi_d"_h, &Simulator::Simulate_ZdaD_ZnS_ZmS_imm},
263 {"sqdmlalt_z_zzzi_s"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH_imm},
264 {"sqdmlslb_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
265 {"sqdmlslb_z_zzzi_d"_h, &Simulator::Simulate_ZdaD_ZnS_ZmS_imm},
266 {"sqdmlslb_z_zzzi_s"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH_imm},
267 {"sqdmlslbt_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
268 {"sqdmlslt_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
269 {"sqdmlslt_z_zzzi_d"_h, &Simulator::Simulate_ZdaD_ZnS_ZmS_imm},
270 {"sqdmlslt_z_zzzi_s"_h, &Simulator::Simulate_ZdaS_ZnH_ZmH_imm},
271 {"sqdmulh_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
272 {"sqdmulh_z_zzi_d"_h, &Simulator::SimulateSVESaturatingMulHighIndex},
273 {"sqdmulh_z_zzi_h"_h, &Simulator::SimulateSVESaturatingMulHighIndex},
274 {"sqdmulh_z_zzi_s"_h, &Simulator::SimulateSVESaturatingMulHighIndex},
275 {"sqdmullb_z_zz"_h, &Simulator::SimulateSVEIntMulLongVec},
276 {"sqdmullb_z_zzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
277 {"sqdmullb_z_zzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
278 {"sqdmullt_z_zz"_h, &Simulator::SimulateSVEIntMulLongVec},
279 {"sqdmullt_z_zzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
280 {"sqdmullt_z_zzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
281 {"sqneg_z_p_z"_h, &Simulator::Simulate_ZdT_PgM_ZnT},
282 {"sqrdcmlah_z_zzz"_h, &Simulator::SimulateSVEComplexIntMulAdd},
283 {"sqrdcmlah_z_zzzi_h"_h, &Simulator::SimulateSVEComplexIntMulAdd},
284 {"sqrdcmlah_z_zzzi_s"_h, &Simulator::SimulateSVEComplexIntMulAdd},
285 {"sqrdmlah_z_zzz"_h, &Simulator::SimulateSVESaturatingMulAddHigh},
286 {"sqrdmlah_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingMulAddHigh},
287 {"sqrdmlah_z_zzzi_h"_h, &Simulator::SimulateSVESaturatingMulAddHigh},
288 {"sqrdmlah_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingMulAddHigh},
289 {"sqrdmlsh_z_zzz"_h, &Simulator::SimulateSVESaturatingMulAddHigh},
290 {"sqrdmlsh_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingMulAddHigh},
291 {"sqrdmlsh_z_zzzi_h"_h, &Simulator::SimulateSVESaturatingMulAddHigh},
292 {"sqrdmlsh_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingMulAddHigh},
293 {"sqrdmulh_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
294 {"sqrdmulh_z_zzi_d"_h, &Simulator::SimulateSVESaturatingMulHighIndex},
295 {"sqrdmulh_z_zzi_h"_h, &Simulator::SimulateSVESaturatingMulHighIndex},
296 {"sqrdmulh_z_zzi_s"_h, &Simulator::SimulateSVESaturatingMulHighIndex},
297 {"sqrshl_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
298 {"sqrshlr_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
299 {"sqrshrnb_z_zi"_h, &Simulator::SimulateSVENarrow},
300 {"sqrshrnt_z_zi"_h, &Simulator::SimulateSVENarrow},
301 {"sqrshrunb_z_zi"_h, &Simulator::SimulateSVENarrow},
302 {"sqrshrunt_z_zi"_h, &Simulator::SimulateSVENarrow},
303 {"sqshl_z_p_zi"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_const},
304 {"sqshl_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
305 {"sqshlr_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
306 {"sqshlu_z_p_zi"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_const},
307 {"sqshrnb_z_zi"_h, &Simulator::SimulateSVENarrow},
308 {"sqshrnt_z_zi"_h, &Simulator::SimulateSVENarrow},
309 {"sqshrunb_z_zi"_h, &Simulator::SimulateSVENarrow},
310 {"sqshrunt_z_zi"_h, &Simulator::SimulateSVENarrow},
311 {"sqsub_z_p_zz"_h, &Simulator::SimulateSVESaturatingArithmetic},
312 {"sqsubr_z_p_zz"_h, &Simulator::SimulateSVESaturatingArithmetic},
313 {"sqxtnb_z_zz"_h, &Simulator::SimulateSVENarrow},
314 {"sqxtnt_z_zz"_h, &Simulator::SimulateSVENarrow},
315 {"sqxtunb_z_zz"_h, &Simulator::SimulateSVENarrow},
316 {"sqxtunt_z_zz"_h, &Simulator::SimulateSVENarrow},
317 {"srhadd_z_p_zz"_h, &Simulator::SimulateSVEHalvingAddSub},
318 {"sri_z_zzi"_h, &Simulator::Simulate_ZdT_ZnT_const},
319 {"srshl_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
320 {"srshlr_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
321 {"srshr_z_p_zi"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_const},
322 {"srsra_z_zi"_h, &Simulator::Simulate_ZdaT_ZnT_const},
323 {"sshllb_z_zi"_h, &Simulator::SimulateSVEShiftLeftImm},
324 {"sshllt_z_zi"_h, &Simulator::SimulateSVEShiftLeftImm},
325 {"ssra_z_zi"_h, &Simulator::Simulate_ZdaT_ZnT_const},
326 {"ssublb_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
327 {"ssublbt_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
328 {"ssublt_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
329 {"ssubltb_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
330 {"ssubwb_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmTb},
331 {"ssubwt_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmTb},
332 {"stnt1b_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_Pg_ZnD_Xm},
333 {"stnt1b_z_p_ar_s_x32_unscaled"_h, &Simulator::Simulate_ZtS_Pg_ZnS_Xm},
334 {"stnt1d_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_Pg_ZnD_Xm},
335 {"stnt1h_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_Pg_ZnD_Xm},
336 {"stnt1h_z_p_ar_s_x32_unscaled"_h, &Simulator::Simulate_ZtS_Pg_ZnS_Xm},
337 {"stnt1w_z_p_ar_d_64_unscaled"_h, &Simulator::Simulate_ZtD_Pg_ZnD_Xm},
338 {"stnt1w_z_p_ar_s_x32_unscaled"_h, &Simulator::Simulate_ZtS_Pg_ZnS_Xm},
339 {"subhnb_z_zz"_h, &Simulator::SimulateSVEAddSubHigh},
340 {"subhnt_z_zz"_h, &Simulator::SimulateSVEAddSubHigh},
341 {"suqadd_z_p_zz"_h, &Simulator::SimulateSVESaturatingArithmetic},
342 {"tbl_z_zz_2"_h, &Simulator::VisitSVETableLookup},
343 {"tbx_z_zz"_h, &Simulator::VisitSVETableLookup},
344 {"uaba_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnT_ZmT},
345 {"uabalb_z_zzz"_h, &Simulator::SimulateSVEInterleavedArithLong},
346 {"uabalt_z_zzz"_h, &Simulator::SimulateSVEInterleavedArithLong},
347 {"uabdlb_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
348 {"uabdlt_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
349 {"uadalp_z_p_z"_h, &Simulator::Simulate_ZdaT_PgM_ZnTb},
350 {"uaddlb_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
351 {"uaddlt_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
352 {"uaddwb_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmTb},
353 {"uaddwt_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmTb},
354 {"uhadd_z_p_zz"_h, &Simulator::SimulateSVEHalvingAddSub},
355 {"uhsub_z_p_zz"_h, &Simulator::SimulateSVEHalvingAddSub},
356 {"uhsubr_z_p_zz"_h, &Simulator::SimulateSVEHalvingAddSub},
357 {"umaxp_z_p_zz"_h, &Simulator::SimulateSVEIntArithPair},
358 {"uminp_z_p_zz"_h, &Simulator::SimulateSVEIntArithPair},
359 {"umlalb_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
360 {"umlalb_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
361 {"umlalb_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
362 {"umlalt_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
363 {"umlalt_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
364 {"umlalt_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
365 {"umlslb_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
366 {"umlslb_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
367 {"umlslb_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
368 {"umlslt_z_zzz"_h, &Simulator::Simulate_ZdaT_ZnTb_ZmTb},
369 {"umlslt_z_zzzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
370 {"umlslt_z_zzzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
371 {"umulh_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmT},
372 {"umullb_z_zz"_h, &Simulator::SimulateSVEIntMulLongVec},
373 {"umullb_z_zzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
374 {"umullb_z_zzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
375 {"umullt_z_zz"_h, &Simulator::SimulateSVEIntMulLongVec},
376 {"umullt_z_zzi_d"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
377 {"umullt_z_zzi_s"_h, &Simulator::SimulateSVESaturatingIntMulLongIdx},
378 {"uqadd_z_p_zz"_h, &Simulator::SimulateSVESaturatingArithmetic},
379 {"uqrshl_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
380 {"uqrshlr_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
381 {"uqrshrnb_z_zi"_h, &Simulator::SimulateSVENarrow},
382 {"uqrshrnt_z_zi"_h, &Simulator::SimulateSVENarrow},
383 {"uqshl_z_p_zi"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_const},
384 {"uqshl_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
385 {"uqshlr_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
386 {"uqshrnb_z_zi"_h, &Simulator::SimulateSVENarrow},
387 {"uqshrnt_z_zi"_h, &Simulator::SimulateSVENarrow},
388 {"uqsub_z_p_zz"_h, &Simulator::SimulateSVESaturatingArithmetic},
389 {"uqsubr_z_p_zz"_h, &Simulator::SimulateSVESaturatingArithmetic},
390 {"uqxtnb_z_zz"_h, &Simulator::SimulateSVENarrow},
391 {"uqxtnt_z_zz"_h, &Simulator::SimulateSVENarrow},
392 {"urecpe_z_p_z"_h, &Simulator::Simulate_ZdS_PgM_ZnS},
393 {"urhadd_z_p_zz"_h, &Simulator::SimulateSVEHalvingAddSub},
394 {"urshl_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
395 {"urshlr_z_p_zz"_h, &Simulator::VisitSVEBitwiseShiftByVector_Predicated},
396 {"urshr_z_p_zi"_h, &Simulator::Simulate_ZdnT_PgM_ZdnT_const},
397 {"ursqrte_z_p_z"_h, &Simulator::Simulate_ZdS_PgM_ZnS},
398 {"ursra_z_zi"_h, &Simulator::Simulate_ZdaT_ZnT_const},
399 {"ushllb_z_zi"_h, &Simulator::SimulateSVEShiftLeftImm},
400 {"ushllt_z_zi"_h, &Simulator::SimulateSVEShiftLeftImm},
401 {"usqadd_z_p_zz"_h, &Simulator::SimulateSVESaturatingArithmetic},
402 {"usra_z_zi"_h, &Simulator::Simulate_ZdaT_ZnT_const},
403 {"usublb_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
404 {"usublt_z_zz"_h, &Simulator::SimulateSVEInterleavedArithLong},
405 {"usubwb_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmTb},
406 {"usubwt_z_zz"_h, &Simulator::Simulate_ZdT_ZnT_ZmTb},
407 {"whilege_p_p_rr"_h, &Simulator::VisitSVEIntCompareScalarCountAndLimit},
408 {"whilegt_p_p_rr"_h, &Simulator::VisitSVEIntCompareScalarCountAndLimit},
409 {"whilehi_p_p_rr"_h, &Simulator::VisitSVEIntCompareScalarCountAndLimit},
410 {"whilehs_p_p_rr"_h, &Simulator::VisitSVEIntCompareScalarCountAndLimit},
411 {"whilerw_p_rr"_h, &Simulator::Simulate_PdT_Xn_Xm},
412 {"whilewr_p_rr"_h, &Simulator::Simulate_PdT_Xn_Xm},
413 {"xar_z_zzi"_h, &Simulator::SimulateSVEExclusiveOrRotate},
414 {"smmla_z_zzz"_h, &Simulator::SimulateMatrixMul},
415 {"ummla_z_zzz"_h, &Simulator::SimulateMatrixMul},
416 {"usmmla_z_zzz"_h, &Simulator::SimulateMatrixMul},
417 {"smmla_asimdsame2_g"_h, &Simulator::SimulateMatrixMul},
418 {"ummla_asimdsame2_g"_h, &Simulator::SimulateMatrixMul},
419 {"usmmla_asimdsame2_g"_h, &Simulator::SimulateMatrixMul},
420 {"fmmla_z_zzz_s"_h, &Simulator::SimulateSVEFPMatrixMul},
421 {"fmmla_z_zzz_d"_h, &Simulator::SimulateSVEFPMatrixMul},
422 {"ld1row_z_p_bi_u32"_h,
Martyn Capewellea8fa652022-01-26 15:48:07 +0000423 &Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm},
Martyn Capewell8afff392022-04-19 18:08:39 +0100424 {"ld1row_z_p_br_contiguous"_h,
Martyn Capewellea8fa652022-01-26 15:48:07 +0000425 &Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar},
Martyn Capewell8afff392022-04-19 18:08:39 +0100426 {"ld1rod_z_p_bi_u64"_h,
Martyn Capewellea8fa652022-01-26 15:48:07 +0000427 &Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm},
Martyn Capewell8afff392022-04-19 18:08:39 +0100428 {"ld1rod_z_p_br_contiguous"_h,
Martyn Capewellea8fa652022-01-26 15:48:07 +0000429 &Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar},
Martyn Capewell8afff392022-04-19 18:08:39 +0100430 {"ld1rob_z_p_bi_u8"_h,
Martyn Capewellea8fa652022-01-26 15:48:07 +0000431 &Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm},
Martyn Capewell8afff392022-04-19 18:08:39 +0100432 {"ld1rob_z_p_br_contiguous"_h,
Martyn Capewellea8fa652022-01-26 15:48:07 +0000433 &Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar},
Martyn Capewell8afff392022-04-19 18:08:39 +0100434 {"ld1roh_z_p_bi_u16"_h,
Martyn Capewellea8fa652022-01-26 15:48:07 +0000435 &Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm},
Martyn Capewell8afff392022-04-19 18:08:39 +0100436 {"ld1roh_z_p_br_contiguous"_h,
Martyn Capewellea8fa652022-01-26 15:48:07 +0000437 &Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar},
Martyn Capewell8afff392022-04-19 18:08:39 +0100438 {"usdot_z_zzz_s"_h, &Simulator::VisitSVEIntMulAddUnpredicated},
439 {"sudot_z_zzzi_s"_h, &Simulator::VisitSVEMulIndex},
440 {"usdot_z_zzzi_s"_h, &Simulator::VisitSVEMulIndex},
441 {"usdot_asimdsame2_d"_h, &Simulator::VisitNEON3SameExtra},
442 {"sudot_asimdelem_d"_h, &Simulator::SimulateNEONDotProdByElement},
443 {"usdot_asimdelem_d"_h, &Simulator::SimulateNEONDotProdByElement},
Martyn Capewelleeae1742022-08-04 13:24:47 +0100444 {"addg_64_addsub_immtags"_h, &Simulator::SimulateMTEAddSubTag},
445 {"gmi_64g_dp_2src"_h, &Simulator::SimulateMTETagMaskInsert},
446 {"irg_64i_dp_2src"_h, &Simulator::Simulate_XdSP_XnSP_Xm},
447 {"ldg_64loffset_ldsttags"_h, &Simulator::SimulateMTELoadTag},
448 {"st2g_64soffset_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
449 {"st2g_64spost_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
450 {"st2g_64spre_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
451 {"stgp_64_ldstpair_off"_h, &Simulator::SimulateMTEStoreTagPair},
452 {"stgp_64_ldstpair_post"_h, &Simulator::SimulateMTEStoreTagPair},
453 {"stgp_64_ldstpair_pre"_h, &Simulator::SimulateMTEStoreTagPair},
454 {"stg_64soffset_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
455 {"stg_64spost_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
456 {"stg_64spre_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
457 {"stz2g_64soffset_ldsttags"_h,
458 &Simulator::Simulator::SimulateMTEStoreTag},
459 {"stz2g_64spost_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
460 {"stz2g_64spre_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
461 {"stzg_64soffset_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
462 {"stzg_64spost_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
463 {"stzg_64spre_ldsttags"_h, &Simulator::Simulator::SimulateMTEStoreTag},
464 {"subg_64_addsub_immtags"_h, &Simulator::SimulateMTEAddSubTag},
465 {"subps_64s_dp_2src"_h, &Simulator::SimulateMTESubPointer},
466 {"subp_64s_dp_2src"_h, &Simulator::SimulateMTESubPointer},
Martyn Capewelld6acdad2022-05-12 15:35:15 +0100467 {"cpyen_cpy_memcms"_h, &Simulator::SimulateCpyE},
468 {"cpyern_cpy_memcms"_h, &Simulator::SimulateCpyE},
469 {"cpyewn_cpy_memcms"_h, &Simulator::SimulateCpyE},
470 {"cpye_cpy_memcms"_h, &Simulator::SimulateCpyE},
471 {"cpyfen_cpy_memcms"_h, &Simulator::SimulateCpyE},
472 {"cpyfern_cpy_memcms"_h, &Simulator::SimulateCpyE},
473 {"cpyfewn_cpy_memcms"_h, &Simulator::SimulateCpyE},
474 {"cpyfe_cpy_memcms"_h, &Simulator::SimulateCpyE},
475 {"cpyfmn_cpy_memcms"_h, &Simulator::SimulateCpyM},
476 {"cpyfmrn_cpy_memcms"_h, &Simulator::SimulateCpyM},
477 {"cpyfmwn_cpy_memcms"_h, &Simulator::SimulateCpyM},
478 {"cpyfm_cpy_memcms"_h, &Simulator::SimulateCpyM},
479 {"cpyfpn_cpy_memcms"_h, &Simulator::SimulateCpyFP},
480 {"cpyfprn_cpy_memcms"_h, &Simulator::SimulateCpyFP},
481 {"cpyfpwn_cpy_memcms"_h, &Simulator::SimulateCpyFP},
482 {"cpyfp_cpy_memcms"_h, &Simulator::SimulateCpyFP},
483 {"cpymn_cpy_memcms"_h, &Simulator::SimulateCpyM},
484 {"cpymrn_cpy_memcms"_h, &Simulator::SimulateCpyM},
485 {"cpymwn_cpy_memcms"_h, &Simulator::SimulateCpyM},
486 {"cpym_cpy_memcms"_h, &Simulator::SimulateCpyM},
487 {"cpypn_cpy_memcms"_h, &Simulator::SimulateCpyP},
488 {"cpyprn_cpy_memcms"_h, &Simulator::SimulateCpyP},
489 {"cpypwn_cpy_memcms"_h, &Simulator::SimulateCpyP},
490 {"cpyp_cpy_memcms"_h, &Simulator::SimulateCpyP},
491 {"setp_set_memcms"_h, &Simulator::SimulateSetP},
492 {"setpn_set_memcms"_h, &Simulator::SimulateSetP},
493 {"setgp_set_memcms"_h, &Simulator::SimulateSetGP},
494 {"setgpn_set_memcms"_h, &Simulator::SimulateSetGP},
495 {"setm_set_memcms"_h, &Simulator::SimulateSetM},
496 {"setmn_set_memcms"_h, &Simulator::SimulateSetM},
497 {"setgm_set_memcms"_h, &Simulator::SimulateSetGM},
498 {"setgmn_set_memcms"_h, &Simulator::SimulateSetGM},
499 {"sete_set_memcms"_h, &Simulator::SimulateSetE},
500 {"seten_set_memcms"_h, &Simulator::SimulateSetE},
501 {"setge_set_memcms"_h, &Simulator::SimulateSetE},
502 {"setgen_set_memcms"_h, &Simulator::SimulateSetE},
mmc28ab5c57c92023-03-16 16:26:31 +0000503 {"abs_32_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
504 {"abs_64_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
505 {"cnt_32_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
506 {"cnt_64_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
507 {"ctz_32_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
508 {"ctz_64_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
509 {"smax_32_dp_2src"_h, &Simulator::SimulateSignedMinMax},
510 {"smax_64_dp_2src"_h, &Simulator::SimulateSignedMinMax},
511 {"smin_32_dp_2src"_h, &Simulator::SimulateSignedMinMax},
512 {"smin_64_dp_2src"_h, &Simulator::SimulateSignedMinMax},
513 {"smax_32_minmax_imm"_h, &Simulator::SimulateSignedMinMax},
514 {"smax_64_minmax_imm"_h, &Simulator::SimulateSignedMinMax},
515 {"smin_32_minmax_imm"_h, &Simulator::SimulateSignedMinMax},
516 {"smin_64_minmax_imm"_h, &Simulator::SimulateSignedMinMax},
517 {"umax_32_dp_2src"_h, &Simulator::SimulateUnsignedMinMax},
518 {"umax_64_dp_2src"_h, &Simulator::SimulateUnsignedMinMax},
519 {"umin_32_dp_2src"_h, &Simulator::SimulateUnsignedMinMax},
520 {"umin_64_dp_2src"_h, &Simulator::SimulateUnsignedMinMax},
521 {"umax_32u_minmax_imm"_h, &Simulator::SimulateUnsignedMinMax},
522 {"umax_64u_minmax_imm"_h, &Simulator::SimulateUnsignedMinMax},
523 {"umin_32u_minmax_imm"_h, &Simulator::SimulateUnsignedMinMax},
524 {"umin_64u_minmax_imm"_h, &Simulator::SimulateUnsignedMinMax},
mmc28af307b4a2024-06-20 14:28:41 +0100525 {"bcax_vvv16_crypto4"_h, &Simulator::SimulateNEONSHA3},
526 {"eor3_vvv16_crypto4"_h, &Simulator::SimulateNEONSHA3},
527 {"rax1_vvv2_cryptosha512_3"_h, &Simulator::SimulateNEONSHA3},
528 {"xar_vvv2_crypto3_imm6"_h, &Simulator::SimulateNEONSHA3},
mmc28aa1856a32024-06-25 14:17:35 +0100529 {"sha512h_qqv_cryptosha512_3"_h, &Simulator::SimulateSHA512},
530 {"sha512h2_qqv_cryptosha512_3"_h, &Simulator::SimulateSHA512},
531 {"sha512su0_vv2_cryptosha512_2"_h, &Simulator::SimulateSHA512},
532 {"sha512su1_vvv2_cryptosha512_3"_h, &Simulator::SimulateSHA512},
mmc28a4415fe42025-01-24 11:10:30 +0000533 {"pmullb_z_zz_q"_h, &Simulator::SimulateSVEPmull128},
534 {"pmullt_z_zz_q"_h, &Simulator::SimulateSVEPmull128},
Martyn Capewellea8fa652022-01-26 15:48:07 +0000535 };
536 return &form_to_visitor;
537}
Martyn Capewell8c691852020-07-15 18:33:15 +0100538
Chris Jones30e7bbd2024-02-15 15:05:25 +0000539// Try to access the piece of memory given by the address passed in RDI and the
Chris Jones3134e252024-02-29 13:44:20 +0000540// offset passed in RSI, using testb. If a signal is raised then the signal
541// handler should set RIP to _vixl_internal_AccessMemory_continue and RAX to
542// MemoryAccessResult::Failure. If no signal is raised then zero RAX before
Chris Jones30e7bbd2024-02-15 15:05:25 +0000543// returning.
544#ifdef VIXL_ENABLE_IMPLICIT_CHECKS
545#ifdef __x86_64__
546asm(R"(
547 .globl _vixl_internal_ReadMemory
548 _vixl_internal_ReadMemory:
549 testb (%rdi, %rsi), %al
550 xorq %rax, %rax
551 ret
Chris Jones3134e252024-02-29 13:44:20 +0000552 .globl _vixl_internal_AccessMemory_continue
553 _vixl_internal_AccessMemory_continue:
Chris Jones30e7bbd2024-02-15 15:05:25 +0000554 ret
555)");
556#else
557asm(R"(
558 .globl _vixl_internal_ReadMemory
559 _vixl_internal_ReadMemory:
560 ret
561)");
562#endif // __x86_64__
563#endif // VIXL_ENABLE_IMPLICIT_CHECKS
564
Jacob Bramleyc4ef66e2020-10-30 18:25:43 +0000565Simulator::Simulator(Decoder* decoder, FILE* stream, SimStack::Allocated stack)
566 : memory_(std::move(stack)),
Martyn Capewell15edd8f2021-03-31 13:54:10 +0100567 last_instr_(NULL),
mmc28a3c407232024-06-19 15:03:55 +0100568 cpu_features_auditor_(decoder, CPUFeatures::All()),
569 gcs_(kGCSNoStack),
570 gcs_enabled_(false) {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100571 // Ensure that shift operations act as the simulator expects.
572 VIXL_ASSERT((static_cast<int32_t>(-1) >> 1) == -1);
573 VIXL_ASSERT((static_cast<uint32_t>(-1) >> 1) == 0x7fffffff);
574
Martyn Capewelld42989c2020-11-10 14:32:56 +0000575 // Set up a placeholder pipe for CanReadMemory.
TheLastRar49d6efa2024-10-15 16:37:27 +0100576#ifndef _WIN32
Martyn Capewelld42989c2020-11-10 14:32:56 +0000577 VIXL_CHECK(pipe(placeholder_pipe_fd_) == 0);
TheLastRar49d6efa2024-10-15 16:37:27 +0100578#endif
Jacob Bramley85a9c102019-12-09 17:48:29 +0000579
Alexandre Ramesd3832962016-07-04 15:03:43 +0100580 // Set up the decoder.
581 decoder_ = decoder;
582 decoder_->AppendVisitor(this);
583
584 stream_ = stream;
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +0100585
Alexandre Ramesd3832962016-07-04 15:03:43 +0100586 print_disasm_ = new PrintDisassembler(stream_);
TatWai Chong6767df02022-03-25 11:33:54 -0700587
588 memory_.AppendMetaData(&meta_data_);
589
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +0100590 // The Simulator and Disassembler share the same available list, held by the
591 // auditor. The Disassembler only annotates instructions with features that
592 // are _not_ available, so registering the auditor should have no effect
593 // unless the simulator is about to abort (due to missing features). In
594 // practice, this means that with trace enabled, the simulator will crash just
595 // after the disassembler prints the instruction, with the missing features
596 // enumerated.
597 print_disasm_->RegisterCPUFeaturesAuditor(&cpu_features_auditor_);
598
Alexandre Ramesd3832962016-07-04 15:03:43 +0100599 SetColouredTrace(false);
600 trace_parameters_ = LOG_NONE;
601
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100602 // We have to configure the SVE vector register length before calling
603 // ResetState().
604 SetVectorLengthInBits(kZRegMinSize);
605
Alexandre Ramesd3832962016-07-04 15:03:43 +0100606 ResetState();
607
Alexandre Ramesd3832962016-07-04 15:03:43 +0100608 // Print a warning about exclusive-access instructions, but only the first
609 // time they are encountered. This warning can be silenced using
610 // SilenceExclusiveAccessWarning().
611 print_exclusive_access_warning_ = true;
Martyn Capewellcb963f72018-10-22 15:25:28 +0100612
613 guard_pages_ = false;
TatWai Chong04edf682018-12-27 16:01:02 -0800614
615 // Initialize the common state of RNDR and RNDRRS.
TheLastRardfc2ffb2024-08-15 14:30:18 +0100616 uint64_t seed = (11 + (22 << 16) + (static_cast<uint64_t>(33) << 32));
617 rand_gen_.seed(seed);
TatWai Chongb2d8d1f2019-10-21 15:19:31 -0700618
619 // Initialize all bits of pseudo predicate register to true.
620 LogicPRegister ones(pregister_all_true_);
621 ones.SetAllBits();
Chris Jonesa0a14392023-12-08 13:59:42 +0000622
623 // Initialize the debugger but disable it by default.
624 SetDebuggerEnabled(false);
625 debugger_ = std::make_unique<Debugger>(this);
Alexandre Ramesd3832962016-07-04 15:03:43 +0100626}
627
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100628void Simulator::ResetSystemRegisters() {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100629 // Reset the system registers.
630 nzcv_ = SimSystemRegister::DefaultValueFor(NZCV);
631 fpcr_ = SimSystemRegister::DefaultValueFor(FPCR);
TatWai Chong4023d7a2019-11-18 14:16:28 -0800632 ResetFFR();
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100633}
Alexandre Ramesd3832962016-07-04 15:03:43 +0100634
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100635void Simulator::ResetRegisters() {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100636 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
637 WriteXRegister(i, 0xbadbeef);
638 }
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100639 // Returning to address 0 exits the Simulator.
640 WriteLr(kEndOfSimAddress);
641}
Pierre Langlois23703a72016-08-15 17:23:39 +0100642
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100643void Simulator::ResetVRegisters() {
TatWai Chonge3d059b2019-02-27 15:04:51 -0800644 // Set SVE/FP registers to a value that is a NaN in both 32-bit and 64-bit FP.
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100645 VIXL_ASSERT((GetVectorLengthInBytes() % kDRegSizeInBytes) == 0);
646 int lane_count = GetVectorLengthInBytes() / kDRegSizeInBytes;
TatWai Chonge3d059b2019-02-27 15:04:51 -0800647 for (unsigned i = 0; i < kNumberOfZRegisters; i++) {
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100648 VIXL_ASSERT(vregisters_[i].GetSizeInBytes() == GetVectorLengthInBytes());
Jacob Bramleyfad4dff2019-07-02 17:09:11 +0100649 vregisters_[i].NotifyAccessAsZ();
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100650 for (int lane = 0; lane < lane_count; lane++) {
TatWai Chonge3d059b2019-02-27 15:04:51 -0800651 // Encode the register number and (D-sized) lane into each NaN, to
652 // make them easier to trace.
653 uint64_t nan_bits = 0x7ff0f0007f80f000 | (0x0000000100000000 * i) |
654 (0x0000000000000001 * lane);
655 VIXL_ASSERT(IsSignallingNaN(RawbitsToDouble(nan_bits & kDRegMask)));
656 VIXL_ASSERT(IsSignallingNaN(RawbitsToFloat(nan_bits & kSRegMask)));
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100657 vregisters_[i].Insert(lane, nan_bits);
TatWai Chonge3d059b2019-02-27 15:04:51 -0800658 }
Alexandre Ramesd3832962016-07-04 15:03:43 +0100659 }
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100660}
TatWai Chonge3d059b2019-02-27 15:04:51 -0800661
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100662void Simulator::ResetPRegisters() {
663 VIXL_ASSERT((GetPredicateLengthInBytes() % kHRegSizeInBytes) == 0);
664 int lane_count = GetPredicateLengthInBytes() / kHRegSizeInBytes;
665 // Ensure the register configuration fits in this bit encoding.
666 VIXL_STATIC_ASSERT(kNumberOfPRegisters <= UINT8_MAX);
667 VIXL_ASSERT(lane_count <= UINT8_MAX);
TatWai Chonge0590cc2019-03-18 16:23:59 -0700668 for (unsigned i = 0; i < kNumberOfPRegisters; i++) {
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100669 VIXL_ASSERT(pregisters_[i].GetSizeInBytes() == GetPredicateLengthInBytes());
670 for (int lane = 0; lane < lane_count; lane++) {
TatWai Chonge0590cc2019-03-18 16:23:59 -0700671 // Encode the register number and (H-sized) lane into each lane slot.
672 uint16_t bits = (0x0100 * lane) | i;
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100673 pregisters_[i].Insert(lane, bits);
TatWai Chonge0590cc2019-03-18 16:23:59 -0700674 }
675 }
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100676}
TatWai Chonge0590cc2019-03-18 16:23:59 -0700677
TatWai Chong4023d7a2019-11-18 14:16:28 -0800678void Simulator::ResetFFR() {
679 VIXL_ASSERT((GetPredicateLengthInBytes() % kHRegSizeInBytes) == 0);
680 int default_active_lanes = GetPredicateLengthInBytes() / kHRegSizeInBytes;
681 ffr_register_.Write(static_cast<uint16_t>(GetUintMask(default_active_lanes)));
682}
683
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100684void Simulator::ResetState() {
685 ResetSystemRegisters();
686 ResetRegisters();
687 ResetVRegisters();
688 ResetPRegisters();
Martyn Capewellcb963f72018-10-22 15:25:28 +0100689
Jacob Bramleyc4ef66e2020-10-30 18:25:43 +0000690 WriteSp(memory_.GetStack().GetBase());
mmc28a3c407232024-06-19 15:03:55 +0100691 ResetGCSState();
692 EnableGCSCheck();
Jacob Bramleyc4ef66e2020-10-30 18:25:43 +0000693
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100694 pc_ = NULL;
695 pc_modified_ = false;
696
697 // BTI state.
Martyn Capewellcb963f72018-10-22 15:25:28 +0100698 btype_ = DefaultBType;
699 next_btype_ = DefaultBType;
Chris Jones8eca2b72023-09-13 10:09:12 +0100700
701 meta_data_.ResetState();
Alexandre Ramesd3832962016-07-04 15:03:43 +0100702}
703
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100704void Simulator::SetVectorLengthInBits(unsigned vector_length) {
705 VIXL_ASSERT((vector_length >= kZRegMinSize) &&
706 (vector_length <= kZRegMaxSize));
Martyn Capewellc40e2882024-03-22 13:47:46 +0000707 VIXL_ASSERT(IsPowerOf2(vector_length));
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100708 vector_length_ = vector_length;
709
710 for (unsigned i = 0; i < kNumberOfZRegisters; i++) {
711 vregisters_[i].SetSizeInBytes(GetVectorLengthInBytes());
712 }
713 for (unsigned i = 0; i < kNumberOfPRegisters; i++) {
714 pregisters_[i].SetSizeInBytes(GetPredicateLengthInBytes());
715 }
716
TatWai Chong4023d7a2019-11-18 14:16:28 -0800717 ffr_register_.SetSizeInBytes(GetPredicateLengthInBytes());
718
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100719 ResetVRegisters();
720 ResetPRegisters();
TatWai Chong4023d7a2019-11-18 14:16:28 -0800721 ResetFFR();
Jacob Bramley9d06c4d2019-05-13 18:15:06 +0100722}
Alexandre Ramesd3832962016-07-04 15:03:43 +0100723
724Simulator::~Simulator() {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100725 // The decoder may outlive the simulator.
726 decoder_->RemoveVisitor(print_disasm_);
727 delete print_disasm_;
TheLastRar49d6efa2024-10-15 16:37:27 +0100728#ifndef _WIN32
Martyn Capewelld42989c2020-11-10 14:32:56 +0000729 close(placeholder_pipe_fd_[0]);
730 close(placeholder_pipe_fd_[1]);
TheLastRar49d6efa2024-10-15 16:37:27 +0100731#endif
mmc28a3c407232024-06-19 15:03:55 +0100732 if (IsAllocatedGCS(gcs_)) {
733 GetGCSManager().FreeStack(gcs_);
734 }
Alexandre Ramesd3832962016-07-04 15:03:43 +0100735}
736
737
738void Simulator::Run() {
739 // Flush any written registers before executing anything, so that
740 // manually-set registers are logged _before_ the first instruction.
741 LogAllWrittenRegisters();
742
Chris Jonesa0a14392023-12-08 13:59:42 +0000743 if (debugger_enabled_) {
744 // Slow path to check for breakpoints only if the debugger is enabled.
745 Debugger* debugger = GetDebugger();
746 while (!IsSimulationFinished()) {
747 if (debugger->IsAtBreakpoint()) {
748 fprintf(stream_, "Debugger hit breakpoint, breaking...\n");
749 debugger->Debug();
750 } else {
751 ExecuteInstruction();
752 }
753 }
754 } else {
755 while (!IsSimulationFinished()) {
756 ExecuteInstruction();
757 }
Alexandre Ramesd3832962016-07-04 15:03:43 +0100758 }
759}
760
761
762void Simulator::RunFrom(const Instruction* first) {
Jacob Bramleye79723a2016-06-07 17:50:47 +0100763 WritePc(first, NoBranchLog);
Alexandre Ramesd3832962016-07-04 15:03:43 +0100764 Run();
765}
766
767
Jacob Bramleyf5659ff2019-08-02 11:19:04 +0100768// clang-format off
Alexandre Ramesd3832962016-07-04 15:03:43 +0100769const char* Simulator::xreg_names[] = {"x0", "x1", "x2", "x3", "x4", "x5",
770 "x6", "x7", "x8", "x9", "x10", "x11",
771 "x12", "x13", "x14", "x15", "x16", "x17",
772 "x18", "x19", "x20", "x21", "x22", "x23",
773 "x24", "x25", "x26", "x27", "x28", "x29",
774 "lr", "xzr", "sp"};
775
776const char* Simulator::wreg_names[] = {"w0", "w1", "w2", "w3", "w4", "w5",
777 "w6", "w7", "w8", "w9", "w10", "w11",
778 "w12", "w13", "w14", "w15", "w16", "w17",
779 "w18", "w19", "w20", "w21", "w22", "w23",
780 "w24", "w25", "w26", "w27", "w28", "w29",
781 "w30", "wzr", "wsp"};
782
Jacob Bramley423e5422019-11-13 19:15:55 +0000783const char* Simulator::breg_names[] = {"b0", "b1", "b2", "b3", "b4", "b5",
784 "b6", "b7", "b8", "b9", "b10", "b11",
785 "b12", "b13", "b14", "b15", "b16", "b17",
786 "b18", "b19", "b20", "b21", "b22", "b23",
787 "b24", "b25", "b26", "b27", "b28", "b29",
788 "b30", "b31"};
789
Carey Williamsd8bb3572018-04-10 11:58:07 +0100790const char* Simulator::hreg_names[] = {"h0", "h1", "h2", "h3", "h4", "h5",
791 "h6", "h7", "h8", "h9", "h10", "h11",
792 "h12", "h13", "h14", "h15", "h16", "h17",
793 "h18", "h19", "h20", "h21", "h22", "h23",
794 "h24", "h25", "h26", "h27", "h28", "h29",
795 "h30", "h31"};
796
Alexandre Ramesd3832962016-07-04 15:03:43 +0100797const char* Simulator::sreg_names[] = {"s0", "s1", "s2", "s3", "s4", "s5",
798 "s6", "s7", "s8", "s9", "s10", "s11",
799 "s12", "s13", "s14", "s15", "s16", "s17",
800 "s18", "s19", "s20", "s21", "s22", "s23",
801 "s24", "s25", "s26", "s27", "s28", "s29",
802 "s30", "s31"};
803
804const char* Simulator::dreg_names[] = {"d0", "d1", "d2", "d3", "d4", "d5",
805 "d6", "d7", "d8", "d9", "d10", "d11",
806 "d12", "d13", "d14", "d15", "d16", "d17",
807 "d18", "d19", "d20", "d21", "d22", "d23",
808 "d24", "d25", "d26", "d27", "d28", "d29",
809 "d30", "d31"};
810
811const char* Simulator::vreg_names[] = {"v0", "v1", "v2", "v3", "v4", "v5",
812 "v6", "v7", "v8", "v9", "v10", "v11",
813 "v12", "v13", "v14", "v15", "v16", "v17",
814 "v18", "v19", "v20", "v21", "v22", "v23",
815 "v24", "v25", "v26", "v27", "v28", "v29",
816 "v30", "v31"};
817
TatWai Chong72d2e562019-05-16 11:22:22 -0700818const char* Simulator::zreg_names[] = {"z0", "z1", "z2", "z3", "z4", "z5",
819 "z6", "z7", "z8", "z9", "z10", "z11",
820 "z12", "z13", "z14", "z15", "z16", "z17",
821 "z18", "z19", "z20", "z21", "z22", "z23",
822 "z24", "z25", "z26", "z27", "z28", "z29",
823 "z30", "z31"};
824
Jacob Bramleyf5659ff2019-08-02 11:19:04 +0100825const char* Simulator::preg_names[] = {"p0", "p1", "p2", "p3", "p4", "p5",
826 "p6", "p7", "p8", "p9", "p10", "p11",
827 "p12", "p13", "p14", "p15"};
828// clang-format on
829
Alexandre Ramesd3832962016-07-04 15:03:43 +0100830
831const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100832 // If the code represents the stack pointer, index the name after zr.
Jacob Bramley423e5422019-11-13 19:15:55 +0000833 if ((code == kSPRegInternalCode) ||
834 ((code == kZeroRegCode) && (mode == Reg31IsStackPointer))) {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100835 code = kZeroRegCode + 1;
836 }
Jacob Bramley423e5422019-11-13 19:15:55 +0000837 VIXL_ASSERT(code < ArrayLength(wreg_names));
Alexandre Ramesd3832962016-07-04 15:03:43 +0100838 return wreg_names[code];
839}
840
841
842const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100843 // If the code represents the stack pointer, index the name after zr.
Jacob Bramley423e5422019-11-13 19:15:55 +0000844 if ((code == kSPRegInternalCode) ||
845 ((code == kZeroRegCode) && (mode == Reg31IsStackPointer))) {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100846 code = kZeroRegCode + 1;
847 }
Jacob Bramley423e5422019-11-13 19:15:55 +0000848 VIXL_ASSERT(code < ArrayLength(xreg_names));
Alexandre Ramesd3832962016-07-04 15:03:43 +0100849 return xreg_names[code];
850}
851
852
Jacob Bramley423e5422019-11-13 19:15:55 +0000853const char* Simulator::BRegNameForCode(unsigned code) {
854 VIXL_ASSERT(code < kNumberOfVRegisters);
855 return breg_names[code];
856}
857
858
Carey Williamsd8bb3572018-04-10 11:58:07 +0100859const char* Simulator::HRegNameForCode(unsigned code) {
Jacob Bramleycf93ad52019-04-15 16:00:22 +0100860 VIXL_ASSERT(code < kNumberOfVRegisters);
Carey Williamsd8bb3572018-04-10 11:58:07 +0100861 return hreg_names[code];
862}
863
864
Alexandre Ramesd3832962016-07-04 15:03:43 +0100865const char* Simulator::SRegNameForCode(unsigned code) {
Jacob Bramleycf93ad52019-04-15 16:00:22 +0100866 VIXL_ASSERT(code < kNumberOfVRegisters);
Alexandre Ramesd3832962016-07-04 15:03:43 +0100867 return sreg_names[code];
868}
869
870
871const char* Simulator::DRegNameForCode(unsigned code) {
Jacob Bramleycf93ad52019-04-15 16:00:22 +0100872 VIXL_ASSERT(code < kNumberOfVRegisters);
Alexandre Ramesd3832962016-07-04 15:03:43 +0100873 return dreg_names[code];
874}
875
876
877const char* Simulator::VRegNameForCode(unsigned code) {
878 VIXL_ASSERT(code < kNumberOfVRegisters);
879 return vreg_names[code];
880}
881
882
TatWai Chong72d2e562019-05-16 11:22:22 -0700883const char* Simulator::ZRegNameForCode(unsigned code) {
884 VIXL_ASSERT(code < kNumberOfZRegisters);
885 return zreg_names[code];
886}
887
888
Jacob Bramleyf5659ff2019-08-02 11:19:04 +0100889const char* Simulator::PRegNameForCode(unsigned code) {
890 VIXL_ASSERT(code < kNumberOfPRegisters);
891 return preg_names[code];
892}
893
Martyn Capewell7fd6fd52019-12-06 14:50:15 +0000894SimVRegister Simulator::ExpandToSimVRegister(const SimPRegister& pg) {
895 SimVRegister ones, result;
896 dup_immediate(kFormatVnB, ones, 0xff);
897 mov_zeroing(kFormatVnB, result, pg, ones);
898 return result;
899}
900
TatWai Chong47c26842020-02-10 01:51:32 -0800901void Simulator::ExtractFromSimVRegister(VectorFormat vform,
902 SimPRegister& pd,
903 SimVRegister vreg) {
Martyn Capewell7fd6fd52019-12-06 14:50:15 +0000904 SimVRegister zero;
905 dup_immediate(kFormatVnB, zero, 0);
906 SVEIntCompareVectorsHelper(ne,
TatWai Chong47c26842020-02-10 01:51:32 -0800907 vform,
Martyn Capewell7fd6fd52019-12-06 14:50:15 +0000908 pd,
909 GetPTrue(),
910 vreg,
911 zero,
912 false,
913 LeaveFlags);
914}
Jacob Bramleyf5659ff2019-08-02 11:19:04 +0100915
Alexandre Ramesd3832962016-07-04 15:03:43 +0100916#define COLOUR(colour_code) "\033[0;" colour_code "m"
917#define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m"
Jacob Bramleye79723a2016-06-07 17:50:47 +0100918#define COLOUR_HIGHLIGHT "\033[43m"
Alexandre Ramesd3832962016-07-04 15:03:43 +0100919#define NORMAL ""
920#define GREY "30"
921#define RED "31"
922#define GREEN "32"
923#define YELLOW "33"
924#define BLUE "34"
925#define MAGENTA "35"
926#define CYAN "36"
927#define WHITE "37"
928void Simulator::SetColouredTrace(bool value) {
929 coloured_trace_ = value;
930
931 clr_normal = value ? COLOUR(NORMAL) : "";
932 clr_flag_name = value ? COLOUR_BOLD(WHITE) : "";
933 clr_flag_value = value ? COLOUR(NORMAL) : "";
934 clr_reg_name = value ? COLOUR_BOLD(CYAN) : "";
935 clr_reg_value = value ? COLOUR(CYAN) : "";
936 clr_vreg_name = value ? COLOUR_BOLD(MAGENTA) : "";
937 clr_vreg_value = value ? COLOUR(MAGENTA) : "";
Jacob Bramleyf5659ff2019-08-02 11:19:04 +0100938 clr_preg_name = value ? COLOUR_BOLD(GREEN) : "";
939 clr_preg_value = value ? COLOUR(GREEN) : "";
Alexandre Ramesd3832962016-07-04 15:03:43 +0100940 clr_memory_address = value ? COLOUR_BOLD(BLUE) : "";
941 clr_warning = value ? COLOUR_BOLD(YELLOW) : "";
942 clr_warning_message = value ? COLOUR(YELLOW) : "";
943 clr_printf = value ? COLOUR(GREEN) : "";
Jacob Bramleye79723a2016-06-07 17:50:47 +0100944 clr_branch_marker = value ? COLOUR(GREY) COLOUR_HIGHLIGHT : "";
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +0100945
946 if (value) {
947 print_disasm_->SetCPUFeaturesPrefix("// Needs: " COLOUR_BOLD(RED));
948 print_disasm_->SetCPUFeaturesSuffix(COLOUR(NORMAL));
949 } else {
950 print_disasm_->SetCPUFeaturesPrefix("// Needs: ");
951 print_disasm_->SetCPUFeaturesSuffix("");
952 }
Alexandre Ramesd3832962016-07-04 15:03:43 +0100953}
954
955
956void Simulator::SetTraceParameters(int parameters) {
957 bool disasm_before = trace_parameters_ & LOG_DISASM;
958 trace_parameters_ = parameters;
959 bool disasm_after = trace_parameters_ & LOG_DISASM;
960
961 if (disasm_before != disasm_after) {
962 if (disasm_after) {
963 decoder_->InsertVisitorBefore(print_disasm_, this);
964 } else {
965 decoder_->RemoveVisitor(print_disasm_);
966 }
967 }
968}
969
Alexandre Ramesd3832962016-07-04 15:03:43 +0100970// Helpers ---------------------------------------------------------------------
971uint64_t Simulator::AddWithCarry(unsigned reg_size,
972 bool set_flags,
973 uint64_t left,
974 uint64_t right,
975 int carry_in) {
Martyn Capewellc4b56bb2020-10-14 15:45:14 +0100976 std::pair<uint64_t, uint8_t> result_and_flags =
977 AddWithCarry(reg_size, left, right, carry_in);
978 if (set_flags) {
979 uint8_t flags = result_and_flags.second;
980 ReadNzcv().SetN((flags >> 3) & 1);
981 ReadNzcv().SetZ((flags >> 2) & 1);
982 ReadNzcv().SetC((flags >> 1) & 1);
983 ReadNzcv().SetV((flags >> 0) & 1);
984 LogSystemRegister(NZCV);
985 }
986 return result_and_flags.first;
987}
988
989std::pair<uint64_t, uint8_t> Simulator::AddWithCarry(unsigned reg_size,
990 uint64_t left,
991 uint64_t right,
992 int carry_in) {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100993 VIXL_ASSERT((carry_in == 0) || (carry_in == 1));
994 VIXL_ASSERT((reg_size == kXRegSize) || (reg_size == kWRegSize));
995
996 uint64_t max_uint = (reg_size == kWRegSize) ? kWMaxUInt : kXMaxUInt;
997 uint64_t reg_mask = (reg_size == kWRegSize) ? kWRegMask : kXRegMask;
998 uint64_t sign_mask = (reg_size == kWRegSize) ? kWSignMask : kXSignMask;
999
1000 left &= reg_mask;
1001 right &= reg_mask;
1002 uint64_t result = (left + right + carry_in) & reg_mask;
1003
Martyn Capewellc4b56bb2020-10-14 15:45:14 +01001004 // NZCV bits, ordered N in bit 3 to V in bit 0.
1005 uint8_t nzcv = CalcNFlag(result, reg_size) ? 8 : 0;
1006 nzcv |= CalcZFlag(result) ? 4 : 0;
Alexandre Ramesd3832962016-07-04 15:03:43 +01001007
Martyn Capewellc4b56bb2020-10-14 15:45:14 +01001008 // Compute the C flag by comparing the result to the max unsigned integer.
1009 uint64_t max_uint_2op = max_uint - carry_in;
1010 bool C = (left > max_uint_2op) || ((max_uint_2op - left) < right);
1011 nzcv |= C ? 2 : 0;
Alexandre Ramesd3832962016-07-04 15:03:43 +01001012
Martyn Capewellc4b56bb2020-10-14 15:45:14 +01001013 // Overflow iff the sign bit is the same for the two inputs and different
1014 // for the result.
1015 uint64_t left_sign = left & sign_mask;
1016 uint64_t right_sign = right & sign_mask;
1017 uint64_t result_sign = result & sign_mask;
1018 bool V = (left_sign == right_sign) && (left_sign != result_sign);
1019 nzcv |= V ? 1 : 0;
Alexandre Ramesd3832962016-07-04 15:03:43 +01001020
Martyn Capewellc4b56bb2020-10-14 15:45:14 +01001021 return std::make_pair(result, nzcv);
Alexandre Ramesd3832962016-07-04 15:03:43 +01001022}
1023
TatWai Chongcad27c52021-03-10 11:26:50 -08001024using vixl_uint128_t = std::pair<uint64_t, uint64_t>;
1025
1026vixl_uint128_t Simulator::Add128(vixl_uint128_t x, vixl_uint128_t y) {
1027 std::pair<uint64_t, uint8_t> sum_lo =
1028 AddWithCarry(kXRegSize, x.second, y.second, 0);
1029 int carry_in = (sum_lo.second & 0x2) >> 1; // C flag in NZCV result.
1030 std::pair<uint64_t, uint8_t> sum_hi =
1031 AddWithCarry(kXRegSize, x.first, y.first, carry_in);
1032 return std::make_pair(sum_hi.first, sum_lo.first);
1033}
1034
mmc28a5a2144d2024-02-23 17:23:23 +00001035vixl_uint128_t Simulator::Lsl128(vixl_uint128_t x, unsigned shift) const {
1036 VIXL_ASSERT(shift <= 64);
1037 if (shift == 0) return x;
1038 if (shift == 64) return std::make_pair(x.second, 0);
1039 uint64_t lo = x.second << shift;
1040 uint64_t hi = (x.first << shift) | (x.second >> (64 - shift));
1041 return std::make_pair(hi, lo);
1042}
1043
1044vixl_uint128_t Simulator::Eor128(vixl_uint128_t x, vixl_uint128_t y) const {
1045 return std::make_pair(x.first ^ y.first, x.second ^ y.second);
1046}
1047
TatWai Chongcad27c52021-03-10 11:26:50 -08001048vixl_uint128_t Simulator::Neg128(vixl_uint128_t x) {
1049 // Negate the integer value. Throw an assertion when the input is INT128_MIN.
1050 VIXL_ASSERT((x.first != GetSignMask(64)) || (x.second != 0));
1051 x.first = ~x.first;
1052 x.second = ~x.second;
1053 return Add128(x, {0, 1});
1054}
1055
1056vixl_uint128_t Simulator::Mul64(uint64_t x, uint64_t y) {
1057 bool neg_result = false;
1058 if ((x >> 63) == 1) {
TheLastRar49d6efa2024-10-15 16:37:27 +01001059 x = UnsignedNegate(x);
TatWai Chongcad27c52021-03-10 11:26:50 -08001060 neg_result = !neg_result;
1061 }
1062 if ((y >> 63) == 1) {
TheLastRar49d6efa2024-10-15 16:37:27 +01001063 y = UnsignedNegate(y);
TatWai Chongcad27c52021-03-10 11:26:50 -08001064 neg_result = !neg_result;
1065 }
1066
1067 uint64_t x_lo = x & 0xffffffff;
1068 uint64_t x_hi = x >> 32;
1069 uint64_t y_lo = y & 0xffffffff;
1070 uint64_t y_hi = y >> 32;
1071
1072 uint64_t t1 = x_lo * y_hi;
1073 uint64_t t2 = x_hi * y_lo;
1074 vixl_uint128_t a = std::make_pair(0, x_lo * y_lo);
1075 vixl_uint128_t b = std::make_pair(t1 >> 32, t1 << 32);
1076 vixl_uint128_t c = std::make_pair(t2 >> 32, t2 << 32);
1077 vixl_uint128_t d = std::make_pair(x_hi * y_hi, 0);
1078
1079 vixl_uint128_t result = Add128(a, b);
1080 result = Add128(result, c);
1081 result = Add128(result, d);
TheLastRar49d6efa2024-10-15 16:37:27 +01001082 return neg_result ? std::make_pair(UnsignedNegate(result.first) - 1,
1083 UnsignedNegate(result.second))
TatWai Chongcad27c52021-03-10 11:26:50 -08001084 : result;
1085}
1086
mmc28a5a2144d2024-02-23 17:23:23 +00001087vixl_uint128_t Simulator::PolynomialMult128(uint64_t op1,
1088 uint64_t op2,
1089 int lane_size_in_bits) const {
1090 VIXL_ASSERT(static_cast<unsigned>(lane_size_in_bits) <= kDRegSize);
1091 vixl_uint128_t result = std::make_pair(0, 0);
1092 vixl_uint128_t op2q = std::make_pair(0, op2);
1093 for (int i = 0; i < lane_size_in_bits; i++) {
1094 if ((op1 >> i) & 1) {
1095 result = Eor128(result, Lsl128(op2q, i));
1096 }
1097 }
1098 return result;
1099}
1100
Alexandre Ramesd3832962016-07-04 15:03:43 +01001101int64_t Simulator::ShiftOperand(unsigned reg_size,
Martyn Capewell3bf2d162020-02-17 15:04:36 +00001102 uint64_t uvalue,
Alexandre Ramesd3832962016-07-04 15:03:43 +01001103 Shift shift_type,
Alexandre Rames868bfc42016-07-19 17:10:48 +01001104 unsigned amount) const {
TatWai Chong29a0c432019-11-06 22:20:44 -08001105 VIXL_ASSERT((reg_size == kBRegSize) || (reg_size == kHRegSize) ||
1106 (reg_size == kSRegSize) || (reg_size == kDRegSize));
Martyn Capewell3bf2d162020-02-17 15:04:36 +00001107 if (amount > 0) {
1108 uint64_t mask = GetUintMask(reg_size);
1109 bool is_negative = (uvalue & GetSignMask(reg_size)) != 0;
1110 // The behavior is undefined in c++ if the shift amount greater than or
1111 // equal to the register lane size. Work out the shifted result based on
Josh Sorefb43d6ef2022-08-03 12:47:14 -04001112 // architectural behavior before performing the c++ type shift operations.
Martyn Capewell3bf2d162020-02-17 15:04:36 +00001113 switch (shift_type) {
1114 case LSL:
1115 if (amount >= reg_size) {
1116 return UINT64_C(0);
1117 }
1118 uvalue <<= amount;
1119 break;
1120 case LSR:
1121 if (amount >= reg_size) {
1122 return UINT64_C(0);
1123 }
1124 uvalue >>= amount;
1125 break;
1126 case ASR:
1127 if (amount >= reg_size) {
1128 return is_negative ? ~UINT64_C(0) : UINT64_C(0);
1129 }
1130 uvalue >>= amount;
1131 if (is_negative) {
1132 // Simulate sign-extension to 64 bits.
1133 uvalue |= ~UINT64_C(0) << (reg_size - amount);
1134 }
1135 break;
1136 case ROR: {
1137 uvalue = RotateRight(uvalue, amount, reg_size);
1138 break;
TatWai Chong29a0c432019-11-06 22:20:44 -08001139 }
Martyn Capewell3bf2d162020-02-17 15:04:36 +00001140 default:
1141 VIXL_UNIMPLEMENTED();
1142 return 0;
Alexandre Ramesd3832962016-07-04 15:03:43 +01001143 }
Martyn Capewell3bf2d162020-02-17 15:04:36 +00001144 uvalue &= mask;
Alexandre Ramesd3832962016-07-04 15:03:43 +01001145 }
Martyn Capewell5b24fb32016-11-02 18:52:55 +00001146
1147 int64_t result;
1148 memcpy(&result, &uvalue, sizeof(result));
1149 return result;
Alexandre Ramesd3832962016-07-04 15:03:43 +01001150}
1151
1152
1153int64_t Simulator::ExtendValue(unsigned reg_size,
1154 int64_t value,
1155 Extend extend_type,
Alexandre Rames868bfc42016-07-19 17:10:48 +01001156 unsigned left_shift) const {
Alexandre Ramesd3832962016-07-04 15:03:43 +01001157 switch (extend_type) {
1158 case UXTB:
1159 value &= kByteMask;
1160 break;
1161 case UXTH:
1162 value &= kHalfWordMask;
1163 break;
1164 case UXTW:
1165 value &= kWordMask;
1166 break;
1167 case SXTB:
Martyn Capewell5b24fb32016-11-02 18:52:55 +00001168 value &= kByteMask;
1169 if ((value & 0x80) != 0) {
1170 value |= ~UINT64_C(0) << 8;
1171 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01001172 break;
1173 case SXTH:
Martyn Capewell5b24fb32016-11-02 18:52:55 +00001174 value &= kHalfWordMask;
1175 if ((value & 0x8000) != 0) {
1176 value |= ~UINT64_C(0) << 16;
1177 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01001178 break;
1179 case SXTW:
Martyn Capewell5b24fb32016-11-02 18:52:55 +00001180 value &= kWordMask;
1181 if ((value & 0x80000000) != 0) {
1182 value |= ~UINT64_C(0) << 32;
1183 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01001184 break;
1185 case UXTX:
1186 case SXTX:
1187 break;
1188 default:
1189 VIXL_UNREACHABLE();
1190 }
Martyn Capewell5b24fb32016-11-02 18:52:55 +00001191 return ShiftOperand(reg_size, value, LSL, left_shift);
Alexandre Ramesd3832962016-07-04 15:03:43 +01001192}
1193
1194
1195void Simulator::FPCompare(double val0, double val1, FPTrapFlags trap) {
1196 AssertSupportedFPCR();
1197
1198 // TODO: This assumes that the C++ implementation handles comparisons in the
1199 // way that we expect (as per AssertSupportedFPCR()).
1200 bool process_exception = false;
Jacob Bramleyca789742018-09-13 14:25:46 +01001201 if ((IsNaN(val0) != 0) || (IsNaN(val1) != 0)) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01001202 ReadNzcv().SetRawValue(FPUnorderedFlag);
1203 if (IsSignallingNaN(val0) || IsSignallingNaN(val1) ||
1204 (trap == EnableTrap)) {
1205 process_exception = true;
1206 }
1207 } else if (val0 < val1) {
1208 ReadNzcv().SetRawValue(FPLessThanFlag);
1209 } else if (val0 > val1) {
1210 ReadNzcv().SetRawValue(FPGreaterThanFlag);
1211 } else if (val0 == val1) {
1212 ReadNzcv().SetRawValue(FPEqualFlag);
1213 } else {
1214 VIXL_UNREACHABLE();
1215 }
1216 LogSystemRegister(NZCV);
1217 if (process_exception) FPProcessException();
1218}
1219
1220
Alexandre Rames868bfc42016-07-19 17:10:48 +01001221uint64_t Simulator::ComputeMemOperandAddress(const MemOperand& mem_op) const {
1222 VIXL_ASSERT(mem_op.IsValid());
1223 int64_t base = ReadRegister<int64_t>(mem_op.GetBaseRegister());
1224 if (mem_op.IsImmediateOffset()) {
1225 return base + mem_op.GetOffset();
1226 } else {
1227 VIXL_ASSERT(mem_op.GetRegisterOffset().IsValid());
1228 int64_t offset = ReadRegister<int64_t>(mem_op.GetRegisterOffset());
Pierre Langloisf5348ce2016-09-22 11:15:35 +01001229 unsigned shift_amount = mem_op.GetShiftAmount();
Alexandre Rames868bfc42016-07-19 17:10:48 +01001230 if (mem_op.GetShift() != NO_SHIFT) {
1231 offset = ShiftOperand(kXRegSize, offset, mem_op.GetShift(), shift_amount);
1232 }
1233 if (mem_op.GetExtend() != NO_EXTEND) {
1234 offset = ExtendValue(kXRegSize, offset, mem_op.GetExtend(), shift_amount);
1235 }
1236 return static_cast<uint64_t>(base + offset);
1237 }
1238}
1239
1240
Alexandre Ramesd3832962016-07-04 15:03:43 +01001241Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatForSize(
1242 unsigned reg_size, unsigned lane_size) {
1243 VIXL_ASSERT(reg_size >= lane_size);
1244
1245 uint32_t format = 0;
1246 if (reg_size != lane_size) {
1247 switch (reg_size) {
1248 default:
1249 VIXL_UNREACHABLE();
1250 break;
1251 case kQRegSizeInBytes:
1252 format = kPrintRegAsQVector;
1253 break;
1254 case kDRegSizeInBytes:
1255 format = kPrintRegAsDVector;
1256 break;
1257 }
1258 }
1259
1260 switch (lane_size) {
1261 default:
1262 VIXL_UNREACHABLE();
1263 break;
1264 case kQRegSizeInBytes:
1265 format |= kPrintReg1Q;
1266 break;
1267 case kDRegSizeInBytes:
1268 format |= kPrintReg1D;
1269 break;
1270 case kSRegSizeInBytes:
1271 format |= kPrintReg1S;
1272 break;
1273 case kHRegSizeInBytes:
1274 format |= kPrintReg1H;
1275 break;
1276 case kBRegSizeInBytes:
1277 format |= kPrintReg1B;
1278 break;
1279 }
1280 // These sizes would be duplicate case labels.
1281 VIXL_STATIC_ASSERT(kXRegSizeInBytes == kDRegSizeInBytes);
1282 VIXL_STATIC_ASSERT(kWRegSizeInBytes == kSRegSizeInBytes);
1283 VIXL_STATIC_ASSERT(kPrintXReg == kPrintReg1D);
1284 VIXL_STATIC_ASSERT(kPrintWReg == kPrintReg1S);
1285
1286 return static_cast<PrintRegisterFormat>(format);
1287}
1288
1289
1290Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormat(
1291 VectorFormat vform) {
1292 switch (vform) {
1293 default:
1294 VIXL_UNREACHABLE();
1295 return kPrintReg16B;
1296 case kFormat16B:
1297 return kPrintReg16B;
1298 case kFormat8B:
1299 return kPrintReg8B;
1300 case kFormat8H:
1301 return kPrintReg8H;
1302 case kFormat4H:
1303 return kPrintReg4H;
1304 case kFormat4S:
1305 return kPrintReg4S;
1306 case kFormat2S:
1307 return kPrintReg2S;
1308 case kFormat2D:
1309 return kPrintReg2D;
1310 case kFormat1D:
1311 return kPrintReg1D;
1312
1313 case kFormatB:
1314 return kPrintReg1B;
1315 case kFormatH:
1316 return kPrintReg1H;
1317 case kFormatS:
1318 return kPrintReg1S;
1319 case kFormatD:
1320 return kPrintReg1D;
Jacob Bramleye668b202019-08-14 17:57:34 +01001321
1322 case kFormatVnB:
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001323 return kPrintRegVnB;
Jacob Bramleye668b202019-08-14 17:57:34 +01001324 case kFormatVnH:
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001325 return kPrintRegVnH;
Jacob Bramleye668b202019-08-14 17:57:34 +01001326 case kFormatVnS:
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001327 return kPrintRegVnS;
Jacob Bramleye668b202019-08-14 17:57:34 +01001328 case kFormatVnD:
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001329 return kPrintRegVnD;
Alexandre Ramesd3832962016-07-04 15:03:43 +01001330 }
1331}
1332
1333
1334Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatFP(
1335 VectorFormat vform) {
1336 switch (vform) {
1337 default:
1338 VIXL_UNREACHABLE();
1339 return kPrintReg16B;
Carey Williamsd8bb3572018-04-10 11:58:07 +01001340 case kFormat8H:
1341 return kPrintReg8HFP;
1342 case kFormat4H:
1343 return kPrintReg4HFP;
Alexandre Ramesd3832962016-07-04 15:03:43 +01001344 case kFormat4S:
1345 return kPrintReg4SFP;
1346 case kFormat2S:
1347 return kPrintReg2SFP;
1348 case kFormat2D:
1349 return kPrintReg2DFP;
1350 case kFormat1D:
1351 return kPrintReg1DFP;
Carey Williamsd8bb3572018-04-10 11:58:07 +01001352 case kFormatH:
1353 return kPrintReg1HFP;
Alexandre Ramesd3832962016-07-04 15:03:43 +01001354 case kFormatS:
1355 return kPrintReg1SFP;
1356 case kFormatD:
1357 return kPrintReg1DFP;
1358 }
1359}
1360
Jacob Bramley423e5422019-11-13 19:15:55 +00001361void Simulator::PrintRegisters() {
Alexandre Ramesd3832962016-07-04 15:03:43 +01001362 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
Jacob Bramley423e5422019-11-13 19:15:55 +00001363 if (i == kSpRegCode) i = kSPRegInternalCode;
1364 PrintRegister(i);
Alexandre Ramesd3832962016-07-04 15:03:43 +01001365 }
1366}
1367
Jacob Bramley423e5422019-11-13 19:15:55 +00001368void Simulator::PrintVRegisters() {
1369 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
1370 PrintVRegister(i);
1371 }
1372}
1373
1374void Simulator::PrintZRegisters() {
1375 for (unsigned i = 0; i < kNumberOfZRegisters; i++) {
1376 PrintZRegister(i);
1377 }
1378}
1379
1380void Simulator::PrintWrittenRegisters() {
1381 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
1382 if (registers_[i].WrittenSinceLastLog()) {
1383 if (i == kSpRegCode) i = kSPRegInternalCode;
1384 PrintRegister(i);
1385 }
1386 }
1387}
Alexandre Ramesd3832962016-07-04 15:03:43 +01001388
1389void Simulator::PrintWrittenVRegisters() {
Jacob Bramleyfad4dff2019-07-02 17:09:11 +01001390 bool has_sve = GetCPUFeatures()->Has(CPUFeatures::kSVE);
Alexandre Ramesd3832962016-07-04 15:03:43 +01001391 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
Jacob Bramleyfad4dff2019-07-02 17:09:11 +01001392 if (vregisters_[i].WrittenSinceLastLog()) {
1393 // Z registers are initialised in the constructor before the user can
1394 // configure the CPU features, so we must also check for SVE here.
1395 if (vregisters_[i].AccessedAsZSinceLastLog() && has_sve) {
1396 PrintZRegister(i);
1397 } else {
Jacob Bramley423e5422019-11-13 19:15:55 +00001398 PrintVRegister(i);
Jacob Bramleyfad4dff2019-07-02 17:09:11 +01001399 }
1400 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01001401 }
1402}
1403
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001404void Simulator::PrintWrittenPRegisters() {
1405 // P registers are initialised in the constructor before the user can
1406 // configure the CPU features, so we must check for SVE here.
1407 if (!GetCPUFeatures()->Has(CPUFeatures::kSVE)) return;
1408 for (unsigned i = 0; i < kNumberOfPRegisters; i++) {
1409 if (pregisters_[i].WrittenSinceLastLog()) {
1410 PrintPRegister(i);
1411 }
1412 }
Jacob Bramley0d754e92020-06-18 10:59:09 +01001413 if (ReadFFR().WrittenSinceLastLog()) PrintFFR();
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001414}
1415
Alexandre Ramesd3832962016-07-04 15:03:43 +01001416void Simulator::PrintSystemRegisters() {
1417 PrintSystemRegister(NZCV);
1418 PrintSystemRegister(FPCR);
1419}
1420
Jacob Bramley423e5422019-11-13 19:15:55 +00001421void Simulator::PrintRegisterValue(const uint8_t* value,
1422 int value_size,
1423 PrintRegisterFormat format) {
1424 int print_width = GetPrintRegSizeInBytes(format);
1425 VIXL_ASSERT(print_width <= value_size);
1426 for (int i = value_size - 1; i >= print_width; i--) {
1427 // Pad with spaces so that values align vertically.
Alexandre Ramesd3832962016-07-04 15:03:43 +01001428 fprintf(stream_, " ");
Jacob Bramley423e5422019-11-13 19:15:55 +00001429 // If we aren't explicitly printing a partial value, ensure that the
1430 // unprinted bits are zero.
1431 VIXL_ASSERT(((format & kPrintRegPartial) != 0) || (value[i] == 0));
Alexandre Ramesd3832962016-07-04 15:03:43 +01001432 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01001433 fprintf(stream_, "0x");
Jacob Bramley423e5422019-11-13 19:15:55 +00001434 for (int i = print_width - 1; i >= 0; i--) {
1435 fprintf(stream_, "%02x", value[i]);
Alexandre Ramesd3832962016-07-04 15:03:43 +01001436 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01001437}
1438
Jacob Bramley423e5422019-11-13 19:15:55 +00001439void Simulator::PrintRegisterValueFPAnnotations(const uint8_t* value,
1440 uint16_t lane_mask,
1441 PrintRegisterFormat format) {
1442 VIXL_ASSERT((format & kPrintRegAsFP) != 0);
1443 int lane_size = GetPrintRegLaneSizeInBytes(format);
1444 fprintf(stream_, " (");
1445 bool last_inactive = false;
1446 const char* sep = "";
1447 for (int i = GetPrintRegLaneCount(format) - 1; i >= 0; i--, sep = ", ") {
1448 bool access = (lane_mask & (1 << (i * lane_size))) != 0;
1449 if (access) {
1450 // Read the lane as a double, so we can format all FP types in the same
1451 // way. We squash NaNs, and a double can exactly represent any other value
1452 // that the smaller types can represent, so this is lossless.
1453 double element;
1454 switch (lane_size) {
1455 case kHRegSizeInBytes: {
1456 Float16 element_fp16;
1457 VIXL_STATIC_ASSERT(sizeof(element_fp16) == kHRegSizeInBytes);
1458 memcpy(&element_fp16, &value[i * lane_size], sizeof(element_fp16));
1459 element = FPToDouble(element_fp16, kUseDefaultNaN);
1460 break;
1461 }
1462 case kSRegSizeInBytes: {
1463 float element_fp32;
1464 memcpy(&element_fp32, &value[i * lane_size], sizeof(element_fp32));
1465 element = static_cast<double>(element_fp32);
1466 break;
1467 }
1468 case kDRegSizeInBytes: {
1469 memcpy(&element, &value[i * lane_size], sizeof(element));
1470 break;
1471 }
1472 default:
1473 VIXL_UNREACHABLE();
1474 fprintf(stream_, "{UnknownFPValue}");
1475 continue;
1476 }
1477 if (IsNaN(element)) {
1478 // The fprintf behaviour for NaNs is implementation-defined. Always
1479 // print "nan", so that traces are consistent.
1480 fprintf(stream_, "%s%snan%s", sep, clr_vreg_value, clr_normal);
1481 } else {
1482 fprintf(stream_,
1483 "%s%s%#.4g%s",
1484 sep,
1485 clr_vreg_value,
1486 element,
1487 clr_normal);
1488 }
1489 last_inactive = false;
1490 } else if (!last_inactive) {
1491 // Replace each contiguous sequence of inactive lanes with "...".
1492 fprintf(stream_, "%s...", sep);
1493 last_inactive = true;
1494 }
1495 }
1496 fprintf(stream_, ")");
1497}
1498
1499void Simulator::PrintRegister(int code,
1500 PrintRegisterFormat format,
1501 const char* suffix) {
1502 VIXL_ASSERT((static_cast<unsigned>(code) < kNumberOfRegisters) ||
1503 (static_cast<unsigned>(code) == kSPRegInternalCode));
1504 VIXL_ASSERT((format & kPrintRegAsVectorMask) == kPrintRegAsScalar);
1505 VIXL_ASSERT((format & kPrintRegAsFP) == 0);
1506
1507 SimRegister* reg;
1508 SimRegister zero;
1509 if (code == kZeroRegCode) {
1510 reg = &zero;
1511 } else {
1512 // registers_[31] holds the SP.
1513 VIXL_STATIC_ASSERT((kSPRegInternalCode % kNumberOfRegisters) == 31);
1514 reg = &registers_[code % kNumberOfRegisters];
1515 }
1516
1517 // We trace register writes as whole register values, implying that any
1518 // unprinted bits are all zero:
1519 // "# x{code}: 0x{-----value----}"
1520 // "# w{code}: 0x{-value}"
1521 // Stores trace partial register values, implying nothing about the unprinted
1522 // bits:
1523 // "# x{code}<63:0>: 0x{-----value----}"
1524 // "# x{code}<31:0>: 0x{-value}"
1525 // "# x{code}<15:0>: 0x{--}"
1526 // "# x{code}<7:0>: 0x{}"
1527
1528 bool is_partial = (format & kPrintRegPartial) != 0;
1529 unsigned print_reg_size = GetPrintRegSizeInBits(format);
1530 std::stringstream name;
1531 if (is_partial) {
1532 name << XRegNameForCode(code) << GetPartialRegSuffix(format);
1533 } else {
1534 // Notify the register that it has been logged, but only if we're printing
1535 // all of it.
1536 reg->NotifyRegisterLogged();
1537 switch (print_reg_size) {
1538 case kWRegSize:
1539 name << WRegNameForCode(code);
1540 break;
1541 case kXRegSize:
1542 name << XRegNameForCode(code);
1543 break;
1544 default:
1545 VIXL_UNREACHABLE();
1546 return;
1547 }
1548 }
1549
1550 fprintf(stream_,
1551 "# %s%*s: %s",
1552 clr_reg_name,
1553 kPrintRegisterNameFieldWidth,
1554 name.str().c_str(),
1555 clr_reg_value);
1556 PrintRegisterValue(*reg, format);
1557 fprintf(stream_, "%s%s", clr_normal, suffix);
1558}
1559
1560void Simulator::PrintVRegister(int code,
1561 PrintRegisterFormat format,
1562 const char* suffix) {
1563 VIXL_ASSERT(static_cast<unsigned>(code) < kNumberOfVRegisters);
1564 VIXL_ASSERT(((format & kPrintRegAsVectorMask) == kPrintRegAsScalar) ||
1565 ((format & kPrintRegAsVectorMask) == kPrintRegAsDVector) ||
1566 ((format & kPrintRegAsVectorMask) == kPrintRegAsQVector));
1567
1568 // We trace register writes as whole register values, implying that any
1569 // unprinted bits are all zero:
1570 // "# v{code}: 0x{-------------value------------}"
1571 // "# d{code}: 0x{-----value----}"
1572 // "# s{code}: 0x{-value}"
1573 // "# h{code}: 0x{--}"
1574 // "# b{code}: 0x{}"
1575 // Stores trace partial register values, implying nothing about the unprinted
1576 // bits:
1577 // "# v{code}<127:0>: 0x{-------------value------------}"
1578 // "# v{code}<63:0>: 0x{-----value----}"
1579 // "# v{code}<31:0>: 0x{-value}"
1580 // "# v{code}<15:0>: 0x{--}"
1581 // "# v{code}<7:0>: 0x{}"
1582
1583 bool is_partial = ((format & kPrintRegPartial) != 0);
1584 std::stringstream name;
1585 unsigned print_reg_size = GetPrintRegSizeInBits(format);
1586 if (is_partial) {
1587 name << VRegNameForCode(code) << GetPartialRegSuffix(format);
1588 } else {
1589 // Notify the register that it has been logged, but only if we're printing
1590 // all of it.
1591 vregisters_[code].NotifyRegisterLogged();
1592 switch (print_reg_size) {
1593 case kBRegSize:
1594 name << BRegNameForCode(code);
1595 break;
1596 case kHRegSize:
1597 name << HRegNameForCode(code);
1598 break;
1599 case kSRegSize:
1600 name << SRegNameForCode(code);
1601 break;
1602 case kDRegSize:
1603 name << DRegNameForCode(code);
1604 break;
1605 case kQRegSize:
1606 name << VRegNameForCode(code);
1607 break;
1608 default:
1609 VIXL_UNREACHABLE();
1610 return;
1611 }
1612 }
1613
1614 fprintf(stream_,
1615 "# %s%*s: %s",
1616 clr_vreg_name,
1617 kPrintRegisterNameFieldWidth,
1618 name.str().c_str(),
1619 clr_vreg_value);
1620 PrintRegisterValue(vregisters_[code], format);
1621 fprintf(stream_, "%s", clr_normal);
1622 if ((format & kPrintRegAsFP) != 0) {
1623 PrintRegisterValueFPAnnotations(vregisters_[code], format);
1624 }
1625 fprintf(stream_, "%s", suffix);
1626}
1627
1628void Simulator::PrintVRegistersForStructuredAccess(int rt_code,
1629 int reg_count,
1630 uint16_t focus_mask,
1631 PrintRegisterFormat format) {
1632 bool print_fp = (format & kPrintRegAsFP) != 0;
1633 // Suppress FP formatting, so we can specify the lanes we're interested in.
1634 PrintRegisterFormat format_no_fp =
1635 static_cast<PrintRegisterFormat>(format & ~kPrintRegAsFP);
1636
1637 for (int r = 0; r < reg_count; r++) {
1638 int code = (rt_code + r) % kNumberOfVRegisters;
1639 PrintVRegister(code, format_no_fp, "");
1640 if (print_fp) {
1641 PrintRegisterValueFPAnnotations(vregisters_[code], focus_mask, format);
1642 }
1643 fprintf(stream_, "\n");
1644 }
1645}
Alexandre Ramesd3832962016-07-04 15:03:43 +01001646
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001647void Simulator::PrintZRegistersForStructuredAccess(int rt_code,
1648 int q_index,
1649 int reg_count,
1650 uint16_t focus_mask,
1651 PrintRegisterFormat format) {
1652 bool print_fp = (format & kPrintRegAsFP) != 0;
1653 // Suppress FP formatting, so we can specify the lanes we're interested in.
1654 PrintRegisterFormat format_no_fp =
1655 static_cast<PrintRegisterFormat>(format & ~kPrintRegAsFP);
TatWai Chong72d2e562019-05-16 11:22:22 -07001656
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001657 PrintRegisterFormat format_q = GetPrintRegAsQChunkOfSVE(format);
TatWai Chong72d2e562019-05-16 11:22:22 -07001658
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001659 const unsigned size = kQRegSizeInBytes;
1660 unsigned byte_index = q_index * size;
1661 const uint8_t* value = vregisters_[rt_code].GetBytes() + byte_index;
1662 VIXL_ASSERT((byte_index + size) <= vregisters_[rt_code].GetSizeInBytes());
TatWai Chong72d2e562019-05-16 11:22:22 -07001663
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001664 for (int r = 0; r < reg_count; r++) {
1665 int code = (rt_code + r) % kNumberOfZRegisters;
1666 PrintPartialZRegister(code, q_index, format_no_fp, "");
1667 if (print_fp) {
1668 PrintRegisterValueFPAnnotations(value, focus_mask, format_q);
TatWai Chong72d2e562019-05-16 11:22:22 -07001669 }
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001670 fprintf(stream_, "\n");
TatWai Chong72d2e562019-05-16 11:22:22 -07001671 }
TatWai Chong72d2e562019-05-16 11:22:22 -07001672}
1673
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001674void Simulator::PrintZRegister(int code, PrintRegisterFormat format) {
1675 // We're going to print the register in parts, so force a partial format.
1676 format = GetPrintRegPartial(format);
1677 VIXL_ASSERT((format & kPrintRegAsVectorMask) == kPrintRegAsSVEVector);
1678 int vl = GetVectorLengthInBits();
1679 VIXL_ASSERT((vl % kQRegSize) == 0);
1680 for (unsigned i = 0; i < (vl / kQRegSize); i++) {
1681 PrintPartialZRegister(code, i, format);
1682 }
1683 vregisters_[code].NotifyRegisterLogged();
1684}
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001685
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001686void Simulator::PrintPRegister(int code, PrintRegisterFormat format) {
1687 // We're going to print the register in parts, so force a partial format.
1688 format = GetPrintRegPartial(format);
1689 VIXL_ASSERT((format & kPrintRegAsVectorMask) == kPrintRegAsSVEVector);
1690 int vl = GetVectorLengthInBits();
1691 VIXL_ASSERT((vl % kQRegSize) == 0);
1692 for (unsigned i = 0; i < (vl / kQRegSize); i++) {
1693 PrintPartialPRegister(code, i, format);
1694 }
1695 pregisters_[code].NotifyRegisterLogged();
1696}
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001697
Jacob Bramley0d754e92020-06-18 10:59:09 +01001698void Simulator::PrintFFR(PrintRegisterFormat format) {
1699 // We're going to print the register in parts, so force a partial format.
1700 format = GetPrintRegPartial(format);
1701 VIXL_ASSERT((format & kPrintRegAsVectorMask) == kPrintRegAsSVEVector);
1702 int vl = GetVectorLengthInBits();
1703 VIXL_ASSERT((vl % kQRegSize) == 0);
1704 SimPRegister& ffr = ReadFFR();
1705 for (unsigned i = 0; i < (vl / kQRegSize); i++) {
1706 PrintPartialPRegister("FFR", ffr, i, format);
1707 }
1708 ffr.NotifyRegisterLogged();
1709}
1710
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001711void Simulator::PrintPartialZRegister(int code,
1712 int q_index,
1713 PrintRegisterFormat format,
1714 const char* suffix) {
1715 VIXL_ASSERT(static_cast<unsigned>(code) < kNumberOfZRegisters);
1716 VIXL_ASSERT((format & kPrintRegAsVectorMask) == kPrintRegAsSVEVector);
1717 VIXL_ASSERT((format & kPrintRegPartial) != 0);
1718 VIXL_ASSERT((q_index * kQRegSize) < GetVectorLengthInBits());
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001719
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001720 // We _only_ trace partial Z register values in Q-sized chunks, because
1721 // they're often too large to reasonably fit on a single line. Each line
1722 // implies nothing about the unprinted bits.
1723 // "# z{code}<127:0>: 0x{-------------value------------}"
1724
1725 format = GetPrintRegAsQChunkOfSVE(format);
1726
1727 const unsigned size = kQRegSizeInBytes;
1728 unsigned byte_index = q_index * size;
1729 const uint8_t* value = vregisters_[code].GetBytes() + byte_index;
1730 VIXL_ASSERT((byte_index + size) <= vregisters_[code].GetSizeInBytes());
1731
1732 int lsb = q_index * kQRegSize;
1733 int msb = lsb + kQRegSize - 1;
1734 std::stringstream name;
1735 name << ZRegNameForCode(code) << '<' << msb << ':' << lsb << '>';
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001736
1737 fprintf(stream_,
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001738 "# %s%*s: %s",
1739 clr_vreg_name,
1740 kPrintRegisterNameFieldWidth,
1741 name.str().c_str(),
1742 clr_vreg_value);
1743 PrintRegisterValue(value, size, format);
1744 fprintf(stream_, "%s", clr_normal);
1745 if ((format & kPrintRegAsFP) != 0) {
1746 PrintRegisterValueFPAnnotations(value, GetPrintRegLaneMask(format), format);
1747 }
1748 fprintf(stream_, "%s", suffix);
1749}
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001750
Jacob Bramley0d754e92020-06-18 10:59:09 +01001751void Simulator::PrintPartialPRegister(const char* name,
1752 const SimPRegister& reg,
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001753 int q_index,
1754 PrintRegisterFormat format,
1755 const char* suffix) {
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001756 VIXL_ASSERT((format & kPrintRegAsVectorMask) == kPrintRegAsSVEVector);
1757 VIXL_ASSERT((format & kPrintRegPartial) != 0);
1758 VIXL_ASSERT((q_index * kQRegSize) < GetVectorLengthInBits());
1759
1760 // We don't currently use the format for anything here.
1761 USE(format);
1762
1763 // We _only_ trace partial P register values, because they're often too large
1764 // to reasonably fit on a single line. Each line implies nothing about the
1765 // unprinted bits.
1766 //
1767 // We print values in binary, with spaces between each bit, in order for the
1768 // bits to align with the Z register bytes that they predicate.
Jacob Bramley0d754e92020-06-18 10:59:09 +01001769 // "# {name}<15:0>: 0b{-------------value------------}"
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001770
1771 int print_size_in_bits = kQRegSize / kZRegBitsPerPRegBit;
1772 int lsb = q_index * print_size_in_bits;
1773 int msb = lsb + print_size_in_bits - 1;
Jacob Bramley0d754e92020-06-18 10:59:09 +01001774 std::stringstream prefix;
1775 prefix << name << '<' << msb << ':' << lsb << '>';
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001776
1777 fprintf(stream_,
1778 "# %s%*s: %s0b",
1779 clr_preg_name,
1780 kPrintRegisterNameFieldWidth,
Jacob Bramley0d754e92020-06-18 10:59:09 +01001781 prefix.str().c_str(),
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001782 clr_preg_value);
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001783 for (int i = msb; i >= lsb; i--) {
Jacob Bramley0d754e92020-06-18 10:59:09 +01001784 fprintf(stream_, " %c", reg.GetBit(i) ? '1' : '0');
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001785 }
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001786 fprintf(stream_, "%s%s", clr_normal, suffix);
Jacob Bramleyf5659ff2019-08-02 11:19:04 +01001787}
1788
Jacob Bramley0d754e92020-06-18 10:59:09 +01001789void Simulator::PrintPartialPRegister(int code,
1790 int q_index,
1791 PrintRegisterFormat format,
1792 const char* suffix) {
1793 VIXL_ASSERT(static_cast<unsigned>(code) < kNumberOfPRegisters);
1794 PrintPartialPRegister(PRegNameForCode(code),
1795 pregisters_[code],
1796 q_index,
1797 format,
1798 suffix);
1799}
1800
Alexandre Ramesd3832962016-07-04 15:03:43 +01001801void Simulator::PrintSystemRegister(SystemRegister id) {
1802 switch (id) {
1803 case NZCV:
1804 fprintf(stream_,
1805 "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n",
1806 clr_flag_name,
1807 clr_flag_value,
1808 ReadNzcv().GetN(),
1809 ReadNzcv().GetZ(),
1810 ReadNzcv().GetC(),
1811 ReadNzcv().GetV(),
1812 clr_normal);
1813 break;
1814 case FPCR: {
1815 static const char* rmode[] = {"0b00 (Round to Nearest)",
1816 "0b01 (Round towards Plus Infinity)",
1817 "0b10 (Round towards Minus Infinity)",
1818 "0b11 (Round towards Zero)"};
Jacob Bramleyca789742018-09-13 14:25:46 +01001819 VIXL_ASSERT(ReadFpcr().GetRMode() < ArrayLength(rmode));
Alexandre Ramesd3832962016-07-04 15:03:43 +01001820 fprintf(stream_,
1821 "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
1822 clr_flag_name,
1823 clr_flag_value,
1824 ReadFpcr().GetAHP(),
1825 ReadFpcr().GetDN(),
1826 ReadFpcr().GetFZ(),
1827 rmode[ReadFpcr().GetRMode()],
1828 clr_normal);
1829 break;
1830 }
1831 default:
1832 VIXL_UNREACHABLE();
1833 }
1834}
1835
mmc28a3c407232024-06-19 15:03:55 +01001836void Simulator::PrintGCS(bool is_push, uint64_t addr, size_t entry) {
1837 const char* arrow = is_push ? "<-" : "->";
1838 fprintf(stream_,
Chris Jonesbb7bc982025-03-11 17:15:34 +00001839 "# %sgcs0x%04" PRIx64 "[%zx]: %s %s 0x%016" PRIx64 "\n",
mmc28a3c407232024-06-19 15:03:55 +01001840 clr_flag_name,
1841 gcs_,
1842 entry,
1843 clr_normal,
1844 arrow,
1845 addr);
1846}
1847
Jacob Bramley423e5422019-11-13 19:15:55 +00001848uint16_t Simulator::PrintPartialAccess(uint16_t access_mask,
1849 uint16_t future_access_mask,
1850 int struct_element_count,
1851 int lane_size_in_bytes,
1852 const char* op,
1853 uintptr_t address,
1854 int reg_size_in_bytes) {
1855 // We want to assume that we'll access at least one lane.
1856 VIXL_ASSERT(access_mask != 0);
1857 VIXL_ASSERT((reg_size_in_bytes == kXRegSizeInBytes) ||
1858 (reg_size_in_bytes == kQRegSizeInBytes));
1859 bool started_annotation = false;
1860 // Indent to match the register field, the fixed formatting, and the value
1861 // prefix ("0x"): "# {name}: 0x"
1862 fprintf(stream_, "# %*s ", kPrintRegisterNameFieldWidth, "");
1863 // First, annotate the lanes (byte by byte).
1864 for (int lane = reg_size_in_bytes - 1; lane >= 0; lane--) {
1865 bool access = (access_mask & (1 << lane)) != 0;
1866 bool future = (future_access_mask & (1 << lane)) != 0;
1867 if (started_annotation) {
1868 // If we've started an annotation, draw a horizontal line in addition to
1869 // any other symbols.
1870 if (access) {
1871 fprintf(stream_, "─╨");
1872 } else if (future) {
1873 fprintf(stream_, "─║");
1874 } else {
1875 fprintf(stream_, "──");
1876 }
1877 } else {
1878 if (access) {
1879 started_annotation = true;
1880 fprintf(stream_, " â•™");
1881 } else if (future) {
1882 fprintf(stream_, " â•‘");
1883 } else {
1884 fprintf(stream_, " ");
1885 }
1886 }
1887 }
1888 VIXL_ASSERT(started_annotation);
1889 fprintf(stream_, "─ 0x");
1890 int lane_size_in_nibbles = lane_size_in_bytes * 2;
1891 // Print the most-significant struct element first.
1892 const char* sep = "";
1893 for (int i = struct_element_count - 1; i >= 0; i--) {
1894 int offset = lane_size_in_bytes * i;
Chris Jones30e7bbd2024-02-15 15:05:25 +00001895 auto nibble = MemReadUint(lane_size_in_bytes, address + offset);
1896 VIXL_ASSERT(nibble);
1897 fprintf(stream_, "%s%0*" PRIx64, sep, lane_size_in_nibbles, *nibble);
Jacob Bramley423e5422019-11-13 19:15:55 +00001898 sep = "'";
1899 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01001900 fprintf(stream_,
Jacob Bramley423e5422019-11-13 19:15:55 +00001901 " %s %s0x%016" PRIxPTR "%s\n",
1902 op,
1903 clr_memory_address,
1904 address,
1905 clr_normal);
1906 return future_access_mask & ~access_mask;
1907}
1908
1909void Simulator::PrintAccess(int code,
1910 PrintRegisterFormat format,
1911 const char* op,
1912 uintptr_t address) {
1913 VIXL_ASSERT(GetPrintRegLaneCount(format) == 1);
1914 VIXL_ASSERT((strcmp(op, "->") == 0) || (strcmp(op, "<-") == 0));
1915 if ((format & kPrintRegPartial) == 0) {
mmc28a9128d582023-01-17 15:53:00 +00001916 if (code != kZeroRegCode) {
1917 registers_[code].NotifyRegisterLogged();
1918 }
Jacob Bramley423e5422019-11-13 19:15:55 +00001919 }
1920 // Scalar-format accesses use a simple format:
1921 // "# {reg}: 0x{value} -> {address}"
1922
1923 // Suppress the newline, so the access annotation goes on the same line.
1924 PrintRegister(code, format, "");
1925 fprintf(stream_,
1926 " %s %s0x%016" PRIxPTR "%s\n",
1927 op,
Alexandre Ramesd3832962016-07-04 15:03:43 +01001928 clr_memory_address,
1929 address,
1930 clr_normal);
1931}
1932
Jacob Bramley423e5422019-11-13 19:15:55 +00001933void Simulator::PrintVAccess(int code,
1934 PrintRegisterFormat format,
1935 const char* op,
1936 uintptr_t address) {
1937 VIXL_ASSERT((strcmp(op, "->") == 0) || (strcmp(op, "<-") == 0));
Alexandre Ramesd3832962016-07-04 15:03:43 +01001938
Jacob Bramley423e5422019-11-13 19:15:55 +00001939 // Scalar-format accesses use a simple format:
1940 // "# v{code}: 0x{value} -> {address}"
Alexandre Ramesd3832962016-07-04 15:03:43 +01001941
Jacob Bramley423e5422019-11-13 19:15:55 +00001942 // Suppress the newline, so the access annotation goes on the same line.
1943 PrintVRegister(code, format, "");
Alexandre Ramesd3832962016-07-04 15:03:43 +01001944 fprintf(stream_,
Jacob Bramley423e5422019-11-13 19:15:55 +00001945 " %s %s0x%016" PRIxPTR "%s\n",
1946 op,
Alexandre Ramesd3832962016-07-04 15:03:43 +01001947 clr_memory_address,
1948 address,
1949 clr_normal);
1950}
1951
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001952void Simulator::PrintVStructAccess(int rt_code,
Jacob Bramley423e5422019-11-13 19:15:55 +00001953 int reg_count,
1954 PrintRegisterFormat format,
1955 const char* op,
1956 uintptr_t address) {
1957 VIXL_ASSERT((strcmp(op, "->") == 0) || (strcmp(op, "<-") == 0));
1958
1959 // For example:
1960 // "# v{code}: 0x{value}"
1961 // "# ...: 0x{value}"
1962 // "# ║ ╙─ {struct_value} -> {lowest_address}"
1963 // "# ╙───── {struct_value} -> {highest_address}"
1964
1965 uint16_t lane_mask = GetPrintRegLaneMask(format);
Jacob Bramley7eb3e212019-11-22 17:28:05 +00001966 PrintVRegistersForStructuredAccess(rt_code, reg_count, lane_mask, format);
Jacob Bramley423e5422019-11-13 19:15:55 +00001967
1968 int reg_size_in_bytes = GetPrintRegSizeInBytes(format);
1969 int lane_size_in_bytes = GetPrintRegLaneSizeInBytes(format);
1970 for (int i = 0; i < reg_size_in_bytes; i += lane_size_in_bytes) {
1971 uint16_t access_mask = 1 << i;
1972 VIXL_ASSERT((lane_mask & access_mask) != 0);
1973 lane_mask = PrintPartialAccess(access_mask,
1974 lane_mask,
1975 reg_count,
1976 lane_size_in_bytes,
1977 op,
1978 address + (i * reg_count));
1979 }
1980}
1981
1982void Simulator::PrintVSingleStructAccess(int rt_code,
1983 int reg_count,
1984 int lane,
1985 PrintRegisterFormat format,
1986 const char* op,
1987 uintptr_t address) {
1988 VIXL_ASSERT((strcmp(op, "->") == 0) || (strcmp(op, "<-") == 0));
1989
1990 // For example:
1991 // "# v{code}: 0x{value}"
1992 // "# ...: 0x{value}"
1993 // "# ╙───── {struct_value} -> {address}"
1994
1995 int lane_size_in_bytes = GetPrintRegLaneSizeInBytes(format);
1996 uint16_t lane_mask = 1 << (lane * lane_size_in_bytes);
1997 PrintVRegistersForStructuredAccess(rt_code, reg_count, lane_mask, format);
1998 PrintPartialAccess(lane_mask, 0, reg_count, lane_size_in_bytes, op, address);
1999}
2000
2001void Simulator::PrintVReplicatingStructAccess(int rt_code,
2002 int reg_count,
2003 PrintRegisterFormat format,
2004 const char* op,
2005 uintptr_t address) {
2006 VIXL_ASSERT((strcmp(op, "->") == 0) || (strcmp(op, "<-") == 0));
2007
2008 // For example:
2009 // "# v{code}: 0x{value}"
2010 // "# ...: 0x{value}"
2011 // "# ╙─╨─╨─╨─ {struct_value} -> {address}"
2012
2013 int lane_size_in_bytes = GetPrintRegLaneSizeInBytes(format);
2014 uint16_t lane_mask = GetPrintRegLaneMask(format);
2015 PrintVRegistersForStructuredAccess(rt_code, reg_count, lane_mask, format);
2016 PrintPartialAccess(lane_mask, 0, reg_count, lane_size_in_bytes, op, address);
2017}
2018
Jacob Bramley7eb3e212019-11-22 17:28:05 +00002019void Simulator::PrintZAccess(int rt_code, const char* op, uintptr_t address) {
2020 VIXL_ASSERT((strcmp(op, "->") == 0) || (strcmp(op, "<-") == 0));
2021
2022 // Scalar-format accesses are split into separate chunks, each of which uses a
2023 // simple format:
2024 // "# z{code}<127:0>: 0x{value} -> {address}"
2025 // "# z{code}<255:128>: 0x{value} -> {address + 16}"
2026 // "# z{code}<383:256>: 0x{value} -> {address + 32}"
2027 // etc
2028
2029 int vl = GetVectorLengthInBits();
2030 VIXL_ASSERT((vl % kQRegSize) == 0);
2031 for (unsigned q_index = 0; q_index < (vl / kQRegSize); q_index++) {
2032 // Suppress the newline, so the access annotation goes on the same line.
2033 PrintPartialZRegister(rt_code, q_index, kPrintRegVnQPartial, "");
2034 fprintf(stream_,
2035 " %s %s0x%016" PRIxPTR "%s\n",
2036 op,
2037 clr_memory_address,
2038 address,
2039 clr_normal);
2040 address += kQRegSizeInBytes;
2041 }
2042}
2043
2044void Simulator::PrintZStructAccess(int rt_code,
2045 int reg_count,
2046 const LogicPRegister& pg,
2047 PrintRegisterFormat format,
2048 int msize_in_bytes,
2049 const char* op,
2050 const LogicSVEAddressVector& addr) {
2051 VIXL_ASSERT((strcmp(op, "->") == 0) || (strcmp(op, "<-") == 0));
2052
2053 // For example:
2054 // "# z{code}<255:128>: 0x{value}"
2055 // "# ...<255:128>: 0x{value}"
2056 // "# ║ ╙─ {struct_value} -> {first_address}"
2057 // "# ╙───── {struct_value} -> {last_address}"
2058
2059 // We're going to print the register in parts, so force a partial format.
2060 bool skip_inactive_chunks = (format & kPrintRegPartial) != 0;
2061 format = GetPrintRegPartial(format);
2062
2063 int esize_in_bytes = GetPrintRegLaneSizeInBytes(format);
2064 int vl = GetVectorLengthInBits();
2065 VIXL_ASSERT((vl % kQRegSize) == 0);
2066 int lanes_per_q = kQRegSizeInBytes / esize_in_bytes;
2067 for (unsigned q_index = 0; q_index < (vl / kQRegSize); q_index++) {
2068 uint16_t pred =
2069 pg.GetActiveMask<uint16_t>(q_index) & GetPrintRegLaneMask(format);
2070 if ((pred == 0) && skip_inactive_chunks) continue;
2071
2072 PrintZRegistersForStructuredAccess(rt_code,
2073 q_index,
2074 reg_count,
2075 pred,
2076 format);
2077 if (pred == 0) {
2078 // This register chunk has no active lanes. The loop below would print
2079 // nothing, so leave a blank line to keep structures grouped together.
2080 fprintf(stream_, "#\n");
2081 continue;
2082 }
2083 for (int i = 0; i < lanes_per_q; i++) {
2084 uint16_t access = 1 << (i * esize_in_bytes);
2085 int lane = (q_index * lanes_per_q) + i;
2086 // Skip inactive lanes.
2087 if ((pred & access) == 0) continue;
2088 pred = PrintPartialAccess(access,
2089 pred,
2090 reg_count,
2091 msize_in_bytes,
2092 op,
2093 addr.GetStructAddress(lane));
2094 }
2095 }
2096
2097 // We print the whole register, even for stores.
2098 for (int i = 0; i < reg_count; i++) {
2099 vregisters_[(rt_code + i) % kNumberOfZRegisters].NotifyRegisterLogged();
2100 }
2101}
2102
2103void Simulator::PrintPAccess(int code, const char* op, uintptr_t address) {
2104 VIXL_ASSERT((strcmp(op, "->") == 0) || (strcmp(op, "<-") == 0));
2105
2106 // Scalar-format accesses are split into separate chunks, each of which uses a
2107 // simple format:
2108 // "# p{code}<15:0>: 0b{value} -> {address}"
2109 // "# p{code}<31:16>: 0b{value} -> {address + 2}"
2110 // "# p{code}<47:32>: 0b{value} -> {address + 4}"
2111 // etc
2112
2113 int vl = GetVectorLengthInBits();
2114 VIXL_ASSERT((vl % kQRegSize) == 0);
2115 for (unsigned q_index = 0; q_index < (vl / kQRegSize); q_index++) {
2116 // Suppress the newline, so the access annotation goes on the same line.
2117 PrintPartialPRegister(code, q_index, kPrintRegVnQPartial, "");
2118 fprintf(stream_,
2119 " %s %s0x%016" PRIxPTR "%s\n",
2120 op,
2121 clr_memory_address,
2122 address,
2123 clr_normal);
2124 address += kQRegSizeInBytes;
2125 }
2126}
2127
Martyn Capewelld6acdad2022-05-12 15:35:15 +01002128void Simulator::PrintMemTransfer(uintptr_t dst, uintptr_t src, uint8_t value) {
2129 fprintf(stream_,
2130 "# %s: %s0x%016" PRIxPTR " %s<- %s0x%02x%s",
2131 clr_reg_name,
2132 clr_memory_address,
2133 dst,
2134 clr_normal,
2135 clr_reg_value,
2136 value,
2137 clr_normal);
2138
2139 fprintf(stream_,
2140 " <- %s0x%016" PRIxPTR "%s\n",
2141 clr_memory_address,
2142 src,
2143 clr_normal);
2144}
2145
Jacob Bramley423e5422019-11-13 19:15:55 +00002146void Simulator::PrintRead(int rt_code,
2147 PrintRegisterFormat format,
2148 uintptr_t address) {
2149 VIXL_ASSERT(GetPrintRegLaneCount(format) == 1);
mmc28a9128d582023-01-17 15:53:00 +00002150 if (rt_code != kZeroRegCode) {
2151 registers_[rt_code].NotifyRegisterLogged();
2152 }
Jacob Bramley423e5422019-11-13 19:15:55 +00002153 PrintAccess(rt_code, format, "<-", address);
2154}
2155
2156void Simulator::PrintExtendingRead(int rt_code,
2157 PrintRegisterFormat format,
2158 int access_size_in_bytes,
2159 uintptr_t address) {
2160 int reg_size_in_bytes = GetPrintRegSizeInBytes(format);
2161 if (access_size_in_bytes == reg_size_in_bytes) {
2162 // There is no extension here, so print a simple load.
2163 PrintRead(rt_code, format, address);
2164 return;
2165 }
2166 VIXL_ASSERT(access_size_in_bytes < reg_size_in_bytes);
2167
2168 // For sign- and zero-extension, make it clear that the resulting register
2169 // value is different from what is loaded from memory.
2170 VIXL_ASSERT(GetPrintRegLaneCount(format) == 1);
mmc28a9128d582023-01-17 15:53:00 +00002171 if (rt_code != kZeroRegCode) {
2172 registers_[rt_code].NotifyRegisterLogged();
2173 }
Jacob Bramley423e5422019-11-13 19:15:55 +00002174 PrintRegister(rt_code, format);
2175 PrintPartialAccess(1,
2176 0,
2177 1,
2178 access_size_in_bytes,
2179 "<-",
2180 address,
2181 kXRegSizeInBytes);
2182}
2183
2184void Simulator::PrintVRead(int rt_code,
2185 PrintRegisterFormat format,
2186 uintptr_t address) {
2187 VIXL_ASSERT(GetPrintRegLaneCount(format) == 1);
2188 vregisters_[rt_code].NotifyRegisterLogged();
2189 PrintVAccess(rt_code, format, "<-", address);
2190}
2191
Jacob Bramley423e5422019-11-13 19:15:55 +00002192void Simulator::PrintWrite(int rt_code,
2193 PrintRegisterFormat format,
2194 uintptr_t address) {
2195 // Because this trace doesn't represent a change to the source register's
2196 // value, only print the relevant part of the value.
2197 format = GetPrintRegPartial(format);
Alexandre Ramesd3832962016-07-04 15:03:43 +01002198 VIXL_ASSERT(GetPrintRegLaneCount(format) == 1);
mmc28a9128d582023-01-17 15:53:00 +00002199 if (rt_code != kZeroRegCode) {
2200 registers_[rt_code].NotifyRegisterLogged();
2201 }
Jacob Bramley423e5422019-11-13 19:15:55 +00002202 PrintAccess(rt_code, format, "->", address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01002203}
2204
Jacob Bramley423e5422019-11-13 19:15:55 +00002205void Simulator::PrintVWrite(int rt_code,
Alexandre Ramesd3832962016-07-04 15:03:43 +01002206 PrintRegisterFormat format,
Jacob Bramley423e5422019-11-13 19:15:55 +00002207 uintptr_t address) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01002208 // Because this trace doesn't represent a change to the source register's
Jacob Bramley423e5422019-11-13 19:15:55 +00002209 // value, only print the relevant part of the value.
2210 format = GetPrintRegPartial(format);
Jacob Bramley7eb3e212019-11-22 17:28:05 +00002211 // It only makes sense to write scalar values here. Vectors are handled by
2212 // PrintVStructAccess.
Jacob Bramley423e5422019-11-13 19:15:55 +00002213 VIXL_ASSERT(GetPrintRegLaneCount(format) == 1);
Jacob Bramley423e5422019-11-13 19:15:55 +00002214 PrintVAccess(rt_code, format, "->", address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01002215}
2216
Jacob Bramleye79723a2016-06-07 17:50:47 +01002217void Simulator::PrintTakenBranch(const Instruction* target) {
2218 fprintf(stream_,
2219 "# %sBranch%s to 0x%016" PRIx64 ".\n",
2220 clr_branch_marker,
2221 clr_normal,
2222 reinterpret_cast<uint64_t>(target));
2223}
2224
Alexandre Ramesd3832962016-07-04 15:03:43 +01002225// Visitors---------------------------------------------------------------------
2226
Jacob Bramley18c97bd2019-01-18 16:01:08 +00002227
Martyn Capewell8c691852020-07-15 18:33:15 +01002228void Simulator::Visit(Metadata* metadata, const Instruction* instr) {
2229 VIXL_ASSERT(metadata->count("form") > 0);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002230 std::string form = (*metadata)["form"];
Martyn Capewell8afff392022-04-19 18:08:39 +01002231 form_hash_ = Hash(form.c_str());
Martyn Capewellea8fa652022-01-26 15:48:07 +00002232 const FormToVisitorFnMap* fv = Simulator::GetFormToVisitorFnMap();
Martyn Capewell8afff392022-04-19 18:08:39 +01002233 FormToVisitorFnMap::const_iterator it = fv->find(form_hash_);
2234 if (it == fv->end()) {
Martyn Capewell8c691852020-07-15 18:33:15 +01002235 VisitUnimplemented(instr);
Martyn Capewell8afff392022-04-19 18:08:39 +01002236 } else {
2237 (it->second)(this, instr);
Martyn Capewell8c691852020-07-15 18:33:15 +01002238 }
2239}
2240
Martyn Capewell6bf28752020-08-05 11:57:06 +01002241void Simulator::Simulate_PdT_PgZ_ZnT_ZmT(const Instruction* instr) {
Martyn Capewell51643312020-08-24 15:58:57 +01002242 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002243 SimPRegister& pd = ReadPRegister(instr->GetPd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002244 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002245 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002246 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002247
2248 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002249 case "match_p_p_zz"_h:
Martyn Capewell51643312020-08-24 15:58:57 +01002250 match(vform, pd, zn, zm, /* negate_match = */ false);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002251 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002252 case "nmatch_p_p_zz"_h:
Martyn Capewell51643312020-08-24 15:58:57 +01002253 match(vform, pd, zn, zm, /* negate_match = */ true);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002254 break;
2255 default:
2256 VIXL_UNIMPLEMENTED();
2257 }
Martyn Capewell51643312020-08-24 15:58:57 +01002258 mov_zeroing(pd, pg, pd);
2259 PredTest(vform, pg, pd);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002260}
2261
Martyn Capewell6bf28752020-08-05 11:57:06 +01002262void Simulator::Simulate_PdT_Xn_Xm(const Instruction* instr) {
Martyn Capewell35636df2020-10-15 15:14:12 +01002263 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002264 SimPRegister& pd = ReadPRegister(instr->GetPd());
Martyn Capewell35636df2020-10-15 15:14:12 +01002265 uint64_t src1 = ReadXRegister(instr->GetRn());
2266 uint64_t src2 = ReadXRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002267
Martyn Capewell35636df2020-10-15 15:14:12 +01002268 uint64_t absdiff = (src1 > src2) ? (src1 - src2) : (src2 - src1);
2269 absdiff >>= LaneSizeInBytesLog2FromFormat(vform);
2270
2271 bool no_conflict = false;
Martyn Capewell6bf28752020-08-05 11:57:06 +01002272 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002273 case "whilerw_p_rr"_h:
Martyn Capewell35636df2020-10-15 15:14:12 +01002274 no_conflict = (absdiff == 0);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002275 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002276 case "whilewr_p_rr"_h:
Martyn Capewell35636df2020-10-15 15:14:12 +01002277 no_conflict = (absdiff == 0) || (src2 <= src1);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002278 break;
2279 default:
2280 VIXL_UNIMPLEMENTED();
2281 }
Martyn Capewell35636df2020-10-15 15:14:12 +01002282
2283 LogicPRegister dst(pd);
2284 for (int i = 0; i < LaneCountFromFormat(vform); i++) {
2285 dst.SetActive(vform,
2286 i,
2287 no_conflict || (static_cast<uint64_t>(i) < absdiff));
2288 }
2289
2290 PredTest(vform, GetPTrue(), pd);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002291}
2292
2293void Simulator::Simulate_ZdB_Zn1B_Zn2B_imm(const Instruction* instr) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002294 VIXL_ASSERT(form_hash_ == "ext_z_zi_con"_h);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002295
Martyn Capewellbf424382021-03-19 15:56:26 +00002296 SimVRegister& zd = ReadVRegister(instr->GetRd());
2297 SimVRegister& zn = ReadVRegister(instr->GetRn());
2298 SimVRegister& zn2 = ReadVRegister((instr->GetRn() + 1) % kNumberOfZRegisters);
2299
2300 int index = instr->GetSVEExtractImmediate();
2301 int vl = GetVectorLengthInBytes();
2302 index = (index >= vl) ? 0 : index;
2303
2304 ext(kFormatVnB, zd, zn, zn2, index);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002305}
2306
2307void Simulator::Simulate_ZdB_ZnB_ZmB(const Instruction* instr) {
2308 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002309 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002310 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002311
2312 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002313 case "histseg_z_zz"_h:
Martyn Capewell710ec6f2020-10-22 16:56:17 +01002314 if (instr->GetSVEVectorFormat() == kFormatVnB) {
2315 histogram(kFormatVnB,
2316 zd,
2317 GetPTrue(),
2318 zn,
2319 zm,
2320 /* do_segmented = */ true);
2321 } else {
2322 VIXL_UNIMPLEMENTED();
2323 }
Martyn Capewell6bf28752020-08-05 11:57:06 +01002324 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002325 case "pmul_z_zz"_h:
TatWai Chong1dba0fb2020-10-07 16:50:13 -07002326 pmul(kFormatVnB, zd, zn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002327 break;
2328 default:
2329 VIXL_UNIMPLEMENTED();
2330 }
2331}
2332
Martyn Capewellf272b9c2020-11-05 18:30:16 +00002333void Simulator::SimulateSVEMulIndex(const Instruction* instr) {
2334 VectorFormat vform = instr->GetSVEVectorFormat();
2335 SimVRegister& zd = ReadVRegister(instr->GetRd());
2336 SimVRegister& zn = ReadVRegister(instr->GetRn());
2337
2338 // The encoding for B and H-sized lanes are redefined to encode the most
2339 // significant bit of index for H-sized lanes. B-sized lanes are not
2340 // supported.
2341 if (vform == kFormatVnB) vform = kFormatVnH;
2342
Martyn Capewelld48909d2022-05-03 16:38:38 +01002343 VIXL_ASSERT((form_hash_ == "mul_z_zzi_d"_h) ||
2344 (form_hash_ == "mul_z_zzi_h"_h) ||
2345 (form_hash_ == "mul_z_zzi_s"_h));
Martyn Capewellf272b9c2020-11-05 18:30:16 +00002346
2347 SimVRegister temp;
2348 dup_elements_to_segments(vform, temp, instr->GetSVEMulZmAndIndex());
2349 mul(vform, zd, zn, temp);
2350}
2351
Martyn Capewell8f4e1692020-11-06 14:16:14 +00002352void Simulator::SimulateSVEMlaMlsIndex(const Instruction* instr) {
2353 VectorFormat vform = instr->GetSVEVectorFormat();
2354 SimVRegister& zda = ReadVRegister(instr->GetRd());
2355 SimVRegister& zn = ReadVRegister(instr->GetRn());
2356
2357 // The encoding for B and H-sized lanes are redefined to encode the most
2358 // significant bit of index for H-sized lanes. B-sized lanes are not
2359 // supported.
2360 if (vform == kFormatVnB) vform = kFormatVnH;
2361
Martyn Capewelld48909d2022-05-03 16:38:38 +01002362 VIXL_ASSERT(
2363 (form_hash_ == "mla_z_zzzi_d"_h) || (form_hash_ == "mla_z_zzzi_h"_h) ||
2364 (form_hash_ == "mla_z_zzzi_s"_h) || (form_hash_ == "mls_z_zzzi_d"_h) ||
2365 (form_hash_ == "mls_z_zzzi_h"_h) || (form_hash_ == "mls_z_zzzi_s"_h));
Martyn Capewell8f4e1692020-11-06 14:16:14 +00002366
2367 SimVRegister temp;
2368 dup_elements_to_segments(vform, temp, instr->GetSVEMulZmAndIndex());
2369 if (instr->ExtractBit(10) == 0) {
2370 mla(vform, zda, zda, zn, temp);
2371 } else {
2372 mls(vform, zda, zda, zn, temp);
2373 }
2374}
2375
Martyn Capewell11ad9452021-03-16 18:27:52 +00002376void Simulator::SimulateSVESaturatingMulHighIndex(const Instruction* instr) {
2377 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002378 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002379 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002380
Martyn Capewell11ad9452021-03-16 18:27:52 +00002381 // The encoding for B and H-sized lanes are redefined to encode the most
2382 // significant bit of index for H-sized lanes. B-sized lanes are not
2383 // supported.
2384 if (vform == kFormatVnB) {
2385 vform = kFormatVnH;
2386 }
2387
2388 SimVRegister temp;
2389 dup_elements_to_segments(vform, temp, instr->GetSVEMulZmAndIndex());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002390 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002391 case "sqdmulh_z_zzi_h"_h:
2392 case "sqdmulh_z_zzi_s"_h:
2393 case "sqdmulh_z_zzi_d"_h:
Martyn Capewell11ad9452021-03-16 18:27:52 +00002394 sqdmulh(vform, zd, zn, temp);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002395 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002396 case "sqrdmulh_z_zzi_h"_h:
2397 case "sqrdmulh_z_zzi_s"_h:
2398 case "sqrdmulh_z_zzi_d"_h:
Martyn Capewell11ad9452021-03-16 18:27:52 +00002399 sqrdmulh(vform, zd, zn, temp);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002400 break;
2401 default:
2402 VIXL_UNIMPLEMENTED();
2403 }
2404}
2405
TatWai Chong1719b712020-09-25 18:16:40 -07002406void Simulator::SimulateSVESaturatingIntMulLongIdx(const Instruction* instr) {
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002407 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002408 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002409 SimVRegister& zn = ReadVRegister(instr->GetRn());
TatWai Chong1719b712020-09-25 18:16:40 -07002410
2411 SimVRegister temp, zm_idx, zn_b, zn_t;
2412 // Instead of calling the indexed form of the instruction logic, we call the
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002413 // vector form, which can reuse existing function logic without modification.
Martyn Capewell97ca8062020-10-23 14:45:14 +01002414 // Select the specified elements based on the index input and than pack them
2415 // to the corresponding position.
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002416 VectorFormat vform_half = VectorFormatHalfWidth(vform);
2417 dup_elements_to_segments(vform_half, temp, instr->GetSVEMulLongZmAndIndex());
2418 pack_even_elements(vform_half, zm_idx, temp);
2419
2420 pack_even_elements(vform_half, zn_b, zn);
2421 pack_odd_elements(vform_half, zn_t, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002422
2423 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002424 case "smullb_z_zzi_s"_h:
2425 case "smullb_z_zzi_d"_h:
Martyn Capewell573246c2021-01-07 17:24:00 +00002426 smull(vform, zd, zn_b, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002427 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002428 case "smullt_z_zzi_s"_h:
2429 case "smullt_z_zzi_d"_h:
Martyn Capewell573246c2021-01-07 17:24:00 +00002430 smull(vform, zd, zn_t, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002431 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002432 case "sqdmullb_z_zzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002433 sqdmull(vform, zd, zn_b, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002434 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002435 case "sqdmullt_z_zzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002436 sqdmull(vform, zd, zn_t, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002437 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002438 case "umullb_z_zzi_s"_h:
2439 case "umullb_z_zzi_d"_h:
Martyn Capewell573246c2021-01-07 17:24:00 +00002440 umull(vform, zd, zn_b, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002441 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002442 case "umullt_z_zzi_s"_h:
2443 case "umullt_z_zzi_d"_h:
Martyn Capewell573246c2021-01-07 17:24:00 +00002444 umull(vform, zd, zn_t, zm_idx);
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002445 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002446 case "sqdmullb_z_zzi_s"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002447 sqdmull(vform, zd, zn_b, zm_idx);
2448 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002449 case "sqdmullt_z_zzi_s"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002450 sqdmull(vform, zd, zn_t, zm_idx);
2451 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002452 case "smlalb_z_zzzi_s"_h:
2453 case "smlalb_z_zzzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002454 smlal(vform, zd, zn_b, zm_idx);
2455 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002456 case "smlalt_z_zzzi_s"_h:
2457 case "smlalt_z_zzzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002458 smlal(vform, zd, zn_t, zm_idx);
2459 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002460 case "smlslb_z_zzzi_s"_h:
2461 case "smlslb_z_zzzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002462 smlsl(vform, zd, zn_b, zm_idx);
2463 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002464 case "smlslt_z_zzzi_s"_h:
2465 case "smlslt_z_zzzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002466 smlsl(vform, zd, zn_t, zm_idx);
2467 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002468 case "umlalb_z_zzzi_s"_h:
2469 case "umlalb_z_zzzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002470 umlal(vform, zd, zn_b, zm_idx);
2471 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002472 case "umlalt_z_zzzi_s"_h:
2473 case "umlalt_z_zzzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002474 umlal(vform, zd, zn_t, zm_idx);
2475 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002476 case "umlslb_z_zzzi_s"_h:
2477 case "umlslb_z_zzzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002478 umlsl(vform, zd, zn_b, zm_idx);
2479 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002480 case "umlslt_z_zzzi_s"_h:
2481 case "umlslt_z_zzzi_d"_h:
Martyn Capewell2e66dc72020-12-02 17:59:09 +00002482 umlsl(vform, zd, zn_t, zm_idx);
2483 break;
Martyn Capewell6bf28752020-08-05 11:57:06 +01002484 default:
2485 VIXL_UNIMPLEMENTED();
2486 }
2487}
2488
2489void Simulator::Simulate_ZdH_PgM_ZnS(const Instruction* instr) {
2490 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002491 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002492 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell4b493882021-03-11 16:51:52 +00002493 SimVRegister result, zd_b;
2494
2495 pack_even_elements(kFormatVnH, zd_b, zd);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002496
2497 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002498 case "fcvtnt_z_p_z_s2h"_h:
TatWai Chong58fecbd2021-03-30 14:38:31 -07002499 fcvt(kFormatVnH, kFormatVnS, result, pg, zn);
Martyn Capewell4b493882021-03-11 16:51:52 +00002500 pack_even_elements(kFormatVnH, result, result);
2501 zip1(kFormatVnH, result, zd_b, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002502 break;
2503 default:
2504 VIXL_UNIMPLEMENTED();
2505 }
Martyn Capewell4b493882021-03-11 16:51:52 +00002506 mov_merging(kFormatVnS, zd, pg, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002507}
2508
Martyn Capewell6bf28752020-08-05 11:57:06 +01002509void Simulator::Simulate_ZdS_PgM_ZnD(const Instruction* instr) {
2510 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002511 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002512 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell4b493882021-03-11 16:51:52 +00002513 SimVRegister result, zero, zd_b;
2514
Martyn Capewell95e73392021-02-24 17:42:51 +00002515 zero.Clear();
Martyn Capewell4b493882021-03-11 16:51:52 +00002516 pack_even_elements(kFormatVnS, zd_b, zd);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002517
2518 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002519 case "fcvtnt_z_p_z_d2s"_h:
TatWai Chong58fecbd2021-03-30 14:38:31 -07002520 fcvt(kFormatVnS, kFormatVnD, result, pg, zn);
Martyn Capewell4b493882021-03-11 16:51:52 +00002521 pack_even_elements(kFormatVnS, result, result);
2522 zip1(kFormatVnS, result, zd_b, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002523 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002524 case "fcvtx_z_p_z_d2s"_h:
Martyn Capewell95e73392021-02-24 17:42:51 +00002525 fcvtxn(kFormatVnS, result, zn);
2526 zip1(kFormatVnS, result, result, zero);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002527 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002528 case "fcvtxnt_z_p_z_d2s"_h:
Martyn Capewell4b493882021-03-11 16:51:52 +00002529 fcvtxn(kFormatVnS, result, zn);
2530 zip1(kFormatVnS, result, zd_b, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002531 break;
2532 default:
2533 VIXL_UNIMPLEMENTED();
2534 }
Martyn Capewell95e73392021-02-24 17:42:51 +00002535 mov_merging(kFormatVnD, zd, pg, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002536}
2537
Martyn Capewell4b493882021-03-11 16:51:52 +00002538void Simulator::SimulateSVEFPConvertLong(const Instruction* instr) {
Martyn Capewell6bf28752020-08-05 11:57:06 +01002539 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002540 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002541 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell4b493882021-03-11 16:51:52 +00002542 SimVRegister result;
Martyn Capewell6bf28752020-08-05 11:57:06 +01002543
2544 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002545 case "fcvtlt_z_p_z_h2s"_h:
Martyn Capewell4b493882021-03-11 16:51:52 +00002546 ext(kFormatVnB, result, zn, zn, kHRegSizeInBytes);
TatWai Chong58fecbd2021-03-30 14:38:31 -07002547 fcvt(kFormatVnS, kFormatVnH, zd, pg, result);
Martyn Capewell4b493882021-03-11 16:51:52 +00002548 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002549 case "fcvtlt_z_p_z_s2d"_h:
Martyn Capewell4b493882021-03-11 16:51:52 +00002550 ext(kFormatVnB, result, zn, zn, kSRegSizeInBytes);
TatWai Chong58fecbd2021-03-30 14:38:31 -07002551 fcvt(kFormatVnD, kFormatVnS, zd, pg, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002552 break;
2553 default:
2554 VIXL_UNIMPLEMENTED();
2555 }
2556}
2557
2558void Simulator::Simulate_ZdS_PgM_ZnS(const Instruction* instr) {
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002559 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002560 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002561 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002562 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002563 SimVRegister result;
2564
2565 if (vform != kFormatVnS) {
2566 VIXL_UNIMPLEMENTED();
2567 }
Martyn Capewell6bf28752020-08-05 11:57:06 +01002568
2569 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002570 case "urecpe_z_p_z"_h:
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002571 urecpe(vform, result, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002572 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002573 case "ursqrte_z_p_z"_h:
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002574 ursqrte(vform, result, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002575 break;
2576 default:
2577 VIXL_UNIMPLEMENTED();
2578 }
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002579 mov_merging(vform, zd, pg, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002580}
2581
Martyn Capewell6bf28752020-08-05 11:57:06 +01002582void Simulator::Simulate_ZdT_PgM_ZnT(const Instruction* instr) {
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002583 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002584 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002585 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002586 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002587 SimVRegister result;
Martyn Capewell6bf28752020-08-05 11:57:06 +01002588
2589 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002590 case "flogb_z_p_z"_h:
Martyn Capewell342876b2021-02-24 16:34:33 +00002591 vform = instr->GetSVEVectorFormat(17);
2592 flogb(vform, result, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002593 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002594 case "sqabs_z_p_z"_h:
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002595 abs(vform, result, zn).SignedSaturate(vform);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002596 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002597 case "sqneg_z_p_z"_h:
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002598 neg(vform, result, zn).SignedSaturate(vform);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002599 break;
2600 default:
2601 VIXL_UNIMPLEMENTED();
2602 }
Martyn Capewell7ebf9cc2020-09-23 18:32:38 +01002603 mov_merging(vform, zd, pg, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002604}
2605
2606void Simulator::Simulate_ZdT_PgZ_ZnT_ZmT(const Instruction* instr) {
Martyn Capewell030875c2020-10-21 18:08:05 +01002607 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002608 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002609 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002610 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002611 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell030875c2020-10-21 18:08:05 +01002612 SimVRegister result;
Martyn Capewell6bf28752020-08-05 11:57:06 +01002613
Martyn Capewelld48909d2022-05-03 16:38:38 +01002614 VIXL_ASSERT(form_hash_ == "histcnt_z_p_zz"_h);
Martyn Capewell030875c2020-10-21 18:08:05 +01002615 if ((vform == kFormatVnS) || (vform == kFormatVnD)) {
Martyn Capewell710ec6f2020-10-22 16:56:17 +01002616 histogram(vform, result, pg, zn, zm);
Martyn Capewell030875c2020-10-21 18:08:05 +01002617 mov_zeroing(vform, zd, pg, result);
2618 } else {
2619 VIXL_UNIMPLEMENTED();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002620 }
2621}
2622
Martyn Capewell6bf28752020-08-05 11:57:06 +01002623void Simulator::Simulate_ZdT_ZnT_ZmT(const Instruction* instr) {
Martyn Capewellcd14aeb2020-09-18 10:53:59 +01002624 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002625 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002626 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002627 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewellcd14aeb2020-09-18 10:53:59 +01002628 SimVRegister result;
Martyn Capewell507dd4e2020-10-20 17:44:00 +01002629 bool do_bext = false;
2630
Martyn Capewell6bf28752020-08-05 11:57:06 +01002631 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002632 case "bdep_z_zz"_h:
Martyn Capewell507dd4e2020-10-20 17:44:00 +01002633 bdep(vform, zd, zn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002634 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002635 case "bext_z_zz"_h:
Martyn Capewell507dd4e2020-10-20 17:44:00 +01002636 do_bext = true;
2637 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002638 case "bgrp_z_zz"_h:
Martyn Capewell507dd4e2020-10-20 17:44:00 +01002639 bgrp(vform, zd, zn, zm, do_bext);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002640 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002641 case "eorbt_z_zz"_h:
Martyn Capewellcd14aeb2020-09-18 10:53:59 +01002642 rotate_elements_right(vform, result, zm, 1);
2643 SVEBitwiseLogicalUnpredicatedHelper(EOR, kFormatVnD, result, zn, result);
2644 mov_alternating(vform, zd, result, 0);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002645 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002646 case "eortb_z_zz"_h:
Martyn Capewellcd14aeb2020-09-18 10:53:59 +01002647 rotate_elements_right(vform, result, zm, -1);
2648 SVEBitwiseLogicalUnpredicatedHelper(EOR, kFormatVnD, result, zn, result);
2649 mov_alternating(vform, zd, result, 1);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002650 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002651 case "mul_z_zz"_h:
TatWai Chong1dba0fb2020-10-07 16:50:13 -07002652 mul(vform, zd, zn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002653 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002654 case "smulh_z_zz"_h:
TatWai Chong1dba0fb2020-10-07 16:50:13 -07002655 smulh(vform, zd, zn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002656 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002657 case "sqdmulh_z_zz"_h:
Martyn Capewell310326b2021-01-12 16:33:22 +00002658 sqdmulh(vform, zd, zn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002659 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002660 case "sqrdmulh_z_zz"_h:
Martyn Capewell310326b2021-01-12 16:33:22 +00002661 sqrdmulh(vform, zd, zn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002662 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002663 case "umulh_z_zz"_h:
TatWai Chong1dba0fb2020-10-07 16:50:13 -07002664 umulh(vform, zd, zn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002665 break;
2666 default:
2667 VIXL_UNIMPLEMENTED();
2668 }
2669}
2670
2671void Simulator::Simulate_ZdT_ZnT_ZmTb(const Instruction* instr) {
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002672 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002673 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002674 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002675 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002676
2677 SimVRegister zm_b, zm_t;
TatWai Chong236e7ae2020-09-13 14:55:04 -07002678 VectorFormat vform_half = VectorFormatHalfWidth(vform);
2679 pack_even_elements(vform_half, zm_b, zm);
2680 pack_odd_elements(vform_half, zm_t, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002681
2682 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002683 case "saddwb_z_zz"_h:
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002684 saddw(vform, zd, zn, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002685 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002686 case "saddwt_z_zz"_h:
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002687 saddw(vform, zd, zn, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002688 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002689 case "ssubwb_z_zz"_h:
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002690 ssubw(vform, zd, zn, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002691 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002692 case "ssubwt_z_zz"_h:
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002693 ssubw(vform, zd, zn, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002694 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002695 case "uaddwb_z_zz"_h:
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002696 uaddw(vform, zd, zn, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002697 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002698 case "uaddwt_z_zz"_h:
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002699 uaddw(vform, zd, zn, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002700 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002701 case "usubwb_z_zz"_h:
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002702 usubw(vform, zd, zn, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002703 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002704 case "usubwt_z_zz"_h:
Martyn Capewell7cf66e82020-09-25 15:54:31 +01002705 usubw(vform, zd, zn, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002706 break;
2707 default:
2708 VIXL_UNIMPLEMENTED();
2709 }
2710}
2711
2712void Simulator::Simulate_ZdT_ZnT_const(const Instruction* instr) {
2713 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002714 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell78743b62020-09-09 11:08:57 +01002715
2716 std::pair<int, int> shift_and_lane_size =
2717 instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ false);
2718 int lane_size = shift_and_lane_size.second;
2719 VIXL_ASSERT((lane_size >= 0) &&
2720 (static_cast<unsigned>(lane_size) <= kDRegSizeInBytesLog2));
2721 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(lane_size);
2722 int shift_dist = shift_and_lane_size.first;
Martyn Capewell6bf28752020-08-05 11:57:06 +01002723
2724 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002725 case "sli_z_zzi"_h:
Martyn Capewell78743b62020-09-09 11:08:57 +01002726 // Shift distance is computed differently for left shifts. Convert the
2727 // result.
2728 shift_dist = (8 << lane_size) - shift_dist;
2729 sli(vform, zd, zn, shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002730 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002731 case "sri_z_zzi"_h:
Martyn Capewell78743b62020-09-09 11:08:57 +01002732 sri(vform, zd, zn, shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002733 break;
2734 default:
2735 VIXL_UNIMPLEMENTED();
2736 }
2737}
2738
Martyn Capewellea9b4072020-10-09 11:25:26 +01002739void Simulator::SimulateSVENarrow(const Instruction* instr) {
Martyn Capewell6bf28752020-08-05 11:57:06 +01002740 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002741 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewellb5636e52020-09-17 11:21:29 +01002742 SimVRegister result;
2743
2744 std::pair<int, int> shift_and_lane_size =
2745 instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ false);
2746 int lane_size = shift_and_lane_size.second;
2747 VIXL_ASSERT((lane_size >= static_cast<int>(kBRegSizeInBytesLog2)) &&
2748 (lane_size <= static_cast<int>(kSRegSizeInBytesLog2)));
2749 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(lane_size);
Martyn Capewellea9b4072020-10-09 11:25:26 +01002750 int right_shift_dist = shift_and_lane_size.first;
Martyn Capewellb5636e52020-09-17 11:21:29 +01002751 bool top = false;
Martyn Capewell6bf28752020-08-05 11:57:06 +01002752
2753 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002754 case "sqxtnt_z_zz"_h:
Martyn Capewellb5636e52020-09-17 11:21:29 +01002755 top = true;
2756 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002757 case "sqxtnb_z_zz"_h:
Martyn Capewellb5636e52020-09-17 11:21:29 +01002758 sqxtn(vform, result, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002759 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002760 case "sqxtunt_z_zz"_h:
Martyn Capewellb5636e52020-09-17 11:21:29 +01002761 top = true;
2762 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002763 case "sqxtunb_z_zz"_h:
Martyn Capewellb5636e52020-09-17 11:21:29 +01002764 sqxtun(vform, result, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002765 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002766 case "uqxtnt_z_zz"_h:
Martyn Capewellb5636e52020-09-17 11:21:29 +01002767 top = true;
2768 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002769 case "uqxtnb_z_zz"_h:
Martyn Capewellb5636e52020-09-17 11:21:29 +01002770 uqxtn(vform, result, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002771 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002772 case "rshrnt_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002773 top = true;
2774 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002775 case "rshrnb_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002776 rshrn(vform, result, zn, right_shift_dist);
2777 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002778 case "shrnt_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002779 top = true;
2780 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002781 case "shrnb_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002782 shrn(vform, result, zn, right_shift_dist);
2783 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002784 case "sqrshrnt_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002785 top = true;
2786 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002787 case "sqrshrnb_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002788 sqrshrn(vform, result, zn, right_shift_dist);
2789 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002790 case "sqrshrunt_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002791 top = true;
2792 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002793 case "sqrshrunb_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002794 sqrshrun(vform, result, zn, right_shift_dist);
2795 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002796 case "sqshrnt_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002797 top = true;
2798 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002799 case "sqshrnb_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002800 sqshrn(vform, result, zn, right_shift_dist);
2801 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002802 case "sqshrunt_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002803 top = true;
2804 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002805 case "sqshrunb_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002806 sqshrun(vform, result, zn, right_shift_dist);
2807 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002808 case "uqrshrnt_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002809 top = true;
2810 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002811 case "uqrshrnb_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002812 uqrshrn(vform, result, zn, right_shift_dist);
2813 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002814 case "uqshrnt_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002815 top = true;
2816 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002817 case "uqshrnb_z_zi"_h:
Martyn Capewellea9b4072020-10-09 11:25:26 +01002818 uqshrn(vform, result, zn, right_shift_dist);
2819 break;
Martyn Capewell6bf28752020-08-05 11:57:06 +01002820 default:
2821 VIXL_UNIMPLEMENTED();
2822 }
Martyn Capewellb5636e52020-09-17 11:21:29 +01002823
2824 if (top) {
2825 // Keep even elements, replace odd elements with the results.
2826 xtn(vform, zd, zd);
2827 zip1(vform, zd, zd, result);
2828 } else {
2829 // Zero odd elements, replace even elements with the results.
2830 SimVRegister zero;
2831 zero.Clear();
2832 zip1(vform, zd, result, zero);
2833 }
Martyn Capewell6bf28752020-08-05 11:57:06 +01002834}
2835
Martyn Capewellc7275e62020-09-24 14:06:07 +01002836void Simulator::SimulateSVEInterleavedArithLong(const Instruction* instr) {
Martyn Capewella2d7fbb2020-09-18 18:22:54 +01002837 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01002838 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002839 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01002840 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewellc7275e62020-09-24 14:06:07 +01002841 SimVRegister temp, zn_b, zm_b, zn_t, zm_t;
2842
2843 // Construct temporary registers containing the even (bottom) and odd (top)
2844 // elements.
TatWai Chong236e7ae2020-09-13 14:55:04 -07002845 VectorFormat vform_half = VectorFormatHalfWidth(vform);
2846 pack_even_elements(vform_half, zn_b, zn);
2847 pack_even_elements(vform_half, zm_b, zm);
2848 pack_odd_elements(vform_half, zn_t, zn);
2849 pack_odd_elements(vform_half, zm_t, zm);
Martyn Capewellc7275e62020-09-24 14:06:07 +01002850
2851 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002852 case "sabdlb_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002853 sabdl(vform, zd, zn_b, zm_b);
2854 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002855 case "sabdlt_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002856 sabdl(vform, zd, zn_t, zm_t);
2857 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002858 case "saddlb_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002859 saddl(vform, zd, zn_b, zm_b);
2860 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002861 case "saddlbt_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002862 saddl(vform, zd, zn_b, zm_t);
2863 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002864 case "saddlt_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002865 saddl(vform, zd, zn_t, zm_t);
2866 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002867 case "ssublb_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002868 ssubl(vform, zd, zn_b, zm_b);
2869 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002870 case "ssublbt_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002871 ssubl(vform, zd, zn_b, zm_t);
2872 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002873 case "ssublt_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002874 ssubl(vform, zd, zn_t, zm_t);
2875 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002876 case "ssubltb_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002877 ssubl(vform, zd, zn_t, zm_b);
2878 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002879 case "uabdlb_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002880 uabdl(vform, zd, zn_b, zm_b);
2881 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002882 case "uabdlt_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002883 uabdl(vform, zd, zn_t, zm_t);
2884 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002885 case "uaddlb_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002886 uaddl(vform, zd, zn_b, zm_b);
2887 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002888 case "uaddlt_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002889 uaddl(vform, zd, zn_t, zm_t);
2890 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002891 case "usublb_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002892 usubl(vform, zd, zn_b, zm_b);
2893 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002894 case "usublt_z_zz"_h:
Martyn Capewellc7275e62020-09-24 14:06:07 +01002895 usubl(vform, zd, zn_t, zm_t);
2896 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002897 case "sabalb_z_zzz"_h:
Martyn Capewell67d2f822020-10-13 16:39:33 +01002898 sabal(vform, zd, zn_b, zm_b);
2899 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002900 case "sabalt_z_zzz"_h:
Martyn Capewell67d2f822020-10-13 16:39:33 +01002901 sabal(vform, zd, zn_t, zm_t);
2902 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002903 case "uabalb_z_zzz"_h:
Martyn Capewell67d2f822020-10-13 16:39:33 +01002904 uabal(vform, zd, zn_b, zm_b);
2905 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002906 case "uabalt_z_zzz"_h:
Martyn Capewell67d2f822020-10-13 16:39:33 +01002907 uabal(vform, zd, zn_t, zm_t);
2908 break;
Martyn Capewellc7275e62020-09-24 14:06:07 +01002909 default:
2910 VIXL_UNIMPLEMENTED();
2911 }
2912}
2913
mmc28a4415fe42025-01-24 11:10:30 +00002914void Simulator::SimulateSVEPmull128(const Instruction* instr) {
2915 SimVRegister& zd = ReadVRegister(instr->GetRd());
2916 SimVRegister& zm = ReadVRegister(instr->GetRm());
2917 SimVRegister& zn = ReadVRegister(instr->GetRn());
2918 SimVRegister zn_temp, zm_temp;
2919
2920 if (form_hash_ == "pmullb_z_zz_q"_h) {
2921 pack_even_elements(kFormatVnD, zn_temp, zn);
2922 pack_even_elements(kFormatVnD, zm_temp, zm);
2923 } else {
2924 VIXL_ASSERT(form_hash_ == "pmullt_z_zz_q"_h);
2925 pack_odd_elements(kFormatVnD, zn_temp, zn);
2926 pack_odd_elements(kFormatVnD, zm_temp, zm);
2927 }
2928 pmull(kFormatVnQ, zd, zn_temp, zm_temp);
2929}
2930
TatWai Chong236e7ae2020-09-13 14:55:04 -07002931void Simulator::SimulateSVEIntMulLongVec(const Instruction* instr) {
2932 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewellc7275e62020-09-24 14:06:07 +01002933 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewellc7275e62020-09-24 14:06:07 +01002934 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewellc7275e62020-09-24 14:06:07 +01002935 SimVRegister& zn = ReadVRegister(instr->GetRn());
TatWai Chong236e7ae2020-09-13 14:55:04 -07002936 SimVRegister temp, zn_b, zm_b, zn_t, zm_t;
2937 VectorFormat vform_half = VectorFormatHalfWidth(vform);
2938 pack_even_elements(vform_half, zn_b, zn);
2939 pack_even_elements(vform_half, zm_b, zm);
2940 pack_odd_elements(vform_half, zn_t, zn);
2941 pack_odd_elements(vform_half, zm_t, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002942
2943 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002944 case "pmullb_z_zz"_h:
mmc28a4415fe42025-01-24 11:10:30 +00002945 // Size '10' is undefined.
2946 if (vform == kFormatVnS) {
TatWai Chong236e7ae2020-09-13 14:55:04 -07002947 VIXL_UNIMPLEMENTED();
2948 }
2949 pmull(vform, zd, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002950 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002951 case "pmullt_z_zz"_h:
mmc28a4415fe42025-01-24 11:10:30 +00002952 // Size '10' is undefined.
2953 if (vform == kFormatVnS) {
TatWai Chong236e7ae2020-09-13 14:55:04 -07002954 VIXL_UNIMPLEMENTED();
2955 }
2956 pmull(vform, zd, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002957 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002958 case "smullb_z_zz"_h:
TatWai Chong236e7ae2020-09-13 14:55:04 -07002959 smull(vform, zd, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002960 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002961 case "smullt_z_zz"_h:
TatWai Chong236e7ae2020-09-13 14:55:04 -07002962 smull(vform, zd, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002963 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002964 case "sqdmullb_z_zz"_h:
TatWai Chong236e7ae2020-09-13 14:55:04 -07002965 sqdmull(vform, zd, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002966 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002967 case "sqdmullt_z_zz"_h:
TatWai Chong236e7ae2020-09-13 14:55:04 -07002968 sqdmull(vform, zd, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002969 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002970 case "umullb_z_zz"_h:
TatWai Chong236e7ae2020-09-13 14:55:04 -07002971 umull(vform, zd, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002972 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01002973 case "umullt_z_zz"_h:
TatWai Chong236e7ae2020-09-13 14:55:04 -07002974 umull(vform, zd, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01002975 break;
Martyn Capewell6bf28752020-08-05 11:57:06 +01002976 default:
2977 VIXL_UNIMPLEMENTED();
2978 }
2979}
2980
Martyn Capewell8b9c44b2020-10-14 18:21:42 +01002981void Simulator::SimulateSVEAddSubHigh(const Instruction* instr) {
2982 SimVRegister& zd = ReadVRegister(instr->GetRd());
2983 SimVRegister& zm = ReadVRegister(instr->GetRm());
2984 SimVRegister& zn = ReadVRegister(instr->GetRn());
2985 SimVRegister result;
2986 bool top = false;
2987
2988 VectorFormat vform_src = instr->GetSVEVectorFormat();
2989 if (vform_src == kFormatVnB) {
2990 VIXL_UNIMPLEMENTED();
2991 }
2992 VectorFormat vform = VectorFormatHalfWidth(vform_src);
2993
2994 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01002995 case "addhnt_z_zz"_h:
Martyn Capewell8b9c44b2020-10-14 18:21:42 +01002996 top = true;
2997 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01002998 case "addhnb_z_zz"_h:
Martyn Capewell8b9c44b2020-10-14 18:21:42 +01002999 addhn(vform, result, zn, zm);
3000 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003001 case "raddhnt_z_zz"_h:
Martyn Capewell8b9c44b2020-10-14 18:21:42 +01003002 top = true;
3003 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01003004 case "raddhnb_z_zz"_h:
Martyn Capewell8b9c44b2020-10-14 18:21:42 +01003005 raddhn(vform, result, zn, zm);
3006 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003007 case "rsubhnt_z_zz"_h:
Martyn Capewell8b9c44b2020-10-14 18:21:42 +01003008 top = true;
3009 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01003010 case "rsubhnb_z_zz"_h:
Martyn Capewell8b9c44b2020-10-14 18:21:42 +01003011 rsubhn(vform, result, zn, zm);
3012 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003013 case "subhnt_z_zz"_h:
Martyn Capewell8b9c44b2020-10-14 18:21:42 +01003014 top = true;
3015 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01003016 case "subhnb_z_zz"_h:
Martyn Capewell8b9c44b2020-10-14 18:21:42 +01003017 subhn(vform, result, zn, zm);
3018 break;
3019 default:
3020 VIXL_UNIMPLEMENTED();
3021 }
3022
3023 if (top) {
3024 // Keep even elements, replace odd elements with the results.
3025 xtn(vform, zd, zd);
3026 zip1(vform, zd, zd, result);
3027 } else {
3028 // Zero odd elements, replace even elements with the results.
3029 SimVRegister zero;
3030 zero.Clear();
3031 zip1(vform, zd, result, zero);
3032 }
3033}
3034
Martyn Capewellea9b4072020-10-09 11:25:26 +01003035void Simulator::SimulateSVEShiftLeftImm(const Instruction* instr) {
Martyn Capewell6bf28752020-08-05 11:57:06 +01003036 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003037 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell51dcef92020-10-08 16:04:12 +01003038 SimVRegister zn_b, zn_t;
3039
3040 std::pair<int, int> shift_and_lane_size =
3041 instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ false);
3042 int lane_size = shift_and_lane_size.second;
3043 VIXL_ASSERT((lane_size >= 0) &&
3044 (static_cast<unsigned>(lane_size) <= kDRegSizeInBytesLog2));
3045 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(lane_size + 1);
3046 int right_shift_dist = shift_and_lane_size.first;
3047 int left_shift_dist = (8 << lane_size) - right_shift_dist;
3048
3049 // Construct temporary registers containing the even (bottom) and odd (top)
3050 // elements.
TatWai Chong236e7ae2020-09-13 14:55:04 -07003051 VectorFormat vform_half = VectorFormatHalfWidth(vform);
3052 pack_even_elements(vform_half, zn_b, zn);
3053 pack_odd_elements(vform_half, zn_t, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003054
3055 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003056 case "sshllb_z_zi"_h:
Martyn Capewell51dcef92020-10-08 16:04:12 +01003057 sshll(vform, zd, zn_b, left_shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003058 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003059 case "sshllt_z_zi"_h:
Martyn Capewell51dcef92020-10-08 16:04:12 +01003060 sshll(vform, zd, zn_t, left_shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003061 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003062 case "ushllb_z_zi"_h:
Martyn Capewell51dcef92020-10-08 16:04:12 +01003063 ushll(vform, zd, zn_b, left_shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003064 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003065 case "ushllt_z_zi"_h:
Martyn Capewell51dcef92020-10-08 16:04:12 +01003066 ushll(vform, zd, zn_t, left_shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003067 break;
3068 default:
3069 VIXL_UNIMPLEMENTED();
3070 }
3071}
3072
TatWai Chonga0a28e42021-03-11 21:19:08 -08003073void Simulator::SimulateSVESaturatingMulAddHigh(const Instruction* instr) {
3074 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01003075 SimVRegister& zda = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003076 SimVRegister& zn = ReadVRegister(instr->GetRn());
TatWai Chonga0a28e42021-03-11 21:19:08 -08003077 unsigned zm_code = instr->GetRm();
3078 int index = -1;
3079 bool is_mla = false;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003080
3081 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003082 case "sqrdmlah_z_zzz"_h:
TatWai Chonga0a28e42021-03-11 21:19:08 -08003083 is_mla = true;
3084 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01003085 case "sqrdmlsh_z_zzz"_h:
TatWai Chonga0a28e42021-03-11 21:19:08 -08003086 // Nothing to do.
Martyn Capewell6bf28752020-08-05 11:57:06 +01003087 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003088 case "sqrdmlah_z_zzzi_h"_h:
TatWai Chonga0a28e42021-03-11 21:19:08 -08003089 is_mla = true;
3090 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01003091 case "sqrdmlsh_z_zzzi_h"_h:
TatWai Chonga0a28e42021-03-11 21:19:08 -08003092 vform = kFormatVnH;
3093 index = (instr->ExtractBit(22) << 2) | instr->ExtractBits(20, 19);
3094 zm_code = instr->ExtractBits(18, 16);
3095 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003096 case "sqrdmlah_z_zzzi_s"_h:
TatWai Chonga0a28e42021-03-11 21:19:08 -08003097 is_mla = true;
3098 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01003099 case "sqrdmlsh_z_zzzi_s"_h:
TatWai Chonga0a28e42021-03-11 21:19:08 -08003100 vform = kFormatVnS;
3101 index = instr->ExtractBits(20, 19);
3102 zm_code = instr->ExtractBits(18, 16);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003103 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003104 case "sqrdmlah_z_zzzi_d"_h:
TatWai Chonga0a28e42021-03-11 21:19:08 -08003105 is_mla = true;
3106 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01003107 case "sqrdmlsh_z_zzzi_d"_h:
TatWai Chonga0a28e42021-03-11 21:19:08 -08003108 vform = kFormatVnD;
3109 index = instr->ExtractBit(20);
3110 zm_code = instr->ExtractBits(19, 16);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003111 break;
3112 default:
3113 VIXL_UNIMPLEMENTED();
3114 }
TatWai Chonga0a28e42021-03-11 21:19:08 -08003115
3116 SimVRegister& zm = ReadVRegister(zm_code);
3117 SimVRegister zm_idx;
3118 if (index >= 0) {
3119 dup_elements_to_segments(vform, zm_idx, zm, index);
3120 }
3121
3122 if (is_mla) {
3123 sqrdmlah(vform, zda, zn, (index >= 0) ? zm_idx : zm);
3124 } else {
3125 sqrdmlsh(vform, zda, zn, (index >= 0) ? zm_idx : zm);
3126 }
Martyn Capewell6bf28752020-08-05 11:57:06 +01003127}
3128
Martyn Capewell6bf28752020-08-05 11:57:06 +01003129void Simulator::Simulate_ZdaD_ZnS_ZmS_imm(const Instruction* instr) {
3130 SimVRegister& zda = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003131 SimVRegister& zn = ReadVRegister(instr->GetRn());
TatWai Chong05545662020-12-18 20:53:05 -08003132 SimVRegister& zm = ReadVRegister(instr->ExtractBits(19, 16));
3133
3134 SimVRegister temp, zm_idx, zn_b, zn_t;
3135 Instr index = (instr->ExtractBit(20) << 1) | instr->ExtractBit(11);
3136 dup_elements_to_segments(kFormatVnS, temp, zm, index);
3137 pack_even_elements(kFormatVnS, zm_idx, temp);
3138 pack_even_elements(kFormatVnS, zn_b, zn);
3139 pack_odd_elements(kFormatVnS, zn_t, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003140
3141 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003142 case "sqdmlalb_z_zzzi_d"_h:
TatWai Chong05545662020-12-18 20:53:05 -08003143 sqdmlal(kFormatVnD, zda, zn_b, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003144 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003145 case "sqdmlalt_z_zzzi_d"_h:
TatWai Chong05545662020-12-18 20:53:05 -08003146 sqdmlal(kFormatVnD, zda, zn_t, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003147 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003148 case "sqdmlslb_z_zzzi_d"_h:
TatWai Chong05545662020-12-18 20:53:05 -08003149 sqdmlsl(kFormatVnD, zda, zn_b, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003150 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003151 case "sqdmlslt_z_zzzi_d"_h:
TatWai Chong05545662020-12-18 20:53:05 -08003152 sqdmlsl(kFormatVnD, zda, zn_t, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003153 break;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003154 default:
3155 VIXL_UNIMPLEMENTED();
3156 }
3157}
3158
Martyn Capewell6bf28752020-08-05 11:57:06 +01003159void Simulator::Simulate_ZdaS_ZnH_ZmH(const Instruction* instr) {
3160 SimVRegister& zda = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003161 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003162 SimVRegister& zn = ReadVRegister(instr->GetRn());
TatWai Chongba9a1482020-10-01 20:25:54 -07003163
3164 SimVRegister temp, zn_b, zm_b, zn_t, zm_t;
3165 pack_even_elements(kFormatVnH, zn_b, zn);
3166 pack_even_elements(kFormatVnH, zm_b, zm);
3167 pack_odd_elements(kFormatVnH, zn_t, zn);
3168 pack_odd_elements(kFormatVnH, zm_t, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003169
3170 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003171 case "fmlalb_z_zzz"_h:
TatWai Chongba9a1482020-10-01 20:25:54 -07003172 fmlal(kFormatVnS, zda, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003173 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003174 case "fmlalt_z_zzz"_h:
TatWai Chongba9a1482020-10-01 20:25:54 -07003175 fmlal(kFormatVnS, zda, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003176 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003177 case "fmlslb_z_zzz"_h:
TatWai Chongba9a1482020-10-01 20:25:54 -07003178 fmlsl(kFormatVnS, zda, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003179 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003180 case "fmlslt_z_zzz"_h:
TatWai Chongba9a1482020-10-01 20:25:54 -07003181 fmlsl(kFormatVnS, zda, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003182 break;
3183 default:
3184 VIXL_UNIMPLEMENTED();
3185 }
3186}
3187
3188void Simulator::Simulate_ZdaS_ZnH_ZmH_imm(const Instruction* instr) {
3189 SimVRegister& zda = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003190 SimVRegister& zn = ReadVRegister(instr->GetRn());
TatWai Chong05545662020-12-18 20:53:05 -08003191 SimVRegister& zm = ReadVRegister(instr->ExtractBits(18, 16));
3192
3193 SimVRegister temp, zm_idx, zn_b, zn_t;
3194 Instr index = (instr->ExtractBits(20, 19) << 1) | instr->ExtractBit(11);
3195 dup_elements_to_segments(kFormatVnH, temp, zm, index);
3196 pack_even_elements(kFormatVnH, zm_idx, temp);
3197 pack_even_elements(kFormatVnH, zn_b, zn);
3198 pack_odd_elements(kFormatVnH, zn_t, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003199
3200 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003201 case "fmlalb_z_zzzi_s"_h:
Martyn Capewell317abf72021-02-24 17:12:46 +00003202 fmlal(kFormatVnS, zda, zn_b, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003203 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003204 case "fmlalt_z_zzzi_s"_h:
Martyn Capewell317abf72021-02-24 17:12:46 +00003205 fmlal(kFormatVnS, zda, zn_t, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003206 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003207 case "fmlslb_z_zzzi_s"_h:
Martyn Capewell317abf72021-02-24 17:12:46 +00003208 fmlsl(kFormatVnS, zda, zn_b, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003209 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003210 case "fmlslt_z_zzzi_s"_h:
Martyn Capewell317abf72021-02-24 17:12:46 +00003211 fmlsl(kFormatVnS, zda, zn_t, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003212 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003213 case "sqdmlalb_z_zzzi_s"_h:
TatWai Chong05545662020-12-18 20:53:05 -08003214 sqdmlal(kFormatVnS, zda, zn_b, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003215 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003216 case "sqdmlalt_z_zzzi_s"_h:
TatWai Chong05545662020-12-18 20:53:05 -08003217 sqdmlal(kFormatVnS, zda, zn_t, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003218 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003219 case "sqdmlslb_z_zzzi_s"_h:
TatWai Chong05545662020-12-18 20:53:05 -08003220 sqdmlsl(kFormatVnS, zda, zn_b, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003221 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003222 case "sqdmlslt_z_zzzi_s"_h:
TatWai Chong05545662020-12-18 20:53:05 -08003223 sqdmlsl(kFormatVnS, zda, zn_t, zm_idx);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003224 break;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003225 default:
3226 VIXL_UNIMPLEMENTED();
3227 }
3228}
3229
Martyn Capewell6bf28752020-08-05 11:57:06 +01003230void Simulator::Simulate_ZdaT_PgM_ZnTb(const Instruction* instr) {
TatWai Chong602aa122020-10-05 16:28:27 -07003231 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01003232 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003233 SimVRegister& zda = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003234 SimVRegister& zn = ReadVRegister(instr->GetRn());
TatWai Chong602aa122020-10-05 16:28:27 -07003235 SimVRegister result;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003236
3237 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003238 case "sadalp_z_p_z"_h:
TatWai Chong602aa122020-10-05 16:28:27 -07003239 sadalp(vform, result, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003240 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003241 case "uadalp_z_p_z"_h:
TatWai Chong602aa122020-10-05 16:28:27 -07003242 uadalp(vform, result, zn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003243 break;
3244 default:
3245 VIXL_UNIMPLEMENTED();
3246 }
TatWai Chong602aa122020-10-05 16:28:27 -07003247 mov_merging(vform, zda, pg, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003248}
3249
Martyn Capewellc4b56bb2020-10-14 15:45:14 +01003250void Simulator::SimulateSVEAddSubCarry(const Instruction* instr) {
3251 VectorFormat vform = (instr->ExtractBit(22) == 0) ? kFormatVnS : kFormatVnD;
3252 SimVRegister& zda = ReadVRegister(instr->GetRd());
3253 SimVRegister& zm = ReadVRegister(instr->GetRm());
3254 SimVRegister& zn = ReadVRegister(instr->GetRn());
3255
3256 SimVRegister not_zn;
3257 not_(vform, not_zn, zn);
3258
3259 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003260 case "adclb_z_zzz"_h:
Martyn Capewellc4b56bb2020-10-14 15:45:14 +01003261 adcl(vform, zda, zn, zm, /* top = */ false);
3262 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003263 case "adclt_z_zzz"_h:
Martyn Capewellc4b56bb2020-10-14 15:45:14 +01003264 adcl(vform, zda, zn, zm, /* top = */ true);
3265 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003266 case "sbclb_z_zzz"_h:
Martyn Capewellc4b56bb2020-10-14 15:45:14 +01003267 adcl(vform, zda, not_zn, zm, /* top = */ false);
3268 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003269 case "sbclt_z_zzz"_h:
Martyn Capewellc4b56bb2020-10-14 15:45:14 +01003270 adcl(vform, zda, not_zn, zm, /* top = */ true);
3271 break;
3272 default:
3273 VIXL_UNIMPLEMENTED();
3274 }
3275}
3276
Martyn Capewell6bf28752020-08-05 11:57:06 +01003277void Simulator::Simulate_ZdaT_ZnT_ZmT(const Instruction* instr) {
Martyn Capewelleb37ef32020-09-09 16:46:41 +01003278 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01003279 SimVRegister& zda = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003280 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003281 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003282
3283 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003284 case "saba_z_zzz"_h:
Martyn Capewelleb37ef32020-09-09 16:46:41 +01003285 saba(vform, zda, zn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003286 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003287 case "uaba_z_zzz"_h:
Martyn Capewelleb37ef32020-09-09 16:46:41 +01003288 uaba(vform, zda, zn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003289 break;
3290 default:
3291 VIXL_UNIMPLEMENTED();
3292 }
3293}
3294
TatWai Chongada6b352020-11-06 13:48:09 -08003295void Simulator::SimulateSVEComplexIntMulAdd(const Instruction* instr) {
Martyn Capewell6bf28752020-08-05 11:57:06 +01003296 SimVRegister& zda = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003297 SimVRegister& zn = ReadVRegister(instr->GetRn());
TatWai Chongada6b352020-11-06 13:48:09 -08003298 int rot = instr->ExtractBits(11, 10) * 90;
Martyn Capewell0ebd9e72021-02-23 17:08:24 +00003299 // vform and zm are only valid for the vector form of instruction.
TatWai Chong6b67f6e2020-12-03 23:37:57 -08003300 VectorFormat vform = instr->GetSVEVectorFormat();
3301 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003302
Martyn Capewell0ebd9e72021-02-23 17:08:24 +00003303 // Inputs for indexed form of instruction.
3304 SimVRegister& zm_h = ReadVRegister(instr->ExtractBits(18, 16));
3305 SimVRegister& zm_s = ReadVRegister(instr->ExtractBits(19, 16));
3306 int idx_h = instr->ExtractBits(20, 19);
3307 int idx_s = instr->ExtractBit(20);
3308
Martyn Capewell6bf28752020-08-05 11:57:06 +01003309 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003310 case "cmla_z_zzz"_h:
TatWai Chongada6b352020-11-06 13:48:09 -08003311 cmla(vform, zda, zda, zn, zm, rot);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003312 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003313 case "cmla_z_zzzi_h"_h:
Martyn Capewell0ebd9e72021-02-23 17:08:24 +00003314 cmla(kFormatVnH, zda, zda, zn, zm_h, idx_h, rot);
TatWai Chong6b67f6e2020-12-03 23:37:57 -08003315 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003316 case "cmla_z_zzzi_s"_h:
Martyn Capewell0ebd9e72021-02-23 17:08:24 +00003317 cmla(kFormatVnS, zda, zda, zn, zm_s, idx_s, rot);
TatWai Chong6b67f6e2020-12-03 23:37:57 -08003318 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003319 case "sqrdcmlah_z_zzz"_h:
TatWai Chongada6b352020-11-06 13:48:09 -08003320 sqrdcmlah(vform, zda, zda, zn, zm, rot);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003321 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003322 case "sqrdcmlah_z_zzzi_h"_h:
Martyn Capewell0ebd9e72021-02-23 17:08:24 +00003323 sqrdcmlah(kFormatVnH, zda, zda, zn, zm_h, idx_h, rot);
TatWai Chong6b67f6e2020-12-03 23:37:57 -08003324 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003325 case "sqrdcmlah_z_zzzi_s"_h:
Martyn Capewell0ebd9e72021-02-23 17:08:24 +00003326 sqrdcmlah(kFormatVnS, zda, zda, zn, zm_s, idx_s, rot);
TatWai Chong6b67f6e2020-12-03 23:37:57 -08003327 break;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003328 default:
3329 VIXL_UNIMPLEMENTED();
3330 }
3331}
3332
3333void Simulator::Simulate_ZdaT_ZnT_const(const Instruction* instr) {
Martyn Capewell3a3560f2020-09-11 15:32:08 +01003334 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003335 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell3a3560f2020-09-11 15:32:08 +01003336
3337 std::pair<int, int> shift_and_lane_size =
3338 instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ false);
3339 int lane_size = shift_and_lane_size.second;
3340 VIXL_ASSERT((lane_size >= 0) &&
3341 (static_cast<unsigned>(lane_size) <= kDRegSizeInBytesLog2));
3342 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(lane_size);
3343 int shift_dist = shift_and_lane_size.first;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003344
3345 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003346 case "srsra_z_zi"_h:
Martyn Capewell3a3560f2020-09-11 15:32:08 +01003347 srsra(vform, zd, zn, shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003348 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003349 case "ssra_z_zi"_h:
Martyn Capewell3a3560f2020-09-11 15:32:08 +01003350 ssra(vform, zd, zn, shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003351 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003352 case "ursra_z_zi"_h:
Martyn Capewell3a3560f2020-09-11 15:32:08 +01003353 ursra(vform, zd, zn, shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003354 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003355 case "usra_z_zi"_h:
Martyn Capewell3a3560f2020-09-11 15:32:08 +01003356 usra(vform, zd, zn, shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003357 break;
3358 default:
3359 VIXL_UNIMPLEMENTED();
3360 }
3361}
3362
3363void Simulator::Simulate_ZdaT_ZnTb_ZmTb(const Instruction* instr) {
Martyn Capewell4a454b42020-11-19 18:18:10 +00003364 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01003365 SimVRegister& zda = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003366 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003367 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell4a454b42020-11-19 18:18:10 +00003368
TatWai Chong5c080292020-12-13 03:57:15 -08003369 SimVRegister zero, zn_b, zm_b, zn_t, zm_t;
3370 zero.Clear();
3371
Martyn Capewell4a454b42020-11-19 18:18:10 +00003372 VectorFormat vform_half = VectorFormatHalfWidth(vform);
TatWai Chong5c080292020-12-13 03:57:15 -08003373 uzp1(vform_half, zn_b, zn, zero);
3374 uzp1(vform_half, zm_b, zm, zero);
3375 uzp2(vform_half, zn_t, zn, zero);
3376 uzp2(vform_half, zm_t, zm, zero);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003377
3378 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003379 case "smlalb_z_zzz"_h:
Martyn Capewell4a454b42020-11-19 18:18:10 +00003380 smlal(vform, zda, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003381 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003382 case "smlalt_z_zzz"_h:
Martyn Capewell4a454b42020-11-19 18:18:10 +00003383 smlal(vform, zda, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003384 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003385 case "smlslb_z_zzz"_h:
Martyn Capewell4a454b42020-11-19 18:18:10 +00003386 smlsl(vform, zda, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003387 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003388 case "smlslt_z_zzz"_h:
Martyn Capewell4a454b42020-11-19 18:18:10 +00003389 smlsl(vform, zda, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003390 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003391 case "sqdmlalb_z_zzz"_h:
TatWai Chong3cb35a62020-12-05 21:22:08 -08003392 sqdmlal(vform, zda, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003393 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003394 case "sqdmlalbt_z_zzz"_h:
TatWai Chong5c080292020-12-13 03:57:15 -08003395 sqdmlal(vform, zda, zn_b, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003396 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003397 case "sqdmlalt_z_zzz"_h:
TatWai Chong3cb35a62020-12-05 21:22:08 -08003398 sqdmlal(vform, zda, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003399 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003400 case "sqdmlslb_z_zzz"_h:
TatWai Chong3cb35a62020-12-05 21:22:08 -08003401 sqdmlsl(vform, zda, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003402 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003403 case "sqdmlslbt_z_zzz"_h:
TatWai Chong5c080292020-12-13 03:57:15 -08003404 sqdmlsl(vform, zda, zn_b, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003405 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003406 case "sqdmlslt_z_zzz"_h:
TatWai Chong3cb35a62020-12-05 21:22:08 -08003407 sqdmlsl(vform, zda, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003408 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003409 case "umlalb_z_zzz"_h:
Martyn Capewell4a454b42020-11-19 18:18:10 +00003410 umlal(vform, zda, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003411 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003412 case "umlalt_z_zzz"_h:
Martyn Capewell4a454b42020-11-19 18:18:10 +00003413 umlal(vform, zda, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003414 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003415 case "umlslb_z_zzz"_h:
Martyn Capewell4a454b42020-11-19 18:18:10 +00003416 umlsl(vform, zda, zn_b, zm_b);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003417 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003418 case "umlslt_z_zzz"_h:
Martyn Capewell4a454b42020-11-19 18:18:10 +00003419 umlsl(vform, zda, zn_t, zm_t);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003420 break;
3421 default:
3422 VIXL_UNIMPLEMENTED();
3423 }
3424}
3425
Martyn Capewell1bb3f1a2020-11-04 18:54:02 +00003426void Simulator::SimulateSVEComplexDotProduct(const Instruction* instr) {
Martyn Capewellf4da2202020-11-03 17:42:57 +00003427 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01003428 SimVRegister& zda = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003429 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewellf4da2202020-11-03 17:42:57 +00003430 int rot = instr->ExtractBits(11, 10) * 90;
Martyn Capewell1bb3f1a2020-11-04 18:54:02 +00003431 unsigned zm_code = instr->GetRm();
3432 int index = -1;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003433
3434 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003435 case "cdot_z_zzz"_h:
Martyn Capewell1bb3f1a2020-11-04 18:54:02 +00003436 // Nothing to do.
3437 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003438 case "cdot_z_zzzi_s"_h:
Martyn Capewell1bb3f1a2020-11-04 18:54:02 +00003439 index = zm_code >> 3;
3440 zm_code &= 0x7;
3441 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003442 case "cdot_z_zzzi_d"_h:
Martyn Capewell1bb3f1a2020-11-04 18:54:02 +00003443 index = zm_code >> 4;
3444 zm_code &= 0xf;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003445 break;
3446 default:
3447 VIXL_UNIMPLEMENTED();
3448 }
Martyn Capewell1bb3f1a2020-11-04 18:54:02 +00003449
3450 SimVRegister temp;
3451 SimVRegister& zm = ReadVRegister(zm_code);
3452 if (index >= 0) dup_elements_to_segments(vform, temp, zm, index);
3453 cdot(vform, zda, zda, zn, (index >= 0) ? temp : zm, rot);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003454}
3455
Martyn Capewellb1b95782020-10-23 15:59:49 +01003456void Simulator::SimulateSVEBitwiseTernary(const Instruction* instr) {
3457 VectorFormat vform = kFormatVnD;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003458 SimVRegister& zdn = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003459 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewellb1b95782020-10-23 15:59:49 +01003460 SimVRegister& zk = ReadVRegister(instr->GetRn());
3461 SimVRegister temp;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003462
3463 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003464 case "bcax_z_zzz"_h:
Martyn Capewellb1b95782020-10-23 15:59:49 +01003465 bic(vform, temp, zm, zk);
3466 eor(vform, zdn, temp, zdn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003467 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003468 case "bsl1n_z_zzz"_h:
Martyn Capewellb1b95782020-10-23 15:59:49 +01003469 not_(vform, temp, zdn);
3470 bsl(vform, zdn, zk, temp, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003471 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003472 case "bsl2n_z_zzz"_h:
Martyn Capewellb1b95782020-10-23 15:59:49 +01003473 not_(vform, temp, zm);
3474 bsl(vform, zdn, zk, zdn, temp);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003475 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003476 case "bsl_z_zzz"_h:
Martyn Capewellb1b95782020-10-23 15:59:49 +01003477 bsl(vform, zdn, zk, zdn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003478 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003479 case "eor3_z_zzz"_h:
Martyn Capewellb1b95782020-10-23 15:59:49 +01003480 eor(vform, temp, zdn, zm);
3481 eor(vform, zdn, temp, zk);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003482 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003483 case "nbsl_z_zzz"_h:
Martyn Capewellb1b95782020-10-23 15:59:49 +01003484 bsl(vform, zdn, zk, zdn, zm);
3485 not_(vform, zdn, zdn);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003486 break;
3487 default:
3488 VIXL_UNIMPLEMENTED();
3489 }
3490}
3491
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003492void Simulator::SimulateSVEHalvingAddSub(const Instruction* instr) {
3493 VectorFormat vform = instr->GetSVEVectorFormat();
3494 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
3495 SimVRegister& zdn = ReadVRegister(instr->GetRd());
3496 SimVRegister& zm = ReadVRegister(instr->GetRn());
3497 SimVRegister result;
3498
3499 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003500 case "shadd_z_p_zz"_h:
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003501 add(vform, result, zdn, zm).Halve(vform);
3502 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003503 case "shsub_z_p_zz"_h:
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003504 sub(vform, result, zdn, zm).Halve(vform);
3505 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003506 case "shsubr_z_p_zz"_h:
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003507 sub(vform, result, zm, zdn).Halve(vform);
3508 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003509 case "srhadd_z_p_zz"_h:
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003510 add(vform, result, zdn, zm).Halve(vform).Round(vform);
3511 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003512 case "uhadd_z_p_zz"_h:
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003513 add(vform, result, zdn, zm).Uhalve(vform);
3514 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003515 case "uhsub_z_p_zz"_h:
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003516 sub(vform, result, zdn, zm).Uhalve(vform);
3517 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003518 case "uhsubr_z_p_zz"_h:
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003519 sub(vform, result, zm, zdn).Uhalve(vform);
3520 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003521 case "urhadd_z_p_zz"_h:
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003522 add(vform, result, zdn, zm).Uhalve(vform).Round(vform);
3523 break;
3524 default:
3525 VIXL_UNIMPLEMENTED();
Martyn Capewell9b532192020-09-15 16:20:11 +01003526 break;
3527 }
3528 mov_merging(vform, zdn, pg, result);
3529}
3530
3531void Simulator::SimulateSVESaturatingArithmetic(const Instruction* instr) {
3532 VectorFormat vform = instr->GetSVEVectorFormat();
3533 SimVRegister& zdn = ReadVRegister(instr->GetRd());
3534 SimVRegister& zm = ReadVRegister(instr->GetRn());
3535 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
3536 SimVRegister result;
3537
3538 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003539 case "sqadd_z_p_zz"_h:
Martyn Capewell9b532192020-09-15 16:20:11 +01003540 add(vform, result, zdn, zm).SignedSaturate(vform);
3541 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003542 case "sqsub_z_p_zz"_h:
Martyn Capewell9b532192020-09-15 16:20:11 +01003543 sub(vform, result, zdn, zm).SignedSaturate(vform);
3544 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003545 case "sqsubr_z_p_zz"_h:
Martyn Capewell9b532192020-09-15 16:20:11 +01003546 sub(vform, result, zm, zdn).SignedSaturate(vform);
3547 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003548 case "suqadd_z_p_zz"_h:
Martyn Capewell9b532192020-09-15 16:20:11 +01003549 suqadd(vform, result, zdn, zm);
3550 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003551 case "uqadd_z_p_zz"_h:
Martyn Capewell9b532192020-09-15 16:20:11 +01003552 add(vform, result, zdn, zm).UnsignedSaturate(vform);
3553 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003554 case "uqsub_z_p_zz"_h:
Martyn Capewell9b532192020-09-15 16:20:11 +01003555 sub(vform, result, zdn, zm).UnsignedSaturate(vform);
3556 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003557 case "uqsubr_z_p_zz"_h:
Martyn Capewell9b532192020-09-15 16:20:11 +01003558 sub(vform, result, zm, zdn).UnsignedSaturate(vform);
3559 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003560 case "usqadd_z_p_zz"_h:
Martyn Capewell9b532192020-09-15 16:20:11 +01003561 usqadd(vform, result, zdn, zm);
3562 break;
3563 default:
3564 VIXL_UNIMPLEMENTED();
3565 break;
Martyn Capewell4e1980d2020-09-04 11:22:41 +01003566 }
3567 mov_merging(vform, zdn, pg, result);
3568}
3569
Martyn Capewellfa1e2112020-09-16 16:53:09 +01003570void Simulator::SimulateSVEIntArithPair(const Instruction* instr) {
3571 VectorFormat vform = instr->GetSVEVectorFormat();
3572 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
3573 SimVRegister& zdn = ReadVRegister(instr->GetRd());
3574 SimVRegister& zm = ReadVRegister(instr->GetRn());
3575 SimVRegister result;
3576
3577 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003578 case "addp_z_p_zz"_h:
Martyn Capewellfa1e2112020-09-16 16:53:09 +01003579 addp(vform, result, zdn, zm);
3580 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003581 case "smaxp_z_p_zz"_h:
Martyn Capewellfa1e2112020-09-16 16:53:09 +01003582 smaxp(vform, result, zdn, zm);
3583 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003584 case "sminp_z_p_zz"_h:
Martyn Capewellfa1e2112020-09-16 16:53:09 +01003585 sminp(vform, result, zdn, zm);
3586 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003587 case "umaxp_z_p_zz"_h:
Martyn Capewellfa1e2112020-09-16 16:53:09 +01003588 umaxp(vform, result, zdn, zm);
3589 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003590 case "uminp_z_p_zz"_h:
Martyn Capewellfa1e2112020-09-16 16:53:09 +01003591 uminp(vform, result, zdn, zm);
3592 break;
3593 default:
3594 VIXL_UNIMPLEMENTED();
3595 break;
3596 }
3597 mov_merging(vform, zdn, pg, result);
3598}
3599
Martyn Capewell6bf28752020-08-05 11:57:06 +01003600void Simulator::Simulate_ZdnT_PgM_ZdnT_ZmT(const Instruction* instr) {
Martyn Capewell14e4ddd2021-02-24 16:42:03 +00003601 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01003602 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003603 SimVRegister& zdn = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003604 SimVRegister& zm = ReadVRegister(instr->GetRn());
Martyn Capewell14e4ddd2021-02-24 16:42:03 +00003605 SimVRegister result;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003606
3607 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003608 case "faddp_z_p_zz"_h:
Martyn Capewell14e4ddd2021-02-24 16:42:03 +00003609 faddp(vform, result, zdn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003610 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003611 case "fmaxnmp_z_p_zz"_h:
Martyn Capewell14e4ddd2021-02-24 16:42:03 +00003612 fmaxnmp(vform, result, zdn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003613 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003614 case "fmaxp_z_p_zz"_h:
Martyn Capewell14e4ddd2021-02-24 16:42:03 +00003615 fmaxp(vform, result, zdn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003616 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003617 case "fminnmp_z_p_zz"_h:
Martyn Capewell14e4ddd2021-02-24 16:42:03 +00003618 fminnmp(vform, result, zdn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003619 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003620 case "fminp_z_p_zz"_h:
Martyn Capewell14e4ddd2021-02-24 16:42:03 +00003621 fminp(vform, result, zdn, zm);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003622 break;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003623 default:
3624 VIXL_UNIMPLEMENTED();
3625 }
Martyn Capewell14e4ddd2021-02-24 16:42:03 +00003626 mov_merging(vform, zdn, pg, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003627}
3628
3629void Simulator::Simulate_ZdnT_PgM_ZdnT_const(const Instruction* instr) {
3630 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003631 SimVRegister& zdn = ReadVRegister(instr->GetRd());
Martyn Capewelld8fc5432020-09-09 18:03:09 +01003632
3633 std::pair<int, int> shift_and_lane_size =
3634 instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ true);
3635 unsigned lane_size = shift_and_lane_size.second;
3636 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(lane_size);
3637 int right_shift_dist = shift_and_lane_size.first;
3638 int left_shift_dist = (8 << lane_size) - right_shift_dist;
3639 SimVRegister result;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003640
3641 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003642 case "sqshl_z_p_zi"_h:
Martyn Capewelld8fc5432020-09-09 18:03:09 +01003643 sqshl(vform, result, zdn, left_shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003644 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003645 case "sqshlu_z_p_zi"_h:
Martyn Capewelld8fc5432020-09-09 18:03:09 +01003646 sqshlu(vform, result, zdn, left_shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003647 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003648 case "srshr_z_p_zi"_h:
Martyn Capewelld8fc5432020-09-09 18:03:09 +01003649 sshr(vform, result, zdn, right_shift_dist).Round(vform);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003650 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003651 case "uqshl_z_p_zi"_h:
Martyn Capewelld8fc5432020-09-09 18:03:09 +01003652 uqshl(vform, result, zdn, left_shift_dist);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003653 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003654 case "urshr_z_p_zi"_h:
Martyn Capewelld8fc5432020-09-09 18:03:09 +01003655 ushr(vform, result, zdn, right_shift_dist).Round(vform);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003656 break;
3657 default:
3658 VIXL_UNIMPLEMENTED();
3659 }
Martyn Capewelld8fc5432020-09-09 18:03:09 +01003660 mov_merging(vform, zdn, pg, result);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003661}
3662
Martyn Capewell97ca8062020-10-23 14:45:14 +01003663void Simulator::SimulateSVEExclusiveOrRotate(const Instruction* instr) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003664 VIXL_ASSERT(form_hash_ == "xar_z_zzi"_h);
Martyn Capewell97ca8062020-10-23 14:45:14 +01003665
3666 SimVRegister& zdn = ReadVRegister(instr->GetRd());
3667 SimVRegister& zm = ReadVRegister(instr->GetRn());
3668
3669 std::pair<int, int> shift_and_lane_size =
3670 instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ false);
3671 unsigned lane_size = shift_and_lane_size.second;
3672 VIXL_ASSERT(lane_size <= kDRegSizeInBytesLog2);
3673 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(lane_size);
3674 int shift_dist = shift_and_lane_size.first;
Martyn Capewellb1b95782020-10-23 15:59:49 +01003675 eor(vform, zdn, zdn, zm);
Martyn Capewell97ca8062020-10-23 14:45:14 +01003676 ror(vform, zdn, zdn, shift_dist);
3677}
3678
Martyn Capewell6bf28752020-08-05 11:57:06 +01003679void Simulator::Simulate_ZdnT_ZdnT_ZmT_const(const Instruction* instr) {
Martyn Capewell819dcf92020-10-20 16:07:09 +01003680 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell6bf28752020-08-05 11:57:06 +01003681 SimVRegister& zdn = ReadVRegister(instr->GetRd());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003682 SimVRegister& zm = ReadVRegister(instr->GetRn());
Martyn Capewell819dcf92020-10-20 16:07:09 +01003683 int rot = (instr->ExtractBit(10) == 0) ? 90 : 270;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003684
3685 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003686 case "cadd_z_zz"_h:
Martyn Capewell819dcf92020-10-20 16:07:09 +01003687 cadd(vform, zdn, zdn, zm, rot);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003688 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003689 case "sqcadd_z_zz"_h:
Martyn Capewell819dcf92020-10-20 16:07:09 +01003690 cadd(vform, zdn, zdn, zm, rot, /* saturate = */ true);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003691 break;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003692 default:
3693 VIXL_UNIMPLEMENTED();
3694 }
3695}
3696
3697void Simulator::Simulate_ZtD_PgZ_ZnD_Xm(const Instruction* instr) {
3698 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003699 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell932cbb02020-11-10 16:53:31 +00003700 uint64_t xm = ReadXRegister(instr->GetRm());
3701
3702 LogicSVEAddressVector addr(xm, &zn, kFormatVnD);
3703 int msize = -1;
3704 bool is_signed = false;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003705
3706 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003707 case "ldnt1b_z_p_ar_d_64_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003708 msize = 0;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003709 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003710 case "ldnt1d_z_p_ar_d_64_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003711 msize = 3;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003712 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003713 case "ldnt1h_z_p_ar_d_64_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003714 msize = 1;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003715 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003716 case "ldnt1sb_z_p_ar_d_64_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003717 msize = 0;
3718 is_signed = true;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003719 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003720 case "ldnt1sh_z_p_ar_d_64_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003721 msize = 1;
3722 is_signed = true;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003723 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003724 case "ldnt1sw_z_p_ar_d_64_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003725 msize = 2;
3726 is_signed = true;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003727 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003728 case "ldnt1w_z_p_ar_d_64_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003729 msize = 2;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003730 break;
3731 default:
3732 VIXL_UNIMPLEMENTED();
3733 }
Martyn Capewell932cbb02020-11-10 16:53:31 +00003734 addr.SetMsizeInBytesLog2(msize);
3735 SVEStructuredLoadHelper(kFormatVnD, pg, instr->GetRt(), addr, is_signed);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003736}
3737
3738void Simulator::Simulate_ZtD_Pg_ZnD_Xm(const Instruction* instr) {
3739 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003740 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell1ac83572020-11-11 16:15:58 +00003741 uint64_t xm = ReadXRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003742
Martyn Capewell1ac83572020-11-11 16:15:58 +00003743 LogicSVEAddressVector addr(xm, &zn, kFormatVnD);
Martyn Capewelld48909d2022-05-03 16:38:38 +01003744 VIXL_ASSERT((form_hash_ == "stnt1b_z_p_ar_d_64_unscaled"_h) ||
3745 (form_hash_ == "stnt1d_z_p_ar_d_64_unscaled"_h) ||
3746 (form_hash_ == "stnt1h_z_p_ar_d_64_unscaled"_h) ||
3747 (form_hash_ == "stnt1w_z_p_ar_d_64_unscaled"_h));
Martyn Capewell1ac83572020-11-11 16:15:58 +00003748
3749 addr.SetMsizeInBytesLog2(
3750 instr->GetSVEMsizeFromDtype(/* is_signed = */ false));
3751 SVEStructuredStoreHelper(kFormatVnD, pg, instr->GetRt(), addr);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003752}
3753
3754void Simulator::Simulate_ZtS_PgZ_ZnS_Xm(const Instruction* instr) {
3755 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003756 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell932cbb02020-11-10 16:53:31 +00003757 uint64_t xm = ReadXRegister(instr->GetRm());
3758
3759 LogicSVEAddressVector addr(xm, &zn, kFormatVnS);
3760 int msize = -1;
3761 bool is_signed = false;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003762
3763 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01003764 case "ldnt1b_z_p_ar_s_x32_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003765 msize = 0;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003766 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003767 case "ldnt1h_z_p_ar_s_x32_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003768 msize = 1;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003769 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003770 case "ldnt1sb_z_p_ar_s_x32_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003771 msize = 0;
3772 is_signed = true;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003773 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003774 case "ldnt1sh_z_p_ar_s_x32_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003775 msize = 1;
3776 is_signed = true;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003777 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01003778 case "ldnt1w_z_p_ar_s_x32_unscaled"_h:
Martyn Capewell932cbb02020-11-10 16:53:31 +00003779 msize = 2;
Martyn Capewell6bf28752020-08-05 11:57:06 +01003780 break;
3781 default:
3782 VIXL_UNIMPLEMENTED();
3783 }
Martyn Capewell932cbb02020-11-10 16:53:31 +00003784 addr.SetMsizeInBytesLog2(msize);
3785 SVEStructuredLoadHelper(kFormatVnS, pg, instr->GetRt(), addr, is_signed);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003786}
3787
3788void Simulator::Simulate_ZtS_Pg_ZnS_Xm(const Instruction* instr) {
3789 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003790 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell1ac83572020-11-11 16:15:58 +00003791 uint64_t xm = ReadXRegister(instr->GetRm());
Martyn Capewell6bf28752020-08-05 11:57:06 +01003792
Martyn Capewell1ac83572020-11-11 16:15:58 +00003793 LogicSVEAddressVector addr(xm, &zn, kFormatVnS);
Martyn Capewelld48909d2022-05-03 16:38:38 +01003794 VIXL_ASSERT((form_hash_ == "stnt1b_z_p_ar_s_x32_unscaled"_h) ||
3795 (form_hash_ == "stnt1h_z_p_ar_s_x32_unscaled"_h) ||
3796 (form_hash_ == "stnt1w_z_p_ar_s_x32_unscaled"_h));
Martyn Capewell1ac83572020-11-11 16:15:58 +00003797
3798 addr.SetMsizeInBytesLog2(
3799 instr->GetSVEMsizeFromDtype(/* is_signed = */ false));
3800 SVEStructuredStoreHelper(kFormatVnS, pg, instr->GetRt(), addr);
Martyn Capewell6bf28752020-08-05 11:57:06 +01003801}
3802
Jacob Bramley18c97bd2019-01-18 16:01:08 +00003803void Simulator::VisitReserved(const Instruction* instr) {
3804 // UDF is the only instruction in this group, and the Decoder is precise here.
3805 VIXL_ASSERT(instr->Mask(ReservedMask) == UDF);
3806
3807 printf("UDF (permanently undefined) instruction at %p: 0x%08" PRIx32 "\n",
3808 reinterpret_cast<const void*>(instr),
3809 instr->GetInstructionBits());
3810 VIXL_ABORT_WITH_MSG("UNDEFINED (UDF)\n");
3811}
3812
3813
Alexandre Ramesd3832962016-07-04 15:03:43 +01003814void Simulator::VisitUnimplemented(const Instruction* instr) {
3815 printf("Unimplemented instruction at %p: 0x%08" PRIx32 "\n",
3816 reinterpret_cast<const void*>(instr),
3817 instr->GetInstructionBits());
3818 VIXL_UNIMPLEMENTED();
3819}
3820
3821
3822void Simulator::VisitUnallocated(const Instruction* instr) {
3823 printf("Unallocated instruction at %p: 0x%08" PRIx32 "\n",
3824 reinterpret_cast<const void*>(instr),
3825 instr->GetInstructionBits());
3826 VIXL_UNIMPLEMENTED();
3827}
3828
3829
3830void Simulator::VisitPCRelAddressing(const Instruction* instr) {
3831 VIXL_ASSERT((instr->Mask(PCRelAddressingMask) == ADR) ||
3832 (instr->Mask(PCRelAddressingMask) == ADRP));
3833
3834 WriteRegister(instr->GetRd(), instr->GetImmPCOffsetTarget());
3835}
3836
3837
3838void Simulator::VisitUnconditionalBranch(const Instruction* instr) {
3839 switch (instr->Mask(UnconditionalBranchMask)) {
3840 case BL:
3841 WriteLr(instr->GetNextInstruction());
mmc28a3c407232024-06-19 15:03:55 +01003842 GCSPush(reinterpret_cast<uint64_t>(instr->GetNextInstruction()));
Alexandre Ramesd3832962016-07-04 15:03:43 +01003843 VIXL_FALLTHROUGH();
3844 case B:
3845 WritePc(instr->GetImmPCOffsetTarget());
3846 break;
3847 default:
3848 VIXL_UNREACHABLE();
3849 }
3850}
3851
3852
3853void Simulator::VisitConditionalBranch(const Instruction* instr) {
3854 VIXL_ASSERT(instr->Mask(ConditionalBranchMask) == B_cond);
3855 if (ConditionPassed(instr->GetConditionBranch())) {
3856 WritePc(instr->GetImmPCOffsetTarget());
3857 }
3858}
3859
Martyn Capewellcb963f72018-10-22 15:25:28 +01003860BType Simulator::GetBTypeFromInstruction(const Instruction* instr) const {
3861 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
3862 case BLR:
3863 case BLRAA:
3864 case BLRAB:
3865 case BLRAAZ:
3866 case BLRABZ:
3867 return BranchAndLink;
3868 case BR:
3869 case BRAA:
3870 case BRAB:
3871 case BRAAZ:
3872 case BRABZ:
3873 if ((instr->GetRn() == 16) || (instr->GetRn() == 17) ||
3874 !PcIsInGuardedPage()) {
3875 return BranchFromUnguardedOrToIP;
3876 }
3877 return BranchFromGuardedNotToIP;
3878 }
3879 return DefaultBType;
3880}
Alexandre Ramesd3832962016-07-04 15:03:43 +01003881
3882void Simulator::VisitUnconditionalBranchToRegister(const Instruction* instr) {
Jacob Bramleyca789742018-09-13 14:25:46 +01003883 bool authenticate = false;
3884 bool link = false;
Chris Jones8eca2b72023-09-13 10:09:12 +01003885 bool ret = false;
mmc28a3c407232024-06-19 15:03:55 +01003886 bool compare_gcs = false;
Martyn Capewellcb963f72018-10-22 15:25:28 +01003887 uint64_t addr = ReadXRegister(instr->GetRn());
Jacob Bramleyca789742018-09-13 14:25:46 +01003888 uint64_t context = 0;
Alexandre Ramesd3832962016-07-04 15:03:43 +01003889
3890 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
3891 case BLR:
Jacob Bramleyca789742018-09-13 14:25:46 +01003892 link = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01003893 VIXL_FALLTHROUGH();
3894 case BR:
Jacob Bramleyca789742018-09-13 14:25:46 +01003895 break;
3896
3897 case BLRAAZ:
3898 case BLRABZ:
3899 link = true;
3900 VIXL_FALLTHROUGH();
3901 case BRAAZ:
3902 case BRABZ:
3903 authenticate = true;
Jacob Bramleyca789742018-09-13 14:25:46 +01003904 break;
3905
3906 case BLRAA:
3907 case BLRAB:
3908 link = true;
3909 VIXL_FALLTHROUGH();
3910 case BRAA:
3911 case BRAB:
3912 authenticate = true;
Jacob Bramleyca789742018-09-13 14:25:46 +01003913 context = ReadXRegister(instr->GetRd());
3914 break;
3915
3916 case RETAA:
3917 case RETAB:
3918 authenticate = true;
3919 addr = ReadXRegister(kLinkRegCode);
3920 context = ReadXRegister(31, Reg31IsStackPointer);
Chris Jones8eca2b72023-09-13 10:09:12 +01003921 VIXL_FALLTHROUGH();
3922 case RET:
mmc28a3c407232024-06-19 15:03:55 +01003923 compare_gcs = true;
Chris Jones8eca2b72023-09-13 10:09:12 +01003924 ret = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01003925 break;
3926 default:
3927 VIXL_UNREACHABLE();
3928 }
Jacob Bramleyca789742018-09-13 14:25:46 +01003929
Jacob Bramleyca789742018-09-13 14:25:46 +01003930 if (authenticate) {
3931 PACKey key = (instr->ExtractBit(10) == 0) ? kPACKeyIA : kPACKeyIB;
3932 addr = AuthPAC(addr, context, key, kInstructionPointer);
3933
3934 int error_lsb = GetTopPACBit(addr, kInstructionPointer) - 2;
3935 if (((addr >> error_lsb) & 0x3) != 0x0) {
3936 VIXL_ABORT_WITH_MSG("Failed to authenticate pointer.");
3937 }
3938 }
3939
mmc28a3c407232024-06-19 15:03:55 +01003940 if (compare_gcs) {
3941 uint64_t expected_lr = GCSPeek();
3942 char msg[128];
3943 if (expected_lr != 0) {
3944 if ((expected_lr & 0x3) != 0) {
3945 snprintf(msg,
3946 sizeof(msg),
TheLastRar49d6efa2024-10-15 16:37:27 +01003947 "GCS contains misaligned return address: 0x%016" PRIx64 "\n",
mmc28a3c407232024-06-19 15:03:55 +01003948 expected_lr);
3949 ReportGCSFailure(msg);
3950 } else if ((addr != 0) && (addr != expected_lr)) {
3951 snprintf(msg,
3952 sizeof(msg),
TheLastRar49d6efa2024-10-15 16:37:27 +01003953 "GCS mismatch: lr = 0x%016" PRIx64 ", gcs = 0x%016" PRIx64
3954 "\n",
mmc28a3c407232024-06-19 15:03:55 +01003955 addr,
3956 expected_lr);
3957 ReportGCSFailure(msg);
3958 }
3959 GCSPop();
3960 }
3961 }
3962
3963 if (link) {
3964 WriteLr(instr->GetNextInstruction());
3965 GCSPush(reinterpret_cast<uint64_t>(instr->GetNextInstruction()));
3966 }
3967
Chris Jones8eca2b72023-09-13 10:09:12 +01003968 if (!ret) {
3969 // Check for interceptions to the target address, if one is found, call it.
3970 MetaDataDepot::BranchInterceptionAbstract* interception =
3971 meta_data_.FindBranchInterception(addr);
3972
3973 if (interception != nullptr) {
3974 // Instead of writing the address of the function to the PC, call the
3975 // function's interception directly. We change the address that will be
3976 // branched to so that afterwards we continue execution from
3977 // the address in the LR. Note: the interception may modify the LR so
3978 // store it before calling the interception.
3979 addr = ReadRegister<uint64_t>(kLinkRegCode);
3980 (*interception)(this);
3981 }
3982 }
3983
Martyn Capewellcb963f72018-10-22 15:25:28 +01003984 WriteNextBType(GetBTypeFromInstruction(instr));
TatWai Chong6767df02022-03-25 11:33:54 -07003985 WritePc(Instruction::Cast(addr));
Alexandre Ramesd3832962016-07-04 15:03:43 +01003986}
3987
3988
3989void Simulator::VisitTestBranch(const Instruction* instr) {
3990 unsigned bit_pos =
3991 (instr->GetImmTestBranchBit5() << 5) | instr->GetImmTestBranchBit40();
3992 bool bit_zero = ((ReadXRegister(instr->GetRt()) >> bit_pos) & 1) == 0;
3993 bool take_branch = false;
3994 switch (instr->Mask(TestBranchMask)) {
3995 case TBZ:
3996 take_branch = bit_zero;
3997 break;
3998 case TBNZ:
3999 take_branch = !bit_zero;
4000 break;
4001 default:
4002 VIXL_UNIMPLEMENTED();
4003 }
4004 if (take_branch) {
4005 WritePc(instr->GetImmPCOffsetTarget());
4006 }
4007}
4008
4009
4010void Simulator::VisitCompareBranch(const Instruction* instr) {
4011 unsigned rt = instr->GetRt();
4012 bool take_branch = false;
4013 switch (instr->Mask(CompareBranchMask)) {
4014 case CBZ_w:
4015 take_branch = (ReadWRegister(rt) == 0);
4016 break;
4017 case CBZ_x:
4018 take_branch = (ReadXRegister(rt) == 0);
4019 break;
4020 case CBNZ_w:
4021 take_branch = (ReadWRegister(rt) != 0);
4022 break;
4023 case CBNZ_x:
4024 take_branch = (ReadXRegister(rt) != 0);
4025 break;
4026 default:
4027 VIXL_UNIMPLEMENTED();
4028 }
4029 if (take_branch) {
4030 WritePc(instr->GetImmPCOffsetTarget());
4031 }
4032}
4033
4034
4035void Simulator::AddSubHelper(const Instruction* instr, int64_t op2) {
4036 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
4037 bool set_flags = instr->GetFlagsUpdate();
4038 int64_t new_val = 0;
4039 Instr operation = instr->Mask(AddSubOpMask);
4040
4041 switch (operation) {
4042 case ADD:
4043 case ADDS: {
4044 new_val = AddWithCarry(reg_size,
4045 set_flags,
4046 ReadRegister(reg_size,
4047 instr->GetRn(),
4048 instr->GetRnMode()),
4049 op2);
4050 break;
4051 }
4052 case SUB:
4053 case SUBS: {
4054 new_val = AddWithCarry(reg_size,
4055 set_flags,
4056 ReadRegister(reg_size,
4057 instr->GetRn(),
4058 instr->GetRnMode()),
4059 ~op2,
4060 1);
4061 break;
4062 }
4063 default:
4064 VIXL_UNREACHABLE();
4065 }
4066
4067 WriteRegister(reg_size,
4068 instr->GetRd(),
4069 new_val,
4070 LogRegWrites,
4071 instr->GetRdMode());
4072}
4073
4074
4075void Simulator::VisitAddSubShifted(const Instruction* instr) {
mmc28a94b311a2023-03-16 15:27:28 +00004076 // Add/sub/adds/subs don't allow ROR as a shift mode.
4077 VIXL_ASSERT(instr->GetShiftDP() != ROR);
4078
Alexandre Ramesd3832962016-07-04 15:03:43 +01004079 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
4080 int64_t op2 = ShiftOperand(reg_size,
4081 ReadRegister(reg_size, instr->GetRm()),
4082 static_cast<Shift>(instr->GetShiftDP()),
4083 instr->GetImmDPShift());
4084 AddSubHelper(instr, op2);
4085}
4086
4087
4088void Simulator::VisitAddSubImmediate(const Instruction* instr) {
4089 int64_t op2 = instr->GetImmAddSub()
Jacob Bramley2b66cd62020-06-05 14:07:55 +01004090 << ((instr->GetImmAddSubShift() == 1) ? 12 : 0);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004091 AddSubHelper(instr, op2);
4092}
4093
4094
4095void Simulator::VisitAddSubExtended(const Instruction* instr) {
4096 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
4097 int64_t op2 = ExtendValue(reg_size,
4098 ReadRegister(reg_size, instr->GetRm()),
4099 static_cast<Extend>(instr->GetExtendMode()),
4100 instr->GetImmExtendShift());
4101 AddSubHelper(instr, op2);
4102}
4103
4104
4105void Simulator::VisitAddSubWithCarry(const Instruction* instr) {
4106 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
4107 int64_t op2 = ReadRegister(reg_size, instr->GetRm());
4108 int64_t new_val;
4109
4110 if ((instr->Mask(AddSubOpMask) == SUB) ||
4111 (instr->Mask(AddSubOpMask) == SUBS)) {
4112 op2 = ~op2;
4113 }
4114
4115 new_val = AddWithCarry(reg_size,
4116 instr->GetFlagsUpdate(),
4117 ReadRegister(reg_size, instr->GetRn()),
4118 op2,
4119 ReadC());
4120
4121 WriteRegister(reg_size, instr->GetRd(), new_val);
4122}
4123
4124
Alexander Gilday2487f142018-11-05 13:07:27 +00004125void Simulator::VisitRotateRightIntoFlags(const Instruction* instr) {
4126 switch (instr->Mask(RotateRightIntoFlagsMask)) {
4127 case RMIF: {
4128 uint64_t value = ReadRegister<uint64_t>(instr->GetRn());
4129 unsigned shift = instr->GetImmRMIFRotation();
4130 unsigned mask = instr->GetNzcv();
4131 uint64_t rotated = RotateRight(value, shift, kXRegSize);
4132
4133 ReadNzcv().SetFlags((rotated & mask) | (ReadNzcv().GetFlags() & ~mask));
4134 break;
4135 }
4136 }
4137}
4138
4139
4140void Simulator::VisitEvaluateIntoFlags(const Instruction* instr) {
4141 uint32_t value = ReadRegister<uint32_t>(instr->GetRn());
4142 unsigned msb = (instr->Mask(EvaluateIntoFlagsMask) == SETF16) ? 15 : 7;
4143
4144 unsigned sign_bit = (value >> msb) & 1;
4145 unsigned overflow_bit = (value >> (msb + 1)) & 1;
4146 ReadNzcv().SetN(sign_bit);
4147 ReadNzcv().SetZ((value << (31 - msb)) == 0);
4148 ReadNzcv().SetV(sign_bit ^ overflow_bit);
4149}
4150
4151
Alexandre Ramesd3832962016-07-04 15:03:43 +01004152void Simulator::VisitLogicalShifted(const Instruction* instr) {
4153 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
4154 Shift shift_type = static_cast<Shift>(instr->GetShiftDP());
4155 unsigned shift_amount = instr->GetImmDPShift();
4156 int64_t op2 = ShiftOperand(reg_size,
4157 ReadRegister(reg_size, instr->GetRm()),
4158 shift_type,
4159 shift_amount);
4160 if (instr->Mask(NOT) == NOT) {
4161 op2 = ~op2;
4162 }
4163 LogicalHelper(instr, op2);
4164}
4165
4166
4167void Simulator::VisitLogicalImmediate(const Instruction* instr) {
Martyn Capewella26a26c2020-09-23 11:30:53 +01004168 if (instr->GetImmLogical() == 0) {
4169 VIXL_UNIMPLEMENTED();
4170 } else {
4171 LogicalHelper(instr, instr->GetImmLogical());
4172 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01004173}
4174
4175
4176void Simulator::LogicalHelper(const Instruction* instr, int64_t op2) {
4177 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
4178 int64_t op1 = ReadRegister(reg_size, instr->GetRn());
4179 int64_t result = 0;
4180 bool update_flags = false;
4181
4182 // Switch on the logical operation, stripping out the NOT bit, as it has a
4183 // different meaning for logical immediate instructions.
4184 switch (instr->Mask(LogicalOpMask & ~NOT)) {
4185 case ANDS:
4186 update_flags = true;
4187 VIXL_FALLTHROUGH();
4188 case AND:
4189 result = op1 & op2;
4190 break;
4191 case ORR:
4192 result = op1 | op2;
4193 break;
4194 case EOR:
4195 result = op1 ^ op2;
4196 break;
4197 default:
4198 VIXL_UNIMPLEMENTED();
4199 }
4200
4201 if (update_flags) {
4202 ReadNzcv().SetN(CalcNFlag(result, reg_size));
4203 ReadNzcv().SetZ(CalcZFlag(result));
4204 ReadNzcv().SetC(0);
4205 ReadNzcv().SetV(0);
4206 LogSystemRegister(NZCV);
4207 }
4208
4209 WriteRegister(reg_size,
4210 instr->GetRd(),
4211 result,
4212 LogRegWrites,
4213 instr->GetRdMode());
4214}
4215
4216
4217void Simulator::VisitConditionalCompareRegister(const Instruction* instr) {
4218 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
4219 ConditionalCompareHelper(instr, ReadRegister(reg_size, instr->GetRm()));
4220}
4221
4222
4223void Simulator::VisitConditionalCompareImmediate(const Instruction* instr) {
4224 ConditionalCompareHelper(instr, instr->GetImmCondCmp());
4225}
4226
4227
4228void Simulator::ConditionalCompareHelper(const Instruction* instr,
4229 int64_t op2) {
4230 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
4231 int64_t op1 = ReadRegister(reg_size, instr->GetRn());
4232
4233 if (ConditionPassed(instr->GetCondition())) {
4234 // If the condition passes, set the status flags to the result of comparing
4235 // the operands.
4236 if (instr->Mask(ConditionalCompareMask) == CCMP) {
4237 AddWithCarry(reg_size, true, op1, ~op2, 1);
4238 } else {
4239 VIXL_ASSERT(instr->Mask(ConditionalCompareMask) == CCMN);
4240 AddWithCarry(reg_size, true, op1, op2, 0);
4241 }
4242 } else {
4243 // If the condition fails, set the status flags to the nzcv immediate.
4244 ReadNzcv().SetFlags(instr->GetNzcv());
4245 LogSystemRegister(NZCV);
4246 }
4247}
4248
4249
4250void Simulator::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
4251 int offset = instr->GetImmLSUnsigned() << instr->GetSizeLS();
4252 LoadStoreHelper(instr, offset, Offset);
4253}
4254
4255
4256void Simulator::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
4257 LoadStoreHelper(instr, instr->GetImmLS(), Offset);
4258}
4259
4260
4261void Simulator::VisitLoadStorePreIndex(const Instruction* instr) {
4262 LoadStoreHelper(instr, instr->GetImmLS(), PreIndex);
4263}
4264
4265
4266void Simulator::VisitLoadStorePostIndex(const Instruction* instr) {
4267 LoadStoreHelper(instr, instr->GetImmLS(), PostIndex);
4268}
4269
4270
Alexander Gilday311edf22018-10-29 13:41:41 +00004271template <typename T1, typename T2>
4272void Simulator::LoadAcquireRCpcUnscaledOffsetHelper(const Instruction* instr) {
4273 unsigned rt = instr->GetRt();
4274 unsigned rn = instr->GetRn();
4275
4276 unsigned element_size = sizeof(T2);
4277 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
4278 int offset = instr->GetImmLS();
4279 address += offset;
4280
4281 // Verify that the address is available to the host.
4282 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
4283
4284 // Check the alignment of `address`.
4285 if (AlignDown(address, 16) != AlignDown(address + element_size - 1, 16)) {
4286 VIXL_ALIGNMENT_EXCEPTION();
4287 }
4288
Chris Jones30e7bbd2024-02-15 15:05:25 +00004289 VIXL_DEFINE_OR_RETURN(value, MemRead<T2>(address));
4290
4291 WriteRegister<T1>(rt, static_cast<T1>(value));
Alexander Gilday311edf22018-10-29 13:41:41 +00004292
4293 // Approximate load-acquire by issuing a full barrier after the load.
TheLastRar49d6efa2024-10-15 16:37:27 +01004294 VIXL_SYNC();
Alexander Gilday311edf22018-10-29 13:41:41 +00004295
Jacob Bramley423e5422019-11-13 19:15:55 +00004296 LogRead(rt, GetPrintRegisterFormat(element_size), address);
Alexander Gilday311edf22018-10-29 13:41:41 +00004297}
4298
4299
4300template <typename T>
4301void Simulator::StoreReleaseUnscaledOffsetHelper(const Instruction* instr) {
4302 unsigned rt = instr->GetRt();
4303 unsigned rn = instr->GetRn();
4304
4305 unsigned element_size = sizeof(T);
4306 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
4307 int offset = instr->GetImmLS();
4308 address += offset;
4309
4310 // Verify that the address is available to the host.
4311 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
4312
4313 // Check the alignment of `address`.
4314 if (AlignDown(address, 16) != AlignDown(address + element_size - 1, 16)) {
4315 VIXL_ALIGNMENT_EXCEPTION();
4316 }
4317
4318 // Approximate store-release by issuing a full barrier after the load.
TheLastRar49d6efa2024-10-15 16:37:27 +01004319 VIXL_SYNC();
Alexander Gilday311edf22018-10-29 13:41:41 +00004320
Chris Jones3134e252024-02-29 13:44:20 +00004321 if (!MemWrite<T>(address, ReadRegister<T>(rt))) return;
Alexander Gilday311edf22018-10-29 13:41:41 +00004322
Jacob Bramley423e5422019-11-13 19:15:55 +00004323 LogWrite(rt, GetPrintRegisterFormat(element_size), address);
Alexander Gilday311edf22018-10-29 13:41:41 +00004324}
4325
4326
4327void Simulator::VisitLoadStoreRCpcUnscaledOffset(const Instruction* instr) {
4328 switch (instr->Mask(LoadStoreRCpcUnscaledOffsetMask)) {
4329 case LDAPURB:
4330 LoadAcquireRCpcUnscaledOffsetHelper<uint8_t, uint8_t>(instr);
4331 break;
4332 case LDAPURH:
4333 LoadAcquireRCpcUnscaledOffsetHelper<uint16_t, uint16_t>(instr);
4334 break;
4335 case LDAPUR_w:
4336 LoadAcquireRCpcUnscaledOffsetHelper<uint32_t, uint32_t>(instr);
4337 break;
4338 case LDAPUR_x:
4339 LoadAcquireRCpcUnscaledOffsetHelper<uint64_t, uint64_t>(instr);
4340 break;
4341 case LDAPURSB_w:
4342 LoadAcquireRCpcUnscaledOffsetHelper<int32_t, int8_t>(instr);
4343 break;
4344 case LDAPURSB_x:
4345 LoadAcquireRCpcUnscaledOffsetHelper<int64_t, int8_t>(instr);
4346 break;
4347 case LDAPURSH_w:
4348 LoadAcquireRCpcUnscaledOffsetHelper<int32_t, int16_t>(instr);
4349 break;
4350 case LDAPURSH_x:
4351 LoadAcquireRCpcUnscaledOffsetHelper<int64_t, int16_t>(instr);
4352 break;
4353 case LDAPURSW:
4354 LoadAcquireRCpcUnscaledOffsetHelper<int64_t, int32_t>(instr);
4355 break;
4356 case STLURB:
4357 StoreReleaseUnscaledOffsetHelper<uint8_t>(instr);
4358 break;
4359 case STLURH:
4360 StoreReleaseUnscaledOffsetHelper<uint16_t>(instr);
4361 break;
4362 case STLUR_w:
4363 StoreReleaseUnscaledOffsetHelper<uint32_t>(instr);
4364 break;
4365 case STLUR_x:
4366 StoreReleaseUnscaledOffsetHelper<uint64_t>(instr);
4367 break;
4368 }
4369}
4370
4371
Alexander Gilday75605592018-11-01 09:30:29 +00004372void Simulator::VisitLoadStorePAC(const Instruction* instr) {
4373 unsigned dst = instr->GetRt();
4374 unsigned addr_reg = instr->GetRn();
4375
4376 uint64_t address = ReadXRegister(addr_reg, Reg31IsStackPointer);
4377
4378 PACKey key = (instr->ExtractBit(23) == 0) ? kPACKeyDA : kPACKeyDB;
4379 address = AuthPAC(address, 0, key, kDataPointer);
4380
4381 int error_lsb = GetTopPACBit(address, kInstructionPointer) - 2;
4382 if (((address >> error_lsb) & 0x3) != 0x0) {
4383 VIXL_ABORT_WITH_MSG("Failed to authenticate pointer.");
4384 }
4385
4386
4387 if ((addr_reg == 31) && ((address % 16) != 0)) {
4388 // When the base register is SP the stack pointer is required to be
4389 // quadword aligned prior to the address calculation and write-backs.
4390 // Misalignment will cause a stack alignment fault.
4391 VIXL_ALIGNMENT_EXCEPTION();
4392 }
4393
4394 int64_t offset = instr->GetImmLSPAC();
4395 address += offset;
4396
4397 if (instr->Mask(LoadStorePACPreBit) == LoadStorePACPreBit) {
4398 // Pre-index mode.
4399 VIXL_ASSERT(offset != 0);
4400 WriteXRegister(addr_reg, address, LogRegWrites, Reg31IsStackPointer);
4401 }
4402
4403 uintptr_t addr_ptr = static_cast<uintptr_t>(address);
4404
4405 // Verify that the calculated address is available to the host.
4406 VIXL_ASSERT(address == addr_ptr);
4407
Chris Jones30e7bbd2024-02-15 15:05:25 +00004408 VIXL_DEFINE_OR_RETURN(value, MemRead<uint64_t>(addr_ptr));
4409
4410 WriteXRegister(dst, value, NoRegLog);
Alexander Gilday75605592018-11-01 09:30:29 +00004411 unsigned access_size = 1 << 3;
Jacob Bramley423e5422019-11-13 19:15:55 +00004412 LogRead(dst, GetPrintRegisterFormatForSize(access_size), addr_ptr);
Alexander Gilday75605592018-11-01 09:30:29 +00004413}
4414
4415
Alexandre Ramesd3832962016-07-04 15:03:43 +01004416void Simulator::VisitLoadStoreRegisterOffset(const Instruction* instr) {
4417 Extend ext = static_cast<Extend>(instr->GetExtendMode());
4418 VIXL_ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
4419 unsigned shift_amount = instr->GetImmShiftLS() * instr->GetSizeLS();
4420
4421 int64_t offset =
4422 ExtendValue(kXRegSize, ReadXRegister(instr->GetRm()), ext, shift_amount);
4423 LoadStoreHelper(instr, offset, Offset);
4424}
4425
4426
4427void Simulator::LoadStoreHelper(const Instruction* instr,
4428 int64_t offset,
4429 AddrMode addrmode) {
4430 unsigned srcdst = instr->GetRt();
4431 uintptr_t address = AddressModeHelper(instr->GetRn(), offset, addrmode);
4432
Jacob Bramley423e5422019-11-13 19:15:55 +00004433 bool rt_is_vreg = false;
4434 int extend_to_size = 0;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004435 LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreMask));
4436 switch (op) {
Chris Jones30e7bbd2024-02-15 15:05:25 +00004437 case LDRB_w: {
4438 VIXL_DEFINE_OR_RETURN(value, MemRead<uint8_t>(address));
4439 WriteWRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004440 extend_to_size = kWRegSizeInBytes;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004441 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004442 }
4443 case LDRH_w: {
4444 VIXL_DEFINE_OR_RETURN(value, MemRead<uint16_t>(address));
4445 WriteWRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004446 extend_to_size = kWRegSizeInBytes;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004447 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004448 }
4449 case LDR_w: {
4450 VIXL_DEFINE_OR_RETURN(value, MemRead<uint32_t>(address));
4451 WriteWRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004452 extend_to_size = kWRegSizeInBytes;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004453 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004454 }
4455 case LDR_x: {
4456 VIXL_DEFINE_OR_RETURN(value, MemRead<uint64_t>(address));
4457 WriteXRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004458 extend_to_size = kXRegSizeInBytes;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004459 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004460 }
4461 case LDRSB_w: {
4462 VIXL_DEFINE_OR_RETURN(value, MemRead<int8_t>(address));
4463 WriteWRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004464 extend_to_size = kWRegSizeInBytes;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004465 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004466 }
4467 case LDRSH_w: {
4468 VIXL_DEFINE_OR_RETURN(value, MemRead<int16_t>(address));
4469 WriteWRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004470 extend_to_size = kWRegSizeInBytes;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004471 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004472 }
4473 case LDRSB_x: {
4474 VIXL_DEFINE_OR_RETURN(value, MemRead<int8_t>(address));
4475 WriteXRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004476 extend_to_size = kXRegSizeInBytes;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004477 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004478 }
4479 case LDRSH_x: {
4480 VIXL_DEFINE_OR_RETURN(value, MemRead<int16_t>(address));
4481 WriteXRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004482 extend_to_size = kXRegSizeInBytes;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004483 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004484 }
4485 case LDRSW_x: {
4486 VIXL_DEFINE_OR_RETURN(value, MemRead<int32_t>(address));
4487 WriteXRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004488 extend_to_size = kXRegSizeInBytes;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004489 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004490 }
4491 case LDR_b: {
4492 VIXL_DEFINE_OR_RETURN(value, MemRead<uint8_t>(address));
4493 WriteBRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004494 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004495 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004496 }
4497 case LDR_h: {
4498 VIXL_DEFINE_OR_RETURN(value, MemRead<uint16_t>(address));
4499 WriteHRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004500 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004501 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004502 }
4503 case LDR_s: {
4504 VIXL_DEFINE_OR_RETURN(value, MemRead<float>(address));
4505 WriteSRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004506 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004507 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004508 }
4509 case LDR_d: {
4510 VIXL_DEFINE_OR_RETURN(value, MemRead<double>(address));
4511 WriteDRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004512 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004513 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004514 }
4515 case LDR_q: {
4516 VIXL_DEFINE_OR_RETURN(value, MemRead<qreg_t>(address));
4517 WriteQRegister(srcdst, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004518 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004519 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00004520 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01004521
4522 case STRB_w:
Chris Jones3134e252024-02-29 13:44:20 +00004523 if (!MemWrite<uint8_t>(address, ReadWRegister(srcdst))) return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004524 break;
4525 case STRH_w:
Chris Jones3134e252024-02-29 13:44:20 +00004526 if (!MemWrite<uint16_t>(address, ReadWRegister(srcdst))) return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004527 break;
4528 case STR_w:
Chris Jones3134e252024-02-29 13:44:20 +00004529 if (!MemWrite<uint32_t>(address, ReadWRegister(srcdst))) return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004530 break;
4531 case STR_x:
Chris Jones3134e252024-02-29 13:44:20 +00004532 if (!MemWrite<uint64_t>(address, ReadXRegister(srcdst))) return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004533 break;
4534 case STR_b:
Chris Jones3134e252024-02-29 13:44:20 +00004535 if (!MemWrite<uint8_t>(address, ReadBRegister(srcdst))) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00004536 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004537 break;
4538 case STR_h:
Chris Jones3134e252024-02-29 13:44:20 +00004539 if (!MemWrite<uint16_t>(address, ReadHRegisterBits(srcdst))) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00004540 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004541 break;
4542 case STR_s:
Chris Jones3134e252024-02-29 13:44:20 +00004543 if (!MemWrite<float>(address, ReadSRegister(srcdst))) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00004544 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004545 break;
4546 case STR_d:
Chris Jones3134e252024-02-29 13:44:20 +00004547 if (!MemWrite<double>(address, ReadDRegister(srcdst))) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00004548 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004549 break;
4550 case STR_q:
Chris Jones3134e252024-02-29 13:44:20 +00004551 if (!MemWrite<qreg_t>(address, ReadQRegister(srcdst))) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00004552 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004553 break;
4554
4555 // Ignore prfm hint instructions.
4556 case PRFM:
4557 break;
4558
4559 default:
4560 VIXL_UNIMPLEMENTED();
4561 }
4562
Jacob Bramley423e5422019-11-13 19:15:55 +00004563 // Print a detailed trace (including the memory address).
4564 bool extend = (extend_to_size != 0);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004565 unsigned access_size = 1 << instr->GetSizeLS();
Jacob Bramley423e5422019-11-13 19:15:55 +00004566 unsigned result_size = extend ? extend_to_size : access_size;
4567 PrintRegisterFormat print_format =
4568 rt_is_vreg ? GetPrintRegisterFormatForSizeTryFP(result_size)
4569 : GetPrintRegisterFormatForSize(result_size);
4570
Alexandre Ramesd3832962016-07-04 15:03:43 +01004571 if (instr->IsLoad()) {
Jacob Bramley423e5422019-11-13 19:15:55 +00004572 if (rt_is_vreg) {
4573 LogVRead(srcdst, print_format, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004574 } else {
Jacob Bramley423e5422019-11-13 19:15:55 +00004575 LogExtendingRead(srcdst, print_format, access_size, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004576 }
4577 } else if (instr->IsStore()) {
Jacob Bramley423e5422019-11-13 19:15:55 +00004578 if (rt_is_vreg) {
4579 LogVWrite(srcdst, print_format, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004580 } else {
Jacob Bramley423e5422019-11-13 19:15:55 +00004581 LogWrite(srcdst, GetPrintRegisterFormatForSize(result_size), address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004582 }
4583 } else {
4584 VIXL_ASSERT(op == PRFM);
4585 }
4586
4587 local_monitor_.MaybeClear();
4588}
4589
4590
4591void Simulator::VisitLoadStorePairOffset(const Instruction* instr) {
4592 LoadStorePairHelper(instr, Offset);
4593}
4594
4595
4596void Simulator::VisitLoadStorePairPreIndex(const Instruction* instr) {
4597 LoadStorePairHelper(instr, PreIndex);
4598}
4599
4600
4601void Simulator::VisitLoadStorePairPostIndex(const Instruction* instr) {
4602 LoadStorePairHelper(instr, PostIndex);
4603}
4604
4605
4606void Simulator::VisitLoadStorePairNonTemporal(const Instruction* instr) {
4607 LoadStorePairHelper(instr, Offset);
4608}
4609
4610
4611void Simulator::LoadStorePairHelper(const Instruction* instr,
4612 AddrMode addrmode) {
4613 unsigned rt = instr->GetRt();
4614 unsigned rt2 = instr->GetRt2();
4615 int element_size = 1 << instr->GetSizeLSPair();
4616 int64_t offset = instr->GetImmLSPair() * element_size;
4617 uintptr_t address = AddressModeHelper(instr->GetRn(), offset, addrmode);
4618 uintptr_t address2 = address + element_size;
4619
4620 LoadStorePairOp op =
4621 static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask));
4622
4623 // 'rt' and 'rt2' can only be aliased for stores.
4624 VIXL_ASSERT(((op & LoadStorePairLBit) == 0) || (rt != rt2));
4625
Jacob Bramley423e5422019-11-13 19:15:55 +00004626 bool rt_is_vreg = false;
4627 bool sign_extend = false;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004628 switch (op) {
4629 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS). We
4630 // will print a more detailed log.
4631 case LDP_w: {
Chris Jones30e7bbd2024-02-15 15:05:25 +00004632 VIXL_DEFINE_OR_RETURN(value, MemRead<uint32_t>(address));
4633 VIXL_DEFINE_OR_RETURN(value2, MemRead<uint32_t>(address2));
4634 WriteWRegister(rt, value, NoRegLog);
4635 WriteWRegister(rt2, value2, NoRegLog);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004636 break;
4637 }
4638 case LDP_s: {
Chris Jones30e7bbd2024-02-15 15:05:25 +00004639 VIXL_DEFINE_OR_RETURN(value, MemRead<float>(address));
4640 VIXL_DEFINE_OR_RETURN(value2, MemRead<float>(address2));
4641 WriteSRegister(rt, value, NoRegLog);
4642 WriteSRegister(rt2, value2, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004643 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004644 break;
4645 }
4646 case LDP_x: {
Chris Jones30e7bbd2024-02-15 15:05:25 +00004647 VIXL_DEFINE_OR_RETURN(value, MemRead<uint64_t>(address));
4648 VIXL_DEFINE_OR_RETURN(value2, MemRead<uint64_t>(address2));
4649 WriteXRegister(rt, value, NoRegLog);
4650 WriteXRegister(rt2, value2, NoRegLog);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004651 break;
4652 }
4653 case LDP_d: {
Chris Jones30e7bbd2024-02-15 15:05:25 +00004654 VIXL_DEFINE_OR_RETURN(value, MemRead<double>(address));
4655 VIXL_DEFINE_OR_RETURN(value2, MemRead<double>(address2));
4656 WriteDRegister(rt, value, NoRegLog);
4657 WriteDRegister(rt2, value2, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004658 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004659 break;
4660 }
4661 case LDP_q: {
Chris Jones30e7bbd2024-02-15 15:05:25 +00004662 VIXL_DEFINE_OR_RETURN(value, MemRead<qreg_t>(address));
4663 VIXL_DEFINE_OR_RETURN(value2, MemRead<qreg_t>(address2));
4664 WriteQRegister(rt, value, NoRegLog);
4665 WriteQRegister(rt2, value2, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004666 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004667 break;
4668 }
4669 case LDPSW_x: {
Chris Jones30e7bbd2024-02-15 15:05:25 +00004670 VIXL_DEFINE_OR_RETURN(value, MemRead<int32_t>(address));
4671 VIXL_DEFINE_OR_RETURN(value2, MemRead<int32_t>(address2));
4672 WriteXRegister(rt, value, NoRegLog);
4673 WriteXRegister(rt2, value2, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004674 sign_extend = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004675 break;
4676 }
4677 case STP_w: {
Chris Jones3134e252024-02-29 13:44:20 +00004678 if (!MemWrite<uint32_t>(address, ReadWRegister(rt))) return;
4679 if (!MemWrite<uint32_t>(address2, ReadWRegister(rt2))) return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004680 break;
4681 }
4682 case STP_s: {
Chris Jones3134e252024-02-29 13:44:20 +00004683 if (!MemWrite<float>(address, ReadSRegister(rt))) return;
4684 if (!MemWrite<float>(address2, ReadSRegister(rt2))) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00004685 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004686 break;
4687 }
4688 case STP_x: {
Chris Jones3134e252024-02-29 13:44:20 +00004689 if (!MemWrite<uint64_t>(address, ReadXRegister(rt))) return;
4690 if (!MemWrite<uint64_t>(address2, ReadXRegister(rt2))) return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004691 break;
4692 }
4693 case STP_d: {
Chris Jones3134e252024-02-29 13:44:20 +00004694 if (!MemWrite<double>(address, ReadDRegister(rt))) return;
4695 if (!MemWrite<double>(address2, ReadDRegister(rt2))) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00004696 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004697 break;
4698 }
4699 case STP_q: {
Chris Jones3134e252024-02-29 13:44:20 +00004700 if (!MemWrite<qreg_t>(address, ReadQRegister(rt))) return;
4701 if (!MemWrite<qreg_t>(address2, ReadQRegister(rt2))) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00004702 rt_is_vreg = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01004703 break;
4704 }
4705 default:
4706 VIXL_UNREACHABLE();
4707 }
4708
Jacob Bramley423e5422019-11-13 19:15:55 +00004709 // Print a detailed trace (including the memory address).
4710 unsigned result_size = sign_extend ? kXRegSizeInBytes : element_size;
4711 PrintRegisterFormat print_format =
4712 rt_is_vreg ? GetPrintRegisterFormatForSizeTryFP(result_size)
4713 : GetPrintRegisterFormatForSize(result_size);
4714
Alexandre Ramesd3832962016-07-04 15:03:43 +01004715 if (instr->IsLoad()) {
Jacob Bramley423e5422019-11-13 19:15:55 +00004716 if (rt_is_vreg) {
4717 LogVRead(rt, print_format, address);
4718 LogVRead(rt2, print_format, address2);
4719 } else if (sign_extend) {
4720 LogExtendingRead(rt, print_format, element_size, address);
4721 LogExtendingRead(rt2, print_format, element_size, address2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004722 } else {
Jacob Bramley423e5422019-11-13 19:15:55 +00004723 LogRead(rt, print_format, address);
4724 LogRead(rt2, print_format, address2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004725 }
4726 } else {
Jacob Bramley423e5422019-11-13 19:15:55 +00004727 if (rt_is_vreg) {
4728 LogVWrite(rt, print_format, address);
4729 LogVWrite(rt2, print_format, address2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004730 } else {
Jacob Bramley423e5422019-11-13 19:15:55 +00004731 LogWrite(rt, print_format, address);
4732 LogWrite(rt2, print_format, address2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01004733 }
4734 }
4735
4736 local_monitor_.MaybeClear();
4737}
4738
4739
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004740template <typename T>
4741void Simulator::CompareAndSwapHelper(const Instruction* instr) {
4742 unsigned rs = instr->GetRs();
4743 unsigned rt = instr->GetRt();
4744 unsigned rn = instr->GetRn();
4745
4746 unsigned element_size = sizeof(T);
4747 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
4748
Alexander Gilday3f89bf12018-10-25 14:03:49 +01004749 CheckIsValidUnalignedAtomicAccess(rn, address, element_size);
4750
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004751 bool is_acquire = instr->ExtractBit(22) == 1;
4752 bool is_release = instr->ExtractBit(15) == 1;
4753
4754 T comparevalue = ReadRegister<T>(rs);
4755 T newvalue = ReadRegister<T>(rt);
4756
4757 // The architecture permits that the data read clears any exclusive monitors
4758 // associated with that location, even if the compare subsequently fails.
4759 local_monitor_.Clear();
4760
Chris Jones30e7bbd2024-02-15 15:05:25 +00004761 VIXL_DEFINE_OR_RETURN(data, MemRead<T>(address));
4762
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004763 if (is_acquire) {
4764 // Approximate load-acquire by issuing a full barrier after the load.
TheLastRar49d6efa2024-10-15 16:37:27 +01004765 VIXL_SYNC();
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004766 }
4767
4768 if (data == comparevalue) {
4769 if (is_release) {
4770 // Approximate store-release by issuing a full barrier before the store.
TheLastRar49d6efa2024-10-15 16:37:27 +01004771 VIXL_SYNC();
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004772 }
Chris Jones3134e252024-02-29 13:44:20 +00004773 if (!MemWrite<T>(address, newvalue)) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00004774 LogWrite(rt, GetPrintRegisterFormatForSize(element_size), address);
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004775 }
Jacob Bramley3eb24e92020-07-03 18:17:36 +01004776 WriteRegister<T>(rs, data, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00004777 LogRead(rs, GetPrintRegisterFormatForSize(element_size), address);
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004778}
4779
Alexander Gilday3f89bf12018-10-25 14:03:49 +01004780
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004781template <typename T>
4782void Simulator::CompareAndSwapPairHelper(const Instruction* instr) {
4783 VIXL_ASSERT((sizeof(T) == 4) || (sizeof(T) == 8));
4784 unsigned rs = instr->GetRs();
4785 unsigned rt = instr->GetRt();
4786 unsigned rn = instr->GetRn();
4787
Jacob Bramley3eb24e92020-07-03 18:17:36 +01004788 VIXL_ASSERT((rs % 2 == 0) && (rt % 2 == 0));
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004789
4790 unsigned element_size = sizeof(T);
4791 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
Alexander Gilday3f89bf12018-10-25 14:03:49 +01004792
4793 CheckIsValidUnalignedAtomicAccess(rn, address, element_size * 2);
4794
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004795 uint64_t address2 = address + element_size;
4796
4797 bool is_acquire = instr->ExtractBit(22) == 1;
4798 bool is_release = instr->ExtractBit(15) == 1;
4799
4800 T comparevalue_high = ReadRegister<T>(rs + 1);
4801 T comparevalue_low = ReadRegister<T>(rs);
4802 T newvalue_high = ReadRegister<T>(rt + 1);
4803 T newvalue_low = ReadRegister<T>(rt);
4804
4805 // The architecture permits that the data read clears any exclusive monitors
4806 // associated with that location, even if the compare subsequently fails.
4807 local_monitor_.Clear();
4808
Chris Jones30e7bbd2024-02-15 15:05:25 +00004809 VIXL_DEFINE_OR_RETURN(data_low, MemRead<T>(address));
4810 VIXL_DEFINE_OR_RETURN(data_high, MemRead<T>(address2));
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004811
4812 if (is_acquire) {
4813 // Approximate load-acquire by issuing a full barrier after the load.
TheLastRar49d6efa2024-10-15 16:37:27 +01004814 VIXL_SYNC();
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004815 }
4816
4817 bool same =
4818 (data_high == comparevalue_high) && (data_low == comparevalue_low);
4819 if (same) {
4820 if (is_release) {
4821 // Approximate store-release by issuing a full barrier before the store.
TheLastRar49d6efa2024-10-15 16:37:27 +01004822 VIXL_SYNC();
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004823 }
4824
Chris Jones3134e252024-02-29 13:44:20 +00004825 if (!MemWrite<T>(address, newvalue_low)) return;
4826 if (!MemWrite<T>(address2, newvalue_high)) return;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004827 }
4828
Jacob Bramley3eb24e92020-07-03 18:17:36 +01004829 WriteRegister<T>(rs + 1, data_high, NoRegLog);
4830 WriteRegister<T>(rs, data_low, NoRegLog);
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004831
Jacob Bramley423e5422019-11-13 19:15:55 +00004832 PrintRegisterFormat format = GetPrintRegisterFormatForSize(element_size);
Jacob Bramley3eb24e92020-07-03 18:17:36 +01004833 LogRead(rs, format, address);
4834 LogRead(rs + 1, format, address2);
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004835
4836 if (same) {
Jacob Bramley3eb24e92020-07-03 18:17:36 +01004837 LogWrite(rt, format, address);
4838 LogWrite(rt + 1, format, address2);
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004839 }
4840}
4841
Jacob Bramley85a9c102019-12-09 17:48:29 +00004842bool Simulator::CanReadMemory(uintptr_t address, size_t size) {
TheLastRar49d6efa2024-10-15 16:37:27 +01004843#ifndef _WIN32
Jacob Bramley85a9c102019-12-09 17:48:29 +00004844 // To simulate fault-tolerant loads, we need to know what host addresses we
4845 // can access without generating a real fault. One way to do that is to
Martyn Capewelld42989c2020-11-10 14:32:56 +00004846 // attempt to `write()` the memory to a placeholder pipe[1]. This is more
4847 // portable and less intrusive than using (global) signal handlers.
Jacob Bramley85a9c102019-12-09 17:48:29 +00004848 //
4849 // [1]: https://stackoverflow.com/questions/7134590
4850
4851 size_t written = 0;
4852 bool can_read = true;
4853 // `write` will normally return after one invocation, but it is allowed to
4854 // handle only part of the operation, so wrap it in a loop.
4855 while (can_read && (written < size)) {
Martyn Capewelld42989c2020-11-10 14:32:56 +00004856 ssize_t result = write(placeholder_pipe_fd_[1],
Jacob Bramley85a9c102019-12-09 17:48:29 +00004857 reinterpret_cast<void*>(address + written),
4858 size - written);
4859 if (result > 0) {
4860 written += result;
4861 } else {
4862 switch (result) {
4863 case -EPERM:
4864 case -EFAULT:
4865 // The address range is not accessible.
4866 // `write` is supposed to return -EFAULT in this case, but in practice
4867 // it seems to return -EPERM, so we accept that too.
4868 can_read = false;
4869 break;
4870 case -EINTR:
4871 // The call was interrupted by a signal. Just try again.
4872 break;
4873 default:
4874 // Any other error is fatal.
4875 VIXL_ABORT();
4876 }
4877 }
4878 }
4879 // Drain the read side of the pipe. If we don't do this, we'll leak memory as
Martyn Capewelld42989c2020-11-10 14:32:56 +00004880 // the placeholder data is buffered. As before, we expect to drain the whole
4881 // write in one invocation, but cannot guarantee that, so we wrap it in a
4882 // loop. This function is primarily intended to implement SVE fault-tolerant
4883 // loads, so the maximum Z register size is a good default buffer size.
Jacob Bramley85a9c102019-12-09 17:48:29 +00004884 char buffer[kZRegMaxSizeInBytes];
4885 while (written > 0) {
Martyn Capewelld42989c2020-11-10 14:32:56 +00004886 ssize_t result = read(placeholder_pipe_fd_[0],
Jacob Bramley85a9c102019-12-09 17:48:29 +00004887 reinterpret_cast<void*>(buffer),
4888 sizeof(buffer));
4889 // `read` blocks, and returns 0 only at EOF. We should not hit EOF until
4890 // we've read everything that was written, so treat 0 as an error.
4891 if (result > 0) {
4892 VIXL_ASSERT(static_cast<size_t>(result) <= written);
4893 written -= result;
4894 } else {
4895 // For -EINTR, just try again. We can't handle any other error.
4896 VIXL_CHECK(result == -EINTR);
4897 }
4898 }
4899
4900 return can_read;
TheLastRar49d6efa2024-10-15 16:37:27 +01004901#else
4902 // To simulate fault-tolerant loads, we need to know what host addresses we
4903 // can access without generating a real fault
4904 // The pipe code above is almost but not fully compatible with Windows
4905 // Instead, use the platform specific API VirtualQuery()
4906 //
4907 // [2]: https://stackoverflow.com/a/18395247/9109981
4908
4909 bool can_read = true;
4910 MEMORY_BASIC_INFORMATION pageInfo;
4911
4912 size_t checked = 0;
4913 while (can_read && (checked < size)) {
4914 size_t result = VirtualQuery(reinterpret_cast<void*>(address + checked),
4915 &pageInfo,
4916 sizeof(pageInfo));
4917
4918 if (result < 0) {
4919 can_read = false;
4920 break;
4921 }
4922
4923 if (pageInfo.State != MEM_COMMIT) {
4924 can_read = false;
4925 break;
4926 }
4927
4928 if (pageInfo.Protect == PAGE_NOACCESS || pageInfo.Protect == PAGE_EXECUTE) {
4929 can_read = false;
4930 break;
4931 }
4932 checked += pageInfo.RegionSize -
4933 ((address + checked) -
4934 reinterpret_cast<uintptr_t>(pageInfo.BaseAddress));
4935 }
4936
4937 return can_read;
4938#endif
Jacob Bramley85a9c102019-12-09 17:48:29 +00004939}
Alexandre Ramesd3832962016-07-04 15:03:43 +01004940
Alexander Gilday3f89bf12018-10-25 14:03:49 +01004941void Simulator::PrintExclusiveAccessWarning() {
4942 if (print_exclusive_access_warning_) {
4943 fprintf(stderr,
4944 "%sWARNING:%s VIXL simulator support for "
4945 "load-/store-/clear-exclusive "
4946 "instructions is limited. Refer to the README for details.%s\n",
4947 clr_warning,
4948 clr_warning_message,
4949 clr_normal);
4950 print_exclusive_access_warning_ = false;
4951 }
4952}
4953
Alexandre Ramesd3832962016-07-04 15:03:43 +01004954void Simulator::VisitLoadStoreExclusive(const Instruction* instr) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01004955 LoadStoreExclusive op =
4956 static_cast<LoadStoreExclusive>(instr->Mask(LoadStoreExclusiveMask));
4957
Alexander Gilday4e5bad92018-04-16 17:42:00 +01004958 switch (op) {
4959 case CAS_w:
4960 case CASA_w:
4961 case CASL_w:
4962 case CASAL_w:
4963 CompareAndSwapHelper<uint32_t>(instr);
4964 break;
4965 case CAS_x:
4966 case CASA_x:
4967 case CASL_x:
4968 case CASAL_x:
4969 CompareAndSwapHelper<uint64_t>(instr);
4970 break;
4971 case CASB:
4972 case CASAB:
4973 case CASLB:
4974 case CASALB:
4975 CompareAndSwapHelper<uint8_t>(instr);
4976 break;
4977 case CASH:
4978 case CASAH:
4979 case CASLH:
4980 case CASALH:
4981 CompareAndSwapHelper<uint16_t>(instr);
4982 break;
4983 case CASP_w:
4984 case CASPA_w:
4985 case CASPL_w:
4986 case CASPAL_w:
4987 CompareAndSwapPairHelper<uint32_t>(instr);
4988 break;
4989 case CASP_x:
4990 case CASPA_x:
4991 case CASPL_x:
4992 case CASPAL_x:
4993 CompareAndSwapPairHelper<uint64_t>(instr);
4994 break;
4995 default:
Alexander Gilday3f89bf12018-10-25 14:03:49 +01004996 PrintExclusiveAccessWarning();
4997
4998 unsigned rs = instr->GetRs();
4999 unsigned rt = instr->GetRt();
5000 unsigned rt2 = instr->GetRt2();
5001 unsigned rn = instr->GetRn();
5002
5003 bool is_exclusive = !instr->GetLdStXNotExclusive();
5004 bool is_acquire_release =
5005 !is_exclusive || instr->GetLdStXAcquireRelease();
5006 bool is_load = instr->GetLdStXLoad();
5007 bool is_pair = instr->GetLdStXPair();
5008
5009 unsigned element_size = 1 << instr->GetLdStXSizeLog2();
5010 unsigned access_size = is_pair ? element_size * 2 : element_size;
5011 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
5012
5013 CheckIsValidUnalignedAtomicAccess(rn, address, access_size);
5014
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005015 if (is_load) {
5016 if (is_exclusive) {
5017 local_monitor_.MarkExclusive(address, access_size);
5018 } else {
5019 // Any non-exclusive load can clear the local monitor as a side
5020 // effect. We don't need to do this, but it is useful to stress the
5021 // simulated code.
5022 local_monitor_.Clear();
5023 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01005024
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005025 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS).
5026 // We will print a more detailed log.
Jacob Bramley423e5422019-11-13 19:15:55 +00005027 unsigned reg_size = 0;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005028 switch (op) {
5029 case LDXRB_w:
5030 case LDAXRB_w:
5031 case LDARB_w:
Chris Jones30e7bbd2024-02-15 15:05:25 +00005032 case LDLARB: {
5033 VIXL_DEFINE_OR_RETURN(value, MemRead<uint8_t>(address));
5034 WriteWRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005035 reg_size = kWRegSizeInBytes;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005036 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005037 }
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005038 case LDXRH_w:
5039 case LDAXRH_w:
5040 case LDARH_w:
Chris Jones30e7bbd2024-02-15 15:05:25 +00005041 case LDLARH: {
5042 VIXL_DEFINE_OR_RETURN(value, MemRead<uint16_t>(address));
5043 WriteWRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005044 reg_size = kWRegSizeInBytes;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005045 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005046 }
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005047 case LDXR_w:
5048 case LDAXR_w:
5049 case LDAR_w:
Chris Jones30e7bbd2024-02-15 15:05:25 +00005050 case LDLAR_w: {
5051 VIXL_DEFINE_OR_RETURN(value, MemRead<uint32_t>(address));
5052 WriteWRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005053 reg_size = kWRegSizeInBytes;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005054 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005055 }
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005056 case LDXR_x:
5057 case LDAXR_x:
5058 case LDAR_x:
Chris Jones30e7bbd2024-02-15 15:05:25 +00005059 case LDLAR_x: {
5060 VIXL_DEFINE_OR_RETURN(value, MemRead<uint64_t>(address));
5061 WriteXRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005062 reg_size = kXRegSizeInBytes;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005063 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005064 }
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005065 case LDXP_w:
Chris Jones30e7bbd2024-02-15 15:05:25 +00005066 case LDAXP_w: {
5067 VIXL_DEFINE_OR_RETURN(value, MemRead<uint32_t>(address));
5068 VIXL_DEFINE_OR_RETURN(value2,
5069 MemRead<uint32_t>(address + element_size));
5070 WriteWRegister(rt, value, NoRegLog);
5071 WriteWRegister(rt2, value2, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005072 reg_size = kWRegSizeInBytes;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005073 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005074 }
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005075 case LDXP_x:
Chris Jones30e7bbd2024-02-15 15:05:25 +00005076 case LDAXP_x: {
5077 VIXL_DEFINE_OR_RETURN(value, MemRead<uint64_t>(address));
5078 VIXL_DEFINE_OR_RETURN(value2,
5079 MemRead<uint64_t>(address + element_size));
5080 WriteXRegister(rt, value, NoRegLog);
5081 WriteXRegister(rt2, value2, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005082 reg_size = kXRegSizeInBytes;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005083 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005084 }
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005085 default:
5086 VIXL_UNREACHABLE();
5087 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01005088
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005089 if (is_acquire_release) {
5090 // Approximate load-acquire by issuing a full barrier after the load.
TheLastRar49d6efa2024-10-15 16:37:27 +01005091 VIXL_SYNC();
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005092 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01005093
Jacob Bramley423e5422019-11-13 19:15:55 +00005094 PrintRegisterFormat format = GetPrintRegisterFormatForSize(reg_size);
5095 LogExtendingRead(rt, format, element_size, address);
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005096 if (is_pair) {
Jacob Bramley423e5422019-11-13 19:15:55 +00005097 LogExtendingRead(rt2, format, element_size, address + element_size);
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005098 }
5099 } else {
5100 if (is_acquire_release) {
5101 // Approximate store-release by issuing a full barrier before the
5102 // store.
TheLastRar49d6efa2024-10-15 16:37:27 +01005103 VIXL_SYNC();
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005104 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01005105
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005106 bool do_store = true;
5107 if (is_exclusive) {
5108 do_store = local_monitor_.IsExclusive(address, access_size) &&
5109 global_monitor_.IsExclusive(address, access_size);
5110 WriteWRegister(rs, do_store ? 0 : 1);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005111
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005112 // - All exclusive stores explicitly clear the local monitor.
5113 local_monitor_.Clear();
5114 } else {
5115 // - Any other store can clear the local monitor as a side effect.
5116 local_monitor_.MaybeClear();
5117 }
5118
5119 if (do_store) {
5120 switch (op) {
5121 case STXRB_w:
5122 case STLXRB_w:
5123 case STLRB_w:
Alexander Gilday2c3cebb2018-04-13 16:15:34 +01005124 case STLLRB:
Chris Jones3134e252024-02-29 13:44:20 +00005125 if (!MemWrite<uint8_t>(address, ReadWRegister(rt))) return;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005126 break;
5127 case STXRH_w:
5128 case STLXRH_w:
5129 case STLRH_w:
Alexander Gilday2c3cebb2018-04-13 16:15:34 +01005130 case STLLRH:
Chris Jones3134e252024-02-29 13:44:20 +00005131 if (!MemWrite<uint16_t>(address, ReadWRegister(rt))) return;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005132 break;
5133 case STXR_w:
5134 case STLXR_w:
5135 case STLR_w:
Alexander Gilday2c3cebb2018-04-13 16:15:34 +01005136 case STLLR_w:
Chris Jones3134e252024-02-29 13:44:20 +00005137 if (!MemWrite<uint32_t>(address, ReadWRegister(rt))) return;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005138 break;
5139 case STXR_x:
5140 case STLXR_x:
5141 case STLR_x:
Alexander Gilday2c3cebb2018-04-13 16:15:34 +01005142 case STLLR_x:
Chris Jones3134e252024-02-29 13:44:20 +00005143 if (!MemWrite<uint64_t>(address, ReadXRegister(rt))) return;
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005144 break;
5145 case STXP_w:
5146 case STLXP_w:
Chris Jones3134e252024-02-29 13:44:20 +00005147 if (!MemWrite<uint32_t>(address, ReadWRegister(rt))) return;
5148 if (!MemWrite<uint32_t>(address + element_size,
5149 ReadWRegister(rt2))) {
5150 return;
5151 }
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005152 break;
5153 case STXP_x:
5154 case STLXP_x:
Chris Jones3134e252024-02-29 13:44:20 +00005155 if (!MemWrite<uint64_t>(address, ReadXRegister(rt))) return;
5156 if (!MemWrite<uint64_t>(address + element_size,
5157 ReadXRegister(rt2))) {
5158 return;
5159 }
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005160 break;
5161 default:
5162 VIXL_UNREACHABLE();
5163 }
5164
Jacob Bramley423e5422019-11-13 19:15:55 +00005165 PrintRegisterFormat format =
5166 GetPrintRegisterFormatForSize(element_size);
5167 LogWrite(rt, format, address);
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005168 if (is_pair) {
Jacob Bramley423e5422019-11-13 19:15:55 +00005169 LogWrite(rt2, format, address + element_size);
Alexander Gilday4e5bad92018-04-16 17:42:00 +01005170 }
5171 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01005172 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01005173 }
5174}
5175
Jacob Bramleyca789742018-09-13 14:25:46 +01005176template <typename T>
5177void Simulator::AtomicMemorySimpleHelper(const Instruction* instr) {
5178 unsigned rs = instr->GetRs();
5179 unsigned rt = instr->GetRt();
5180 unsigned rn = instr->GetRn();
5181
5182 bool is_acquire = (instr->ExtractBit(23) == 1) && (rt != kZeroRegCode);
5183 bool is_release = instr->ExtractBit(22) == 1;
5184
5185 unsigned element_size = sizeof(T);
5186 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
5187
Alexander Gilday3f89bf12018-10-25 14:03:49 +01005188 CheckIsValidUnalignedAtomicAccess(rn, address, element_size);
Jacob Bramleyca789742018-09-13 14:25:46 +01005189
5190 T value = ReadRegister<T>(rs);
5191
Chris Jones30e7bbd2024-02-15 15:05:25 +00005192 VIXL_DEFINE_OR_RETURN(data, MemRead<T>(address));
Jacob Bramleyca789742018-09-13 14:25:46 +01005193
5194 if (is_acquire) {
5195 // Approximate load-acquire by issuing a full barrier after the load.
TheLastRar49d6efa2024-10-15 16:37:27 +01005196 VIXL_SYNC();
Jacob Bramleyca789742018-09-13 14:25:46 +01005197 }
5198
5199 T result = 0;
5200 switch (instr->Mask(AtomicMemorySimpleOpMask)) {
5201 case LDADDOp:
5202 result = data + value;
5203 break;
5204 case LDCLROp:
5205 VIXL_ASSERT(!std::numeric_limits<T>::is_signed);
5206 result = data & ~value;
5207 break;
5208 case LDEOROp:
5209 VIXL_ASSERT(!std::numeric_limits<T>::is_signed);
5210 result = data ^ value;
5211 break;
5212 case LDSETOp:
5213 VIXL_ASSERT(!std::numeric_limits<T>::is_signed);
5214 result = data | value;
5215 break;
5216
5217 // Signed/Unsigned difference is done via the templated type T.
5218 case LDSMAXOp:
5219 case LDUMAXOp:
5220 result = (data > value) ? data : value;
5221 break;
5222 case LDSMINOp:
5223 case LDUMINOp:
5224 result = (data > value) ? value : data;
5225 break;
5226 }
5227
5228 if (is_release) {
5229 // Approximate store-release by issuing a full barrier before the store.
TheLastRar49d6efa2024-10-15 16:37:27 +01005230 VIXL_SYNC();
Jacob Bramleyca789742018-09-13 14:25:46 +01005231 }
5232
Jacob Bramleyca789742018-09-13 14:25:46 +01005233 WriteRegister<T>(rt, data, NoRegLog);
5234
Martyn Capewell57fbc252022-03-01 17:36:42 +00005235 unsigned register_size = element_size;
5236 if (element_size < kXRegSizeInBytes) {
5237 register_size = kWRegSizeInBytes;
5238 }
5239 PrintRegisterFormat format = GetPrintRegisterFormatForSize(register_size);
5240 LogExtendingRead(rt, format, element_size, address);
5241
Chris Jones3134e252024-02-29 13:44:20 +00005242 if (!MemWrite<T>(address, result)) return;
Martyn Capewell57fbc252022-03-01 17:36:42 +00005243 format = GetPrintRegisterFormatForSize(element_size);
Jacob Bramley423e5422019-11-13 19:15:55 +00005244 LogWrite(rs, format, address);
Jacob Bramleyca789742018-09-13 14:25:46 +01005245}
5246
5247template <typename T>
5248void Simulator::AtomicMemorySwapHelper(const Instruction* instr) {
5249 unsigned rs = instr->GetRs();
5250 unsigned rt = instr->GetRt();
5251 unsigned rn = instr->GetRn();
5252
5253 bool is_acquire = (instr->ExtractBit(23) == 1) && (rt != kZeroRegCode);
5254 bool is_release = instr->ExtractBit(22) == 1;
5255
5256 unsigned element_size = sizeof(T);
5257 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
5258
Alexander Gilday3f89bf12018-10-25 14:03:49 +01005259 CheckIsValidUnalignedAtomicAccess(rn, address, element_size);
Jacob Bramleyca789742018-09-13 14:25:46 +01005260
Chris Jones30e7bbd2024-02-15 15:05:25 +00005261 VIXL_DEFINE_OR_RETURN(data, MemRead<T>(address));
5262
Jacob Bramleyca789742018-09-13 14:25:46 +01005263 if (is_acquire) {
5264 // Approximate load-acquire by issuing a full barrier after the load.
TheLastRar49d6efa2024-10-15 16:37:27 +01005265 VIXL_SYNC();
Jacob Bramleyca789742018-09-13 14:25:46 +01005266 }
5267
5268 if (is_release) {
5269 // Approximate store-release by issuing a full barrier before the store.
TheLastRar49d6efa2024-10-15 16:37:27 +01005270 VIXL_SYNC();
Jacob Bramleyca789742018-09-13 14:25:46 +01005271 }
Chris Jones3134e252024-02-29 13:44:20 +00005272 if (!MemWrite<T>(address, ReadRegister<T>(rs))) return;
Jacob Bramleyca789742018-09-13 14:25:46 +01005273
5274 WriteRegister<T>(rt, data);
5275
Jacob Bramley423e5422019-11-13 19:15:55 +00005276 PrintRegisterFormat format = GetPrintRegisterFormatForSize(element_size);
5277 LogRead(rt, format, address);
5278 LogWrite(rs, format, address);
Jacob Bramleyca789742018-09-13 14:25:46 +01005279}
5280
5281template <typename T>
5282void Simulator::LoadAcquireRCpcHelper(const Instruction* instr) {
5283 unsigned rt = instr->GetRt();
5284 unsigned rn = instr->GetRn();
5285
5286 unsigned element_size = sizeof(T);
5287 uint64_t address = ReadRegister<uint64_t>(rn, Reg31IsStackPointer);
5288
Alexander Gilday3f89bf12018-10-25 14:03:49 +01005289 CheckIsValidUnalignedAtomicAccess(rn, address, element_size);
5290
Chris Jones30e7bbd2024-02-15 15:05:25 +00005291 VIXL_DEFINE_OR_RETURN(value, MemRead<T>(address));
5292
5293 WriteRegister<T>(rt, value);
Jacob Bramleyca789742018-09-13 14:25:46 +01005294
5295 // Approximate load-acquire by issuing a full barrier after the load.
TheLastRar49d6efa2024-10-15 16:37:27 +01005296 VIXL_SYNC();
Jacob Bramleyca789742018-09-13 14:25:46 +01005297
Jacob Bramley423e5422019-11-13 19:15:55 +00005298 LogRead(rt, GetPrintRegisterFormatForSize(element_size), address);
Jacob Bramleyca789742018-09-13 14:25:46 +01005299}
5300
5301#define ATOMIC_MEMORY_SIMPLE_UINT_LIST(V) \
5302 V(LDADD) \
5303 V(LDCLR) \
5304 V(LDEOR) \
5305 V(LDSET) \
5306 V(LDUMAX) \
5307 V(LDUMIN)
5308
5309#define ATOMIC_MEMORY_SIMPLE_INT_LIST(V) \
5310 V(LDSMAX) \
5311 V(LDSMIN)
5312
5313void Simulator::VisitAtomicMemory(const Instruction* instr) {
5314 switch (instr->Mask(AtomicMemoryMask)) {
5315// clang-format off
5316#define SIM_FUNC_B(A) \
5317 case A##B: \
5318 case A##AB: \
5319 case A##LB: \
5320 case A##ALB:
5321#define SIM_FUNC_H(A) \
5322 case A##H: \
5323 case A##AH: \
5324 case A##LH: \
5325 case A##ALH:
5326#define SIM_FUNC_w(A) \
5327 case A##_w: \
5328 case A##A_w: \
5329 case A##L_w: \
5330 case A##AL_w:
5331#define SIM_FUNC_x(A) \
5332 case A##_x: \
5333 case A##A_x: \
5334 case A##L_x: \
5335 case A##AL_x:
5336
5337 ATOMIC_MEMORY_SIMPLE_UINT_LIST(SIM_FUNC_B)
5338 AtomicMemorySimpleHelper<uint8_t>(instr);
5339 break;
5340 ATOMIC_MEMORY_SIMPLE_INT_LIST(SIM_FUNC_B)
5341 AtomicMemorySimpleHelper<int8_t>(instr);
5342 break;
5343 ATOMIC_MEMORY_SIMPLE_UINT_LIST(SIM_FUNC_H)
5344 AtomicMemorySimpleHelper<uint16_t>(instr);
5345 break;
5346 ATOMIC_MEMORY_SIMPLE_INT_LIST(SIM_FUNC_H)
5347 AtomicMemorySimpleHelper<int16_t>(instr);
5348 break;
5349 ATOMIC_MEMORY_SIMPLE_UINT_LIST(SIM_FUNC_w)
5350 AtomicMemorySimpleHelper<uint32_t>(instr);
5351 break;
5352 ATOMIC_MEMORY_SIMPLE_INT_LIST(SIM_FUNC_w)
5353 AtomicMemorySimpleHelper<int32_t>(instr);
5354 break;
5355 ATOMIC_MEMORY_SIMPLE_UINT_LIST(SIM_FUNC_x)
5356 AtomicMemorySimpleHelper<uint64_t>(instr);
5357 break;
5358 ATOMIC_MEMORY_SIMPLE_INT_LIST(SIM_FUNC_x)
5359 AtomicMemorySimpleHelper<int64_t>(instr);
5360 break;
mmc28a1a2c1d32024-02-01 16:43:49 +00005361 // clang-format on
Jacob Bramleyca789742018-09-13 14:25:46 +01005362
5363 case SWPB:
5364 case SWPAB:
5365 case SWPLB:
5366 case SWPALB:
5367 AtomicMemorySwapHelper<uint8_t>(instr);
5368 break;
5369 case SWPH:
5370 case SWPAH:
5371 case SWPLH:
5372 case SWPALH:
5373 AtomicMemorySwapHelper<uint16_t>(instr);
5374 break;
5375 case SWP_w:
5376 case SWPA_w:
5377 case SWPL_w:
5378 case SWPAL_w:
5379 AtomicMemorySwapHelper<uint32_t>(instr);
5380 break;
5381 case SWP_x:
5382 case SWPA_x:
5383 case SWPL_x:
5384 case SWPAL_x:
5385 AtomicMemorySwapHelper<uint64_t>(instr);
5386 break;
5387 case LDAPRB:
5388 LoadAcquireRCpcHelper<uint8_t>(instr);
5389 break;
5390 case LDAPRH:
5391 LoadAcquireRCpcHelper<uint16_t>(instr);
5392 break;
5393 case LDAPR_w:
5394 LoadAcquireRCpcHelper<uint32_t>(instr);
5395 break;
5396 case LDAPR_x:
5397 LoadAcquireRCpcHelper<uint64_t>(instr);
5398 break;
5399 }
5400}
5401
Alexandre Ramesd3832962016-07-04 15:03:43 +01005402
5403void Simulator::VisitLoadLiteral(const Instruction* instr) {
5404 unsigned rt = instr->GetRt();
5405 uint64_t address = instr->GetLiteralAddress<uint64_t>();
5406
5407 // Verify that the calculated address is available to the host.
5408 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
5409
5410 switch (instr->Mask(LoadLiteralMask)) {
5411 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_VREGS), then
5412 // print a more detailed log.
Chris Jones30e7bbd2024-02-15 15:05:25 +00005413 case LDR_w_lit: {
5414 VIXL_DEFINE_OR_RETURN(value, MemRead<uint32_t>(address));
5415 WriteWRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005416 LogRead(rt, kPrintWReg, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005417 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005418 }
5419 case LDR_x_lit: {
5420 VIXL_DEFINE_OR_RETURN(value, MemRead<uint64_t>(address));
5421 WriteXRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005422 LogRead(rt, kPrintXReg, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005423 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005424 }
5425 case LDR_s_lit: {
5426 VIXL_DEFINE_OR_RETURN(value, MemRead<float>(address));
5427 WriteSRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005428 LogVRead(rt, kPrintSRegFP, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005429 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005430 }
5431 case LDR_d_lit: {
5432 VIXL_DEFINE_OR_RETURN(value, MemRead<double>(address));
5433 WriteDRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005434 LogVRead(rt, kPrintDRegFP, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005435 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005436 }
5437 case LDR_q_lit: {
5438 VIXL_DEFINE_OR_RETURN(value, MemRead<qreg_t>(address));
5439 WriteQRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005440 LogVRead(rt, kPrintReg1Q, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005441 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005442 }
5443 case LDRSW_x_lit: {
5444 VIXL_DEFINE_OR_RETURN(value, MemRead<int32_t>(address));
5445 WriteXRegister(rt, value, NoRegLog);
Jacob Bramley423e5422019-11-13 19:15:55 +00005446 LogExtendingRead(rt, kPrintXReg, kWRegSizeInBytes, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005447 break;
Chris Jones30e7bbd2024-02-15 15:05:25 +00005448 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01005449
5450 // Ignore prfm hint instructions.
5451 case PRFM_lit:
5452 break;
5453
5454 default:
5455 VIXL_UNREACHABLE();
5456 }
5457
5458 local_monitor_.MaybeClear();
5459}
5460
5461
5462uintptr_t Simulator::AddressModeHelper(unsigned addr_reg,
5463 int64_t offset,
5464 AddrMode addrmode) {
5465 uint64_t address = ReadXRegister(addr_reg, Reg31IsStackPointer);
5466
5467 if ((addr_reg == 31) && ((address % 16) != 0)) {
5468 // When the base register is SP the stack pointer is required to be
5469 // quadword aligned prior to the address calculation and write-backs.
5470 // Misalignment will cause a stack alignment fault.
5471 VIXL_ALIGNMENT_EXCEPTION();
5472 }
5473
5474 if ((addrmode == PreIndex) || (addrmode == PostIndex)) {
5475 VIXL_ASSERT(offset != 0);
5476 // Only preindex should log the register update here. For Postindex, the
5477 // update will be printed automatically by LogWrittenRegisters _after_ the
5478 // memory access itself is logged.
5479 RegLogMode log_mode = (addrmode == PreIndex) ? LogRegWrites : NoRegLog;
5480 WriteXRegister(addr_reg, address + offset, log_mode, Reg31IsStackPointer);
5481 }
5482
5483 if ((addrmode == Offset) || (addrmode == PreIndex)) {
5484 address += offset;
5485 }
5486
5487 // Verify that the calculated address is available to the host.
5488 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
5489
5490 return static_cast<uintptr_t>(address);
5491}
5492
5493
5494void Simulator::VisitMoveWideImmediate(const Instruction* instr) {
5495 MoveWideImmediateOp mov_op =
5496 static_cast<MoveWideImmediateOp>(instr->Mask(MoveWideImmediateMask));
5497 int64_t new_xn_val = 0;
5498
5499 bool is_64_bits = instr->GetSixtyFourBits() == 1;
5500 // Shift is limited for W operations.
5501 VIXL_ASSERT(is_64_bits || (instr->GetShiftMoveWide() < 2));
5502
5503 // Get the shifted immediate.
5504 int64_t shift = instr->GetShiftMoveWide() * 16;
5505 int64_t shifted_imm16 = static_cast<int64_t>(instr->GetImmMoveWide())
5506 << shift;
5507
5508 // Compute the new value.
5509 switch (mov_op) {
5510 case MOVN_w:
5511 case MOVN_x: {
5512 new_xn_val = ~shifted_imm16;
5513 if (!is_64_bits) new_xn_val &= kWRegMask;
5514 break;
5515 }
5516 case MOVK_w:
5517 case MOVK_x: {
5518 unsigned reg_code = instr->GetRd();
5519 int64_t prev_xn_val =
5520 is_64_bits ? ReadXRegister(reg_code) : ReadWRegister(reg_code);
5521 new_xn_val = (prev_xn_val & ~(INT64_C(0xffff) << shift)) | shifted_imm16;
5522 break;
5523 }
5524 case MOVZ_w:
5525 case MOVZ_x: {
5526 new_xn_val = shifted_imm16;
5527 break;
5528 }
5529 default:
5530 VIXL_UNREACHABLE();
5531 }
5532
5533 // Update the destination register.
5534 WriteXRegister(instr->GetRd(), new_xn_val);
5535}
5536
5537
5538void Simulator::VisitConditionalSelect(const Instruction* instr) {
5539 uint64_t new_val = ReadXRegister(instr->GetRn());
5540
5541 if (ConditionFailed(static_cast<Condition>(instr->GetCondition()))) {
5542 new_val = ReadXRegister(instr->GetRm());
5543 switch (instr->Mask(ConditionalSelectMask)) {
5544 case CSEL_w:
5545 case CSEL_x:
5546 break;
5547 case CSINC_w:
5548 case CSINC_x:
5549 new_val++;
5550 break;
5551 case CSINV_w:
5552 case CSINV_x:
5553 new_val = ~new_val;
5554 break;
5555 case CSNEG_w:
5556 case CSNEG_x:
TheLastRar49d6efa2024-10-15 16:37:27 +01005557 new_val = UnsignedNegate(new_val);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005558 break;
5559 default:
5560 VIXL_UNIMPLEMENTED();
5561 }
5562 }
5563 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
5564 WriteRegister(reg_size, instr->GetRd(), new_val);
5565}
5566
5567
mmc28ab5c57c92023-03-16 16:26:31 +00005568#define PAUTH_MODES_REGISTER_CONTEXT(V) \
5569 V(i, a, kPACKeyIA, kInstructionPointer) \
5570 V(i, b, kPACKeyIB, kInstructionPointer) \
5571 V(d, a, kPACKeyDA, kDataPointer) \
5572 V(d, b, kPACKeyDB, kDataPointer)
Jacob Bramleyca789742018-09-13 14:25:46 +01005573
Alexandre Ramesd3832962016-07-04 15:03:43 +01005574void Simulator::VisitDataProcessing1Source(const Instruction* instr) {
5575 unsigned dst = instr->GetRd();
5576 unsigned src = instr->GetRn();
mmc28ab5c57c92023-03-16 16:26:31 +00005577 Reg31Mode r31_pac = Reg31IsStackPointer;
Alexandre Ramesd3832962016-07-04 15:03:43 +01005578
mmc28ab5c57c92023-03-16 16:26:31 +00005579 switch (form_hash_) {
5580#define DEFINE_PAUTH_FUNCS(SUF0, SUF1, KEY, D) \
5581 case "pac" #SUF0 "z" #SUF1 "_64z_dp_1src"_h: \
5582 VIXL_ASSERT(src == kZeroRegCode); \
5583 r31_pac = Reg31IsZeroRegister; \
5584 VIXL_FALLTHROUGH(); \
5585 case "pac" #SUF0 #SUF1 "_64p_dp_1src"_h: { \
5586 uint64_t mod = ReadXRegister(src, r31_pac); \
5587 uint64_t ptr = ReadXRegister(dst); \
5588 WriteXRegister(dst, AddPAC(ptr, mod, KEY, D)); \
5589 break; \
5590 } \
5591 case "aut" #SUF0 "z" #SUF1 "_64z_dp_1src"_h: \
5592 VIXL_ASSERT(src == kZeroRegCode); \
5593 r31_pac = Reg31IsZeroRegister; \
5594 VIXL_FALLTHROUGH(); \
5595 case "aut" #SUF0 #SUF1 "_64p_dp_1src"_h: { \
5596 uint64_t mod = ReadXRegister(src, r31_pac); \
5597 uint64_t ptr = ReadXRegister(dst); \
5598 WriteXRegister(dst, AuthPAC(ptr, mod, KEY, D)); \
5599 break; \
Jacob Bramleyca789742018-09-13 14:25:46 +01005600 }
Pierre Langlois21d46842020-12-31 12:14:37 +00005601 PAUTH_MODES_REGISTER_CONTEXT(DEFINE_PAUTH_FUNCS)
5602#undef DEFINE_PAUTH_FUNCS
5603
mmc28ab5c57c92023-03-16 16:26:31 +00005604 case "xpaci_64z_dp_1src"_h:
Jacob Bramleyca789742018-09-13 14:25:46 +01005605 WriteXRegister(dst, StripPAC(ReadXRegister(dst), kInstructionPointer));
5606 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005607 case "xpacd_64z_dp_1src"_h:
Jacob Bramleyca789742018-09-13 14:25:46 +01005608 WriteXRegister(dst, StripPAC(ReadXRegister(dst), kDataPointer));
5609 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005610 case "rbit_32_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005611 WriteWRegister(dst, ReverseBits(ReadWRegister(src)));
5612 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005613 case "rbit_64_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005614 WriteXRegister(dst, ReverseBits(ReadXRegister(src)));
5615 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005616 case "rev16_32_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005617 WriteWRegister(dst, ReverseBytes(ReadWRegister(src), 1));
5618 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005619 case "rev16_64_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005620 WriteXRegister(dst, ReverseBytes(ReadXRegister(src), 1));
5621 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005622 case "rev_32_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005623 WriteWRegister(dst, ReverseBytes(ReadWRegister(src), 2));
5624 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005625 case "rev32_64_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005626 WriteXRegister(dst, ReverseBytes(ReadXRegister(src), 2));
5627 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005628 case "rev_64_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005629 WriteXRegister(dst, ReverseBytes(ReadXRegister(src), 3));
5630 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005631 case "clz_32_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005632 WriteWRegister(dst, CountLeadingZeros(ReadWRegister(src)));
5633 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005634 case "clz_64_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005635 WriteXRegister(dst, CountLeadingZeros(ReadXRegister(src)));
5636 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005637 case "cls_32_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005638 WriteWRegister(dst, CountLeadingSignBits(ReadWRegister(src)));
5639 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005640 case "cls_64_dp_1src"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01005641 WriteXRegister(dst, CountLeadingSignBits(ReadXRegister(src)));
5642 break;
mmc28ab5c57c92023-03-16 16:26:31 +00005643 case "abs_32_dp_1src"_h:
5644 WriteWRegister(dst, Abs(ReadWRegister(src)));
5645 break;
5646 case "abs_64_dp_1src"_h:
5647 WriteXRegister(dst, Abs(ReadXRegister(src)));
5648 break;
5649 case "cnt_32_dp_1src"_h:
5650 WriteWRegister(dst, CountSetBits(ReadWRegister(src)));
5651 break;
5652 case "cnt_64_dp_1src"_h:
5653 WriteXRegister(dst, CountSetBits(ReadXRegister(src)));
5654 break;
5655 case "ctz_32_dp_1src"_h:
5656 WriteWRegister(dst, CountTrailingZeros(ReadWRegister(src)));
5657 break;
5658 case "ctz_64_dp_1src"_h:
5659 WriteXRegister(dst, CountTrailingZeros(ReadXRegister(src)));
5660 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01005661 }
5662}
5663
Alexandre Ramesd3832962016-07-04 15:03:43 +01005664uint32_t Simulator::Poly32Mod2(unsigned n, uint64_t data, uint32_t poly) {
5665 VIXL_ASSERT((n > 32) && (n <= 64));
5666 for (unsigned i = (n - 1); i >= 32; i--) {
5667 if (((data >> i) & 1) != 0) {
5668 uint64_t polysh32 = (uint64_t)poly << (i - 32);
5669 uint64_t mask = (UINT64_C(1) << i) - 1;
5670 data = ((data & mask) ^ polysh32);
5671 }
5672 }
5673 return data & 0xffffffff;
5674}
5675
5676
5677template <typename T>
5678uint32_t Simulator::Crc32Checksum(uint32_t acc, T val, uint32_t poly) {
5679 unsigned size = sizeof(val) * 8; // Number of bits in type T.
5680 VIXL_ASSERT((size == 8) || (size == 16) || (size == 32));
5681 uint64_t tempacc = static_cast<uint64_t>(ReverseBits(acc)) << size;
5682 uint64_t tempval = static_cast<uint64_t>(ReverseBits(val)) << 32;
5683 return ReverseBits(Poly32Mod2(32 + size, tempacc ^ tempval, poly));
5684}
5685
5686
5687uint32_t Simulator::Crc32Checksum(uint32_t acc, uint64_t val, uint32_t poly) {
5688 // Poly32Mod2 cannot handle inputs with more than 32 bits, so compute
5689 // the CRC of each 32-bit word sequentially.
5690 acc = Crc32Checksum(acc, (uint32_t)(val & 0xffffffff), poly);
5691 return Crc32Checksum(acc, (uint32_t)(val >> 32), poly);
5692}
5693
5694
5695void Simulator::VisitDataProcessing2Source(const Instruction* instr) {
5696 Shift shift_op = NO_SHIFT;
5697 int64_t result = 0;
5698 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
5699
5700 switch (instr->Mask(DataProcessing2SourceMask)) {
5701 case SDIV_w: {
5702 int32_t rn = ReadWRegister(instr->GetRn());
5703 int32_t rm = ReadWRegister(instr->GetRm());
5704 if ((rn == kWMinInt) && (rm == -1)) {
5705 result = kWMinInt;
5706 } else if (rm == 0) {
5707 // Division by zero can be trapped, but not on A-class processors.
5708 result = 0;
5709 } else {
5710 result = rn / rm;
5711 }
5712 break;
5713 }
5714 case SDIV_x: {
5715 int64_t rn = ReadXRegister(instr->GetRn());
5716 int64_t rm = ReadXRegister(instr->GetRm());
5717 if ((rn == kXMinInt) && (rm == -1)) {
5718 result = kXMinInt;
5719 } else if (rm == 0) {
5720 // Division by zero can be trapped, but not on A-class processors.
5721 result = 0;
5722 } else {
5723 result = rn / rm;
5724 }
5725 break;
5726 }
5727 case UDIV_w: {
5728 uint32_t rn = static_cast<uint32_t>(ReadWRegister(instr->GetRn()));
5729 uint32_t rm = static_cast<uint32_t>(ReadWRegister(instr->GetRm()));
5730 if (rm == 0) {
5731 // Division by zero can be trapped, but not on A-class processors.
5732 result = 0;
5733 } else {
5734 result = rn / rm;
5735 }
5736 break;
5737 }
5738 case UDIV_x: {
5739 uint64_t rn = static_cast<uint64_t>(ReadXRegister(instr->GetRn()));
5740 uint64_t rm = static_cast<uint64_t>(ReadXRegister(instr->GetRm()));
5741 if (rm == 0) {
5742 // Division by zero can be trapped, but not on A-class processors.
5743 result = 0;
5744 } else {
5745 result = rn / rm;
5746 }
5747 break;
5748 }
5749 case LSLV_w:
5750 case LSLV_x:
5751 shift_op = LSL;
5752 break;
5753 case LSRV_w:
5754 case LSRV_x:
5755 shift_op = LSR;
5756 break;
5757 case ASRV_w:
5758 case ASRV_x:
5759 shift_op = ASR;
5760 break;
5761 case RORV_w:
5762 case RORV_x:
5763 shift_op = ROR;
5764 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01005765 case PACGA: {
5766 uint64_t dst = static_cast<uint64_t>(ReadXRegister(instr->GetRn()));
5767 uint64_t src = static_cast<uint64_t>(
5768 ReadXRegister(instr->GetRm(), Reg31IsStackPointer));
5769 uint64_t code = ComputePAC(dst, src, kPACKeyGA);
5770 result = code & 0xffffffff00000000;
5771 break;
5772 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01005773 case CRC32B: {
5774 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
5775 uint8_t val = ReadRegister<uint8_t>(instr->GetRm());
5776 result = Crc32Checksum(acc, val, CRC32_POLY);
5777 break;
5778 }
5779 case CRC32H: {
5780 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
5781 uint16_t val = ReadRegister<uint16_t>(instr->GetRm());
5782 result = Crc32Checksum(acc, val, CRC32_POLY);
5783 break;
5784 }
5785 case CRC32W: {
5786 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
5787 uint32_t val = ReadRegister<uint32_t>(instr->GetRm());
5788 result = Crc32Checksum(acc, val, CRC32_POLY);
5789 break;
5790 }
5791 case CRC32X: {
5792 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
5793 uint64_t val = ReadRegister<uint64_t>(instr->GetRm());
5794 result = Crc32Checksum(acc, val, CRC32_POLY);
5795 reg_size = kWRegSize;
5796 break;
5797 }
5798 case CRC32CB: {
5799 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
5800 uint8_t val = ReadRegister<uint8_t>(instr->GetRm());
5801 result = Crc32Checksum(acc, val, CRC32C_POLY);
5802 break;
5803 }
5804 case CRC32CH: {
5805 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
5806 uint16_t val = ReadRegister<uint16_t>(instr->GetRm());
5807 result = Crc32Checksum(acc, val, CRC32C_POLY);
5808 break;
5809 }
5810 case CRC32CW: {
5811 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
5812 uint32_t val = ReadRegister<uint32_t>(instr->GetRm());
5813 result = Crc32Checksum(acc, val, CRC32C_POLY);
5814 break;
5815 }
5816 case CRC32CX: {
5817 uint32_t acc = ReadRegister<uint32_t>(instr->GetRn());
5818 uint64_t val = ReadRegister<uint64_t>(instr->GetRm());
5819 result = Crc32Checksum(acc, val, CRC32C_POLY);
5820 reg_size = kWRegSize;
5821 break;
5822 }
5823 default:
5824 VIXL_UNIMPLEMENTED();
5825 }
5826
5827 if (shift_op != NO_SHIFT) {
5828 // Shift distance encoded in the least-significant five/six bits of the
5829 // register.
5830 int mask = (instr->GetSixtyFourBits() == 1) ? 0x3f : 0x1f;
5831 unsigned shift = ReadWRegister(instr->GetRm()) & mask;
5832 result = ShiftOperand(reg_size,
5833 ReadRegister(reg_size, instr->GetRn()),
5834 shift_op,
5835 shift);
5836 }
5837 WriteRegister(reg_size, instr->GetRd(), result);
5838}
5839
mmc28ab5c57c92023-03-16 16:26:31 +00005840void Simulator::SimulateSignedMinMax(const Instruction* instr) {
5841 int32_t wn = ReadWRegister(instr->GetRn());
5842 int32_t wm = ReadWRegister(instr->GetRm());
5843 int64_t xn = ReadXRegister(instr->GetRn());
5844 int64_t xm = ReadXRegister(instr->GetRm());
5845 int32_t imm = instr->ExtractSignedBits(17, 10);
5846 int dst = instr->GetRd();
5847
5848 switch (form_hash_) {
5849 case "smax_64_minmax_imm"_h:
5850 case "smin_64_minmax_imm"_h:
5851 xm = imm;
5852 break;
5853 case "smax_32_minmax_imm"_h:
5854 case "smin_32_minmax_imm"_h:
5855 wm = imm;
5856 break;
5857 }
5858
5859 switch (form_hash_) {
5860 case "smax_32_minmax_imm"_h:
5861 case "smax_32_dp_2src"_h:
5862 WriteWRegister(dst, std::max(wn, wm));
5863 break;
5864 case "smax_64_minmax_imm"_h:
5865 case "smax_64_dp_2src"_h:
5866 WriteXRegister(dst, std::max(xn, xm));
5867 break;
5868 case "smin_32_minmax_imm"_h:
5869 case "smin_32_dp_2src"_h:
5870 WriteWRegister(dst, std::min(wn, wm));
5871 break;
5872 case "smin_64_minmax_imm"_h:
5873 case "smin_64_dp_2src"_h:
5874 WriteXRegister(dst, std::min(xn, xm));
5875 break;
5876 }
5877}
5878
5879void Simulator::SimulateUnsignedMinMax(const Instruction* instr) {
5880 uint64_t xn = ReadXRegister(instr->GetRn());
5881 uint64_t xm = ReadXRegister(instr->GetRm());
5882 uint32_t imm = instr->ExtractBits(17, 10);
5883 int dst = instr->GetRd();
5884
5885 switch (form_hash_) {
5886 case "umax_64u_minmax_imm"_h:
5887 case "umax_32u_minmax_imm"_h:
5888 case "umin_64u_minmax_imm"_h:
5889 case "umin_32u_minmax_imm"_h:
5890 xm = imm;
5891 break;
5892 }
5893
5894 switch (form_hash_) {
5895 case "umax_32u_minmax_imm"_h:
5896 case "umax_32_dp_2src"_h:
5897 xn &= 0xffff'ffff;
5898 xm &= 0xffff'ffff;
5899 VIXL_FALLTHROUGH();
5900 case "umax_64u_minmax_imm"_h:
5901 case "umax_64_dp_2src"_h:
5902 WriteXRegister(dst, std::max(xn, xm));
5903 break;
5904 case "umin_32u_minmax_imm"_h:
5905 case "umin_32_dp_2src"_h:
5906 xn &= 0xffff'ffff;
5907 xm &= 0xffff'ffff;
5908 VIXL_FALLTHROUGH();
5909 case "umin_64u_minmax_imm"_h:
5910 case "umin_64_dp_2src"_h:
5911 WriteXRegister(dst, std::min(xn, xm));
5912 break;
5913 }
5914}
Alexandre Ramesd3832962016-07-04 15:03:43 +01005915
Alexandre Ramesd3832962016-07-04 15:03:43 +01005916void Simulator::VisitDataProcessing3Source(const Instruction* instr) {
5917 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
5918
5919 uint64_t result = 0;
5920 // Extract and sign- or zero-extend 32-bit arguments for widening operations.
5921 uint64_t rn_u32 = ReadRegister<uint32_t>(instr->GetRn());
5922 uint64_t rm_u32 = ReadRegister<uint32_t>(instr->GetRm());
5923 int64_t rn_s32 = ReadRegister<int32_t>(instr->GetRn());
5924 int64_t rm_s32 = ReadRegister<int32_t>(instr->GetRm());
Martyn Capewell5b24fb32016-11-02 18:52:55 +00005925 uint64_t rn_u64 = ReadXRegister(instr->GetRn());
5926 uint64_t rm_u64 = ReadXRegister(instr->GetRm());
Alexandre Ramesd3832962016-07-04 15:03:43 +01005927 switch (instr->Mask(DataProcessing3SourceMask)) {
5928 case MADD_w:
5929 case MADD_x:
Martyn Capewell5b24fb32016-11-02 18:52:55 +00005930 result = ReadXRegister(instr->GetRa()) + (rn_u64 * rm_u64);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005931 break;
5932 case MSUB_w:
5933 case MSUB_x:
Martyn Capewell5b24fb32016-11-02 18:52:55 +00005934 result = ReadXRegister(instr->GetRa()) - (rn_u64 * rm_u64);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005935 break;
5936 case SMADDL_x:
Martyn Capewell5b24fb32016-11-02 18:52:55 +00005937 result = ReadXRegister(instr->GetRa()) +
5938 static_cast<uint64_t>(rn_s32 * rm_s32);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005939 break;
5940 case SMSUBL_x:
Martyn Capewell5b24fb32016-11-02 18:52:55 +00005941 result = ReadXRegister(instr->GetRa()) -
5942 static_cast<uint64_t>(rn_s32 * rm_s32);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005943 break;
5944 case UMADDL_x:
5945 result = ReadXRegister(instr->GetRa()) + (rn_u32 * rm_u32);
5946 break;
5947 case UMSUBL_x:
5948 result = ReadXRegister(instr->GetRa()) - (rn_u32 * rm_u32);
5949 break;
5950 case UMULH_x:
TatWai Chong13634762019-07-16 16:20:45 -07005951 result =
5952 internal::MultiplyHigh<64>(ReadRegister<uint64_t>(instr->GetRn()),
5953 ReadRegister<uint64_t>(instr->GetRm()));
Alexandre Ramesd3832962016-07-04 15:03:43 +01005954 break;
5955 case SMULH_x:
TatWai Chong13634762019-07-16 16:20:45 -07005956 result = internal::MultiplyHigh<64>(ReadXRegister(instr->GetRn()),
5957 ReadXRegister(instr->GetRm()));
Alexandre Ramesd3832962016-07-04 15:03:43 +01005958 break;
5959 default:
5960 VIXL_UNIMPLEMENTED();
5961 }
5962 WriteRegister(reg_size, instr->GetRd(), result);
5963}
5964
5965
5966void Simulator::VisitBitfield(const Instruction* instr) {
5967 unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
5968 int64_t reg_mask = instr->GetSixtyFourBits() ? kXRegMask : kWRegMask;
Martyn Capewellfb8e3df2016-11-03 15:50:19 +00005969 int R = instr->GetImmR();
5970 int S = instr->GetImmS();
Martyn Capewelle441df52021-07-08 11:22:40 +01005971
5972 if (instr->GetSixtyFourBits() != instr->GetBitN()) {
5973 VisitUnallocated(instr);
5974 }
5975
5976 if ((instr->GetSixtyFourBits() == 0) && ((S > 31) || (R > 31))) {
5977 VisitUnallocated(instr);
5978 }
5979
Martyn Capewellfb8e3df2016-11-03 15:50:19 +00005980 int diff = S - R;
Martyn Capewell5b24fb32016-11-02 18:52:55 +00005981 uint64_t mask;
Alexandre Ramesd3832962016-07-04 15:03:43 +01005982 if (diff >= 0) {
Martyn Capewell5b24fb32016-11-02 18:52:55 +00005983 mask = ~UINT64_C(0) >> (64 - (diff + 1));
Martyn Capewellfb8e3df2016-11-03 15:50:19 +00005984 mask = (static_cast<unsigned>(diff) < (reg_size - 1)) ? mask : reg_mask;
Alexandre Ramesd3832962016-07-04 15:03:43 +01005985 } else {
Martyn Capewell5b24fb32016-11-02 18:52:55 +00005986 mask = ~UINT64_C(0) >> (64 - (S + 1));
Martyn Capewellfb8e3df2016-11-03 15:50:19 +00005987 mask = RotateRight(mask, R, reg_size);
Alexandre Ramesd3832962016-07-04 15:03:43 +01005988 diff += reg_size;
5989 }
5990
5991 // inzero indicates if the extracted bitfield is inserted into the
5992 // destination register value or in zero.
5993 // If extend is true, extend the sign of the extracted bitfield.
5994 bool inzero = false;
5995 bool extend = false;
5996 switch (instr->Mask(BitfieldMask)) {
5997 case BFM_x:
5998 case BFM_w:
5999 break;
6000 case SBFM_x:
6001 case SBFM_w:
6002 inzero = true;
6003 extend = true;
6004 break;
6005 case UBFM_x:
6006 case UBFM_w:
6007 inzero = true;
6008 break;
6009 default:
6010 VIXL_UNIMPLEMENTED();
6011 }
6012
Martyn Capewell5b24fb32016-11-02 18:52:55 +00006013 uint64_t dst = inzero ? 0 : ReadRegister(reg_size, instr->GetRd());
6014 uint64_t src = ReadRegister(reg_size, instr->GetRn());
Alexandre Ramesd3832962016-07-04 15:03:43 +01006015 // Rotate source bitfield into place.
Martyn Capewellfb8e3df2016-11-03 15:50:19 +00006016 uint64_t result = RotateRight(src, R, reg_size);
Alexandre Ramesd3832962016-07-04 15:03:43 +01006017 // Determine the sign extension.
Martyn Capewell5b24fb32016-11-02 18:52:55 +00006018 uint64_t topbits = (diff == 63) ? 0 : (~UINT64_C(0) << (diff + 1));
6019 uint64_t signbits = extend && ((src >> S) & 1) ? topbits : 0;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006020
6021 // Merge sign extension, dest/zero and bitfield.
6022 result = signbits | (result & mask) | (dst & ~mask);
6023
6024 WriteRegister(reg_size, instr->GetRd(), result);
6025}
6026
6027
6028void Simulator::VisitExtract(const Instruction* instr) {
6029 unsigned lsb = instr->GetImmS();
6030 unsigned reg_size = (instr->GetSixtyFourBits() == 1) ? kXRegSize : kWRegSize;
6031 uint64_t low_res =
6032 static_cast<uint64_t>(ReadRegister(reg_size, instr->GetRm())) >> lsb;
Jacob Bramley2fe55ec2020-03-20 17:03:48 +00006033 uint64_t high_res = (lsb == 0)
6034 ? 0
6035 : ReadRegister<uint64_t>(reg_size, instr->GetRn())
6036 << (reg_size - lsb);
Alexandre Ramesd3832962016-07-04 15:03:43 +01006037 WriteRegister(reg_size, instr->GetRd(), low_res | high_res);
6038}
6039
6040
6041void Simulator::VisitFPImmediate(const Instruction* instr) {
6042 AssertSupportedFPCR();
Alexandre Ramesd3832962016-07-04 15:03:43 +01006043 unsigned dest = instr->GetRd();
6044 switch (instr->Mask(FPImmediateMask)) {
Carey Williamsd8bb3572018-04-10 11:58:07 +01006045 case FMOV_h_imm:
Jacob Bramleyca789742018-09-13 14:25:46 +01006046 WriteHRegister(dest, Float16ToRawbits(instr->GetImmFP16()));
Carey Williamsd8bb3572018-04-10 11:58:07 +01006047 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006048 case FMOV_s_imm:
6049 WriteSRegister(dest, instr->GetImmFP32());
6050 break;
6051 case FMOV_d_imm:
6052 WriteDRegister(dest, instr->GetImmFP64());
6053 break;
6054 default:
6055 VIXL_UNREACHABLE();
6056 }
6057}
6058
6059
6060void Simulator::VisitFPIntegerConvert(const Instruction* instr) {
6061 AssertSupportedFPCR();
6062
6063 unsigned dst = instr->GetRd();
6064 unsigned src = instr->GetRn();
6065
6066 FPRounding round = ReadRMode();
6067
6068 switch (instr->Mask(FPIntegerConvertMask)) {
Jacob Bramleyca789742018-09-13 14:25:46 +01006069 case FCVTAS_wh:
6070 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPTieAway));
6071 break;
6072 case FCVTAS_xh:
6073 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPTieAway));
6074 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006075 case FCVTAS_ws:
6076 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPTieAway));
6077 break;
6078 case FCVTAS_xs:
6079 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPTieAway));
6080 break;
6081 case FCVTAS_wd:
6082 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPTieAway));
6083 break;
6084 case FCVTAS_xd:
6085 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPTieAway));
6086 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006087 case FCVTAU_wh:
6088 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPTieAway));
6089 break;
6090 case FCVTAU_xh:
6091 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPTieAway));
6092 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006093 case FCVTAU_ws:
6094 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPTieAway));
6095 break;
6096 case FCVTAU_xs:
6097 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPTieAway));
6098 break;
6099 case FCVTAU_wd:
6100 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPTieAway));
6101 break;
6102 case FCVTAU_xd:
6103 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPTieAway));
6104 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006105 case FCVTMS_wh:
6106 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPNegativeInfinity));
6107 break;
6108 case FCVTMS_xh:
6109 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPNegativeInfinity));
6110 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006111 case FCVTMS_ws:
6112 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPNegativeInfinity));
6113 break;
6114 case FCVTMS_xs:
6115 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPNegativeInfinity));
6116 break;
6117 case FCVTMS_wd:
6118 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPNegativeInfinity));
6119 break;
6120 case FCVTMS_xd:
6121 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPNegativeInfinity));
6122 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006123 case FCVTMU_wh:
6124 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPNegativeInfinity));
6125 break;
6126 case FCVTMU_xh:
6127 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPNegativeInfinity));
6128 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006129 case FCVTMU_ws:
6130 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPNegativeInfinity));
6131 break;
6132 case FCVTMU_xs:
6133 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPNegativeInfinity));
6134 break;
6135 case FCVTMU_wd:
6136 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPNegativeInfinity));
6137 break;
6138 case FCVTMU_xd:
6139 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPNegativeInfinity));
6140 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006141 case FCVTPS_wh:
6142 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPPositiveInfinity));
6143 break;
6144 case FCVTPS_xh:
6145 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPPositiveInfinity));
6146 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006147 case FCVTPS_ws:
6148 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPPositiveInfinity));
6149 break;
6150 case FCVTPS_xs:
6151 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPPositiveInfinity));
6152 break;
6153 case FCVTPS_wd:
6154 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPPositiveInfinity));
6155 break;
6156 case FCVTPS_xd:
6157 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPPositiveInfinity));
6158 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006159 case FCVTPU_wh:
6160 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPPositiveInfinity));
6161 break;
6162 case FCVTPU_xh:
6163 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPPositiveInfinity));
6164 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006165 case FCVTPU_ws:
6166 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPPositiveInfinity));
6167 break;
6168 case FCVTPU_xs:
6169 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPPositiveInfinity));
6170 break;
6171 case FCVTPU_wd:
6172 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPPositiveInfinity));
6173 break;
6174 case FCVTPU_xd:
6175 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPPositiveInfinity));
6176 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006177 case FCVTNS_wh:
6178 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPTieEven));
6179 break;
6180 case FCVTNS_xh:
6181 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPTieEven));
6182 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006183 case FCVTNS_ws:
6184 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPTieEven));
6185 break;
6186 case FCVTNS_xs:
6187 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPTieEven));
6188 break;
6189 case FCVTNS_wd:
6190 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPTieEven));
6191 break;
6192 case FCVTNS_xd:
6193 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPTieEven));
6194 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006195 case FCVTNU_wh:
6196 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPTieEven));
6197 break;
6198 case FCVTNU_xh:
6199 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPTieEven));
6200 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006201 case FCVTNU_ws:
6202 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPTieEven));
6203 break;
6204 case FCVTNU_xs:
6205 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPTieEven));
6206 break;
6207 case FCVTNU_wd:
6208 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPTieEven));
6209 break;
6210 case FCVTNU_xd:
6211 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPTieEven));
6212 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006213 case FCVTZS_wh:
6214 WriteWRegister(dst, FPToInt32(ReadHRegister(src), FPZero));
6215 break;
6216 case FCVTZS_xh:
6217 WriteXRegister(dst, FPToInt64(ReadHRegister(src), FPZero));
6218 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006219 case FCVTZS_ws:
6220 WriteWRegister(dst, FPToInt32(ReadSRegister(src), FPZero));
6221 break;
6222 case FCVTZS_xs:
6223 WriteXRegister(dst, FPToInt64(ReadSRegister(src), FPZero));
6224 break;
6225 case FCVTZS_wd:
6226 WriteWRegister(dst, FPToInt32(ReadDRegister(src), FPZero));
6227 break;
6228 case FCVTZS_xd:
6229 WriteXRegister(dst, FPToInt64(ReadDRegister(src), FPZero));
6230 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006231 case FCVTZU_wh:
6232 WriteWRegister(dst, FPToUInt32(ReadHRegister(src), FPZero));
6233 break;
6234 case FCVTZU_xh:
6235 WriteXRegister(dst, FPToUInt64(ReadHRegister(src), FPZero));
6236 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006237 case FCVTZU_ws:
6238 WriteWRegister(dst, FPToUInt32(ReadSRegister(src), FPZero));
6239 break;
6240 case FCVTZU_xs:
6241 WriteXRegister(dst, FPToUInt64(ReadSRegister(src), FPZero));
6242 break;
6243 case FCVTZU_wd:
6244 WriteWRegister(dst, FPToUInt32(ReadDRegister(src), FPZero));
6245 break;
6246 case FCVTZU_xd:
6247 WriteXRegister(dst, FPToUInt64(ReadDRegister(src), FPZero));
6248 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006249 case FJCVTZS:
6250 WriteWRegister(dst, FPToFixedJS(ReadDRegister(src)));
6251 break;
Carey Williamsd8bb3572018-04-10 11:58:07 +01006252 case FMOV_hw:
6253 WriteHRegister(dst, ReadWRegister(src) & kHRegMask);
6254 break;
6255 case FMOV_wh:
6256 WriteWRegister(dst, ReadHRegisterBits(src));
6257 break;
6258 case FMOV_xh:
6259 WriteXRegister(dst, ReadHRegisterBits(src));
6260 break;
6261 case FMOV_hx:
6262 WriteHRegister(dst, ReadXRegister(src) & kHRegMask);
6263 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006264 case FMOV_ws:
6265 WriteWRegister(dst, ReadSRegisterBits(src));
6266 break;
6267 case FMOV_xd:
6268 WriteXRegister(dst, ReadDRegisterBits(src));
6269 break;
6270 case FMOV_sw:
6271 WriteSRegisterBits(dst, ReadWRegister(src));
6272 break;
6273 case FMOV_dx:
6274 WriteDRegisterBits(dst, ReadXRegister(src));
6275 break;
6276 case FMOV_d1_x:
mmc28a5e267962024-05-28 15:54:13 +01006277 // Zero bits beyond the MSB of a Q register.
6278 mov(kFormat16B, ReadVRegister(dst), ReadVRegister(dst));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006279 LogicVRegister(ReadVRegister(dst))
6280 .SetUint(kFormatD, 1, ReadXRegister(src));
6281 break;
6282 case FMOV_x_d1:
6283 WriteXRegister(dst, LogicVRegister(ReadVRegister(src)).Uint(kFormatD, 1));
6284 break;
6285
6286 // A 32-bit input can be handled in the same way as a 64-bit input, since
6287 // the sign- or zero-extension will not affect the conversion.
6288 case SCVTF_dx:
6289 WriteDRegister(dst, FixedToDouble(ReadXRegister(src), 0, round));
6290 break;
6291 case SCVTF_dw:
6292 WriteDRegister(dst, FixedToDouble(ReadWRegister(src), 0, round));
6293 break;
6294 case UCVTF_dx:
6295 WriteDRegister(dst, UFixedToDouble(ReadXRegister(src), 0, round));
6296 break;
6297 case UCVTF_dw: {
6298 WriteDRegister(dst,
Jacob Bramleyca789742018-09-13 14:25:46 +01006299 UFixedToDouble(ReadRegister<uint32_t>(src), 0, round));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006300 break;
6301 }
6302 case SCVTF_sx:
6303 WriteSRegister(dst, FixedToFloat(ReadXRegister(src), 0, round));
6304 break;
6305 case SCVTF_sw:
6306 WriteSRegister(dst, FixedToFloat(ReadWRegister(src), 0, round));
6307 break;
6308 case UCVTF_sx:
6309 WriteSRegister(dst, UFixedToFloat(ReadXRegister(src), 0, round));
6310 break;
6311 case UCVTF_sw: {
Jacob Bramleyca789742018-09-13 14:25:46 +01006312 WriteSRegister(dst, UFixedToFloat(ReadRegister<uint32_t>(src), 0, round));
6313 break;
6314 }
6315 case SCVTF_hx:
6316 WriteHRegister(dst, FixedToFloat16(ReadXRegister(src), 0, round));
6317 break;
6318 case SCVTF_hw:
6319 WriteHRegister(dst, FixedToFloat16(ReadWRegister(src), 0, round));
6320 break;
6321 case UCVTF_hx:
6322 WriteHRegister(dst, UFixedToFloat16(ReadXRegister(src), 0, round));
6323 break;
6324 case UCVTF_hw: {
6325 WriteHRegister(dst,
6326 UFixedToFloat16(ReadRegister<uint32_t>(src), 0, round));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006327 break;
6328 }
6329
6330 default:
6331 VIXL_UNREACHABLE();
6332 }
6333}
6334
6335
6336void Simulator::VisitFPFixedPointConvert(const Instruction* instr) {
6337 AssertSupportedFPCR();
6338
6339 unsigned dst = instr->GetRd();
6340 unsigned src = instr->GetRn();
6341 int fbits = 64 - instr->GetFPScale();
6342
6343 FPRounding round = ReadRMode();
6344
6345 switch (instr->Mask(FPFixedPointConvertMask)) {
6346 // A 32-bit input can be handled in the same way as a 64-bit input, since
6347 // the sign- or zero-extension will not affect the conversion.
6348 case SCVTF_dx_fixed:
6349 WriteDRegister(dst, FixedToDouble(ReadXRegister(src), fbits, round));
6350 break;
6351 case SCVTF_dw_fixed:
6352 WriteDRegister(dst, FixedToDouble(ReadWRegister(src), fbits, round));
6353 break;
6354 case UCVTF_dx_fixed:
6355 WriteDRegister(dst, UFixedToDouble(ReadXRegister(src), fbits, round));
6356 break;
6357 case UCVTF_dw_fixed: {
6358 WriteDRegister(dst,
Jacob Bramleyca789742018-09-13 14:25:46 +01006359 UFixedToDouble(ReadRegister<uint32_t>(src), fbits, round));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006360 break;
6361 }
6362 case SCVTF_sx_fixed:
6363 WriteSRegister(dst, FixedToFloat(ReadXRegister(src), fbits, round));
6364 break;
6365 case SCVTF_sw_fixed:
6366 WriteSRegister(dst, FixedToFloat(ReadWRegister(src), fbits, round));
6367 break;
6368 case UCVTF_sx_fixed:
6369 WriteSRegister(dst, UFixedToFloat(ReadXRegister(src), fbits, round));
6370 break;
6371 case UCVTF_sw_fixed: {
6372 WriteSRegister(dst,
Jacob Bramleyca789742018-09-13 14:25:46 +01006373 UFixedToFloat(ReadRegister<uint32_t>(src), fbits, round));
6374 break;
6375 }
6376 case SCVTF_hx_fixed:
6377 WriteHRegister(dst, FixedToFloat16(ReadXRegister(src), fbits, round));
6378 break;
6379 case SCVTF_hw_fixed:
6380 WriteHRegister(dst, FixedToFloat16(ReadWRegister(src), fbits, round));
6381 break;
6382 case UCVTF_hx_fixed:
6383 WriteHRegister(dst, UFixedToFloat16(ReadXRegister(src), fbits, round));
6384 break;
6385 case UCVTF_hw_fixed: {
6386 WriteHRegister(dst,
6387 UFixedToFloat16(ReadRegister<uint32_t>(src),
6388 fbits,
6389 round));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006390 break;
6391 }
6392 case FCVTZS_xd_fixed:
6393 WriteXRegister(dst,
6394 FPToInt64(ReadDRegister(src) * std::pow(2.0, fbits),
6395 FPZero));
6396 break;
6397 case FCVTZS_wd_fixed:
6398 WriteWRegister(dst,
6399 FPToInt32(ReadDRegister(src) * std::pow(2.0, fbits),
6400 FPZero));
6401 break;
6402 case FCVTZU_xd_fixed:
6403 WriteXRegister(dst,
6404 FPToUInt64(ReadDRegister(src) * std::pow(2.0, fbits),
6405 FPZero));
6406 break;
6407 case FCVTZU_wd_fixed:
6408 WriteWRegister(dst,
6409 FPToUInt32(ReadDRegister(src) * std::pow(2.0, fbits),
6410 FPZero));
6411 break;
6412 case FCVTZS_xs_fixed:
6413 WriteXRegister(dst,
6414 FPToInt64(ReadSRegister(src) * std::pow(2.0f, fbits),
6415 FPZero));
6416 break;
6417 case FCVTZS_ws_fixed:
6418 WriteWRegister(dst,
6419 FPToInt32(ReadSRegister(src) * std::pow(2.0f, fbits),
6420 FPZero));
6421 break;
6422 case FCVTZU_xs_fixed:
6423 WriteXRegister(dst,
6424 FPToUInt64(ReadSRegister(src) * std::pow(2.0f, fbits),
6425 FPZero));
6426 break;
6427 case FCVTZU_ws_fixed:
6428 WriteWRegister(dst,
6429 FPToUInt32(ReadSRegister(src) * std::pow(2.0f, fbits),
6430 FPZero));
6431 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006432 case FCVTZS_xh_fixed: {
6433 double output =
6434 static_cast<double>(ReadHRegister(src)) * std::pow(2.0, fbits);
6435 WriteXRegister(dst, FPToInt64(output, FPZero));
6436 break;
6437 }
6438 case FCVTZS_wh_fixed: {
6439 double output =
6440 static_cast<double>(ReadHRegister(src)) * std::pow(2.0, fbits);
6441 WriteWRegister(dst, FPToInt32(output, FPZero));
6442 break;
6443 }
6444 case FCVTZU_xh_fixed: {
6445 double output =
6446 static_cast<double>(ReadHRegister(src)) * std::pow(2.0, fbits);
6447 WriteXRegister(dst, FPToUInt64(output, FPZero));
6448 break;
6449 }
6450 case FCVTZU_wh_fixed: {
6451 double output =
6452 static_cast<double>(ReadHRegister(src)) * std::pow(2.0, fbits);
6453 WriteWRegister(dst, FPToUInt32(output, FPZero));
6454 break;
6455 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01006456 default:
6457 VIXL_UNREACHABLE();
6458 }
6459}
6460
6461
6462void Simulator::VisitFPCompare(const Instruction* instr) {
6463 AssertSupportedFPCR();
6464
6465 FPTrapFlags trap = DisableTrap;
6466 switch (instr->Mask(FPCompareMask)) {
Jacob Bramleyca789742018-09-13 14:25:46 +01006467 case FCMPE_h:
6468 trap = EnableTrap;
6469 VIXL_FALLTHROUGH();
6470 case FCMP_h:
6471 FPCompare(ReadHRegister(instr->GetRn()),
6472 ReadHRegister(instr->GetRm()),
6473 trap);
6474 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006475 case FCMPE_s:
6476 trap = EnableTrap;
6477 VIXL_FALLTHROUGH();
6478 case FCMP_s:
6479 FPCompare(ReadSRegister(instr->GetRn()),
6480 ReadSRegister(instr->GetRm()),
6481 trap);
6482 break;
6483 case FCMPE_d:
6484 trap = EnableTrap;
6485 VIXL_FALLTHROUGH();
6486 case FCMP_d:
6487 FPCompare(ReadDRegister(instr->GetRn()),
6488 ReadDRegister(instr->GetRm()),
6489 trap);
6490 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006491 case FCMPE_h_zero:
6492 trap = EnableTrap;
6493 VIXL_FALLTHROUGH();
6494 case FCMP_h_zero:
6495 FPCompare(ReadHRegister(instr->GetRn()), SimFloat16(0.0), trap);
6496 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006497 case FCMPE_s_zero:
6498 trap = EnableTrap;
6499 VIXL_FALLTHROUGH();
6500 case FCMP_s_zero:
6501 FPCompare(ReadSRegister(instr->GetRn()), 0.0f, trap);
6502 break;
6503 case FCMPE_d_zero:
6504 trap = EnableTrap;
6505 VIXL_FALLTHROUGH();
6506 case FCMP_d_zero:
6507 FPCompare(ReadDRegister(instr->GetRn()), 0.0, trap);
6508 break;
6509 default:
6510 VIXL_UNIMPLEMENTED();
6511 }
6512}
6513
6514
6515void Simulator::VisitFPConditionalCompare(const Instruction* instr) {
6516 AssertSupportedFPCR();
6517
6518 FPTrapFlags trap = DisableTrap;
6519 switch (instr->Mask(FPConditionalCompareMask)) {
Jacob Bramleyca789742018-09-13 14:25:46 +01006520 case FCCMPE_h:
6521 trap = EnableTrap;
6522 VIXL_FALLTHROUGH();
6523 case FCCMP_h:
6524 if (ConditionPassed(instr->GetCondition())) {
6525 FPCompare(ReadHRegister(instr->GetRn()),
6526 ReadHRegister(instr->GetRm()),
6527 trap);
6528 } else {
6529 ReadNzcv().SetFlags(instr->GetNzcv());
6530 LogSystemRegister(NZCV);
6531 }
6532 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006533 case FCCMPE_s:
6534 trap = EnableTrap;
6535 VIXL_FALLTHROUGH();
6536 case FCCMP_s:
6537 if (ConditionPassed(instr->GetCondition())) {
6538 FPCompare(ReadSRegister(instr->GetRn()),
6539 ReadSRegister(instr->GetRm()),
6540 trap);
6541 } else {
6542 ReadNzcv().SetFlags(instr->GetNzcv());
6543 LogSystemRegister(NZCV);
6544 }
6545 break;
6546 case FCCMPE_d:
6547 trap = EnableTrap;
6548 VIXL_FALLTHROUGH();
6549 case FCCMP_d:
6550 if (ConditionPassed(instr->GetCondition())) {
6551 FPCompare(ReadDRegister(instr->GetRn()),
6552 ReadDRegister(instr->GetRm()),
6553 trap);
6554 } else {
6555 ReadNzcv().SetFlags(instr->GetNzcv());
6556 LogSystemRegister(NZCV);
6557 }
6558 break;
6559 default:
6560 VIXL_UNIMPLEMENTED();
6561 }
6562}
6563
6564
6565void Simulator::VisitFPConditionalSelect(const Instruction* instr) {
6566 AssertSupportedFPCR();
6567
6568 Instr selected;
6569 if (ConditionPassed(instr->GetCondition())) {
6570 selected = instr->GetRn();
6571 } else {
6572 selected = instr->GetRm();
6573 }
6574
6575 switch (instr->Mask(FPConditionalSelectMask)) {
Jacob Bramleyca789742018-09-13 14:25:46 +01006576 case FCSEL_h:
6577 WriteHRegister(instr->GetRd(), ReadHRegister(selected));
6578 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006579 case FCSEL_s:
6580 WriteSRegister(instr->GetRd(), ReadSRegister(selected));
6581 break;
6582 case FCSEL_d:
6583 WriteDRegister(instr->GetRd(), ReadDRegister(selected));
6584 break;
6585 default:
6586 VIXL_UNIMPLEMENTED();
6587 }
6588}
6589
6590
6591void Simulator::VisitFPDataProcessing1Source(const Instruction* instr) {
6592 AssertSupportedFPCR();
6593
6594 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
Carey Williamsd8bb3572018-04-10 11:58:07 +01006595 VectorFormat vform;
Jacob Bramleyc41760b2018-06-08 17:14:58 +01006596 switch (instr->Mask(FPTypeMask)) {
6597 default:
6598 VIXL_UNREACHABLE_OR_FALLTHROUGH();
6599 case FP64:
6600 vform = kFormatD;
6601 break;
6602 case FP32:
6603 vform = kFormatS;
6604 break;
6605 case FP16:
6606 vform = kFormatH;
6607 break;
Carey Williamsd8bb3572018-04-10 11:58:07 +01006608 }
Jacob Bramleyca789742018-09-13 14:25:46 +01006609
Alexandre Ramesd3832962016-07-04 15:03:43 +01006610 SimVRegister& rd = ReadVRegister(instr->GetRd());
6611 SimVRegister& rn = ReadVRegister(instr->GetRn());
6612 bool inexact_exception = false;
TatWai Chong04471812019-03-19 14:29:00 -07006613 FrintMode frint_mode = kFrintToInteger;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006614
6615 unsigned fd = instr->GetRd();
6616 unsigned fn = instr->GetRn();
6617
6618 switch (instr->Mask(FPDataProcessing1SourceMask)) {
Carey Williamsd8bb3572018-04-10 11:58:07 +01006619 case FMOV_h:
6620 WriteHRegister(fd, ReadHRegister(fn));
6621 return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006622 case FMOV_s:
6623 WriteSRegister(fd, ReadSRegister(fn));
6624 return;
6625 case FMOV_d:
6626 WriteDRegister(fd, ReadDRegister(fn));
6627 return;
Jacob Bramleyca789742018-09-13 14:25:46 +01006628 case FABS_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006629 case FABS_s:
6630 case FABS_d:
6631 fabs_(vform, ReadVRegister(fd), ReadVRegister(fn));
6632 // Explicitly log the register update whilst we have type information.
6633 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
6634 return;
Jacob Bramleyca789742018-09-13 14:25:46 +01006635 case FNEG_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006636 case FNEG_s:
6637 case FNEG_d:
6638 fneg(vform, ReadVRegister(fd), ReadVRegister(fn));
6639 // Explicitly log the register update whilst we have type information.
6640 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
6641 return;
6642 case FCVT_ds:
Carey Williamsb57e3622018-04-10 11:42:03 +01006643 WriteDRegister(fd, FPToDouble(ReadSRegister(fn), ReadDN()));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006644 return;
6645 case FCVT_sd:
Carey Williamsb57e3622018-04-10 11:42:03 +01006646 WriteSRegister(fd, FPToFloat(ReadDRegister(fn), FPTieEven, ReadDN()));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006647 return;
6648 case FCVT_hs:
Jacob Bramleyca789742018-09-13 14:25:46 +01006649 WriteHRegister(fd,
6650 Float16ToRawbits(
6651 FPToFloat16(ReadSRegister(fn), FPTieEven, ReadDN())));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006652 return;
6653 case FCVT_sh:
Carey Williamsb57e3622018-04-10 11:42:03 +01006654 WriteSRegister(fd, FPToFloat(ReadHRegister(fn), ReadDN()));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006655 return;
6656 case FCVT_dh:
Jacob Bramleyca789742018-09-13 14:25:46 +01006657 WriteDRegister(fd, FPToDouble(ReadHRegister(fn), ReadDN()));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006658 return;
6659 case FCVT_hd:
Jacob Bramleyca789742018-09-13 14:25:46 +01006660 WriteHRegister(fd,
6661 Float16ToRawbits(
6662 FPToFloat16(ReadDRegister(fn), FPTieEven, ReadDN())));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006663 return;
Jacob Bramleyca789742018-09-13 14:25:46 +01006664 case FSQRT_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006665 case FSQRT_s:
6666 case FSQRT_d:
6667 fsqrt(vform, rd, rn);
6668 // Explicitly log the register update whilst we have type information.
6669 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
6670 return;
TatWai Chong04471812019-03-19 14:29:00 -07006671 case FRINT32X_s:
6672 case FRINT32X_d:
6673 inexact_exception = true;
6674 frint_mode = kFrintToInt32;
6675 break; // Use FPCR rounding mode.
6676 case FRINT64X_s:
6677 case FRINT64X_d:
6678 inexact_exception = true;
6679 frint_mode = kFrintToInt64;
6680 break; // Use FPCR rounding mode.
6681 case FRINT32Z_s:
6682 case FRINT32Z_d:
6683 inexact_exception = true;
6684 frint_mode = kFrintToInt32;
6685 fpcr_rounding = FPZero;
6686 break;
6687 case FRINT64Z_s:
6688 case FRINT64Z_d:
6689 inexact_exception = true;
6690 frint_mode = kFrintToInt64;
6691 fpcr_rounding = FPZero;
6692 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006693 case FRINTI_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006694 case FRINTI_s:
6695 case FRINTI_d:
6696 break; // Use FPCR rounding mode.
Jacob Bramleyca789742018-09-13 14:25:46 +01006697 case FRINTX_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006698 case FRINTX_s:
6699 case FRINTX_d:
6700 inexact_exception = true;
6701 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006702 case FRINTA_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006703 case FRINTA_s:
6704 case FRINTA_d:
6705 fpcr_rounding = FPTieAway;
6706 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006707 case FRINTM_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006708 case FRINTM_s:
6709 case FRINTM_d:
6710 fpcr_rounding = FPNegativeInfinity;
6711 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006712 case FRINTN_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006713 case FRINTN_s:
6714 case FRINTN_d:
6715 fpcr_rounding = FPTieEven;
6716 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006717 case FRINTP_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006718 case FRINTP_s:
6719 case FRINTP_d:
6720 fpcr_rounding = FPPositiveInfinity;
6721 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006722 case FRINTZ_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006723 case FRINTZ_s:
6724 case FRINTZ_d:
6725 fpcr_rounding = FPZero;
6726 break;
6727 default:
6728 VIXL_UNIMPLEMENTED();
6729 }
6730
6731 // Only FRINT* instructions fall through the switch above.
TatWai Chong04471812019-03-19 14:29:00 -07006732 frint(vform, rd, rn, fpcr_rounding, inexact_exception, frint_mode);
Alexandre Ramesd3832962016-07-04 15:03:43 +01006733 // Explicitly log the register update whilst we have type information.
6734 LogVRegister(fd, GetPrintRegisterFormatFP(vform));
6735}
6736
6737
6738void Simulator::VisitFPDataProcessing2Source(const Instruction* instr) {
6739 AssertSupportedFPCR();
6740
Carey Williamsd8bb3572018-04-10 11:58:07 +01006741 VectorFormat vform;
Jacob Bramleyc41760b2018-06-08 17:14:58 +01006742 switch (instr->Mask(FPTypeMask)) {
6743 default:
6744 VIXL_UNREACHABLE_OR_FALLTHROUGH();
6745 case FP64:
6746 vform = kFormatD;
6747 break;
6748 case FP32:
6749 vform = kFormatS;
6750 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006751 case FP16:
6752 vform = kFormatH;
6753 break;
Carey Williamsd8bb3572018-04-10 11:58:07 +01006754 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01006755 SimVRegister& rd = ReadVRegister(instr->GetRd());
6756 SimVRegister& rn = ReadVRegister(instr->GetRn());
6757 SimVRegister& rm = ReadVRegister(instr->GetRm());
6758
6759 switch (instr->Mask(FPDataProcessing2SourceMask)) {
Jacob Bramleyca789742018-09-13 14:25:46 +01006760 case FADD_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006761 case FADD_s:
6762 case FADD_d:
6763 fadd(vform, rd, rn, rm);
6764 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006765 case FSUB_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006766 case FSUB_s:
6767 case FSUB_d:
6768 fsub(vform, rd, rn, rm);
6769 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006770 case FMUL_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006771 case FMUL_s:
6772 case FMUL_d:
6773 fmul(vform, rd, rn, rm);
6774 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006775 case FNMUL_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006776 case FNMUL_s:
6777 case FNMUL_d:
6778 fnmul(vform, rd, rn, rm);
6779 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006780 case FDIV_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006781 case FDIV_s:
6782 case FDIV_d:
6783 fdiv(vform, rd, rn, rm);
6784 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006785 case FMAX_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006786 case FMAX_s:
6787 case FMAX_d:
6788 fmax(vform, rd, rn, rm);
6789 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006790 case FMIN_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006791 case FMIN_s:
6792 case FMIN_d:
6793 fmin(vform, rd, rn, rm);
6794 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006795 case FMAXNM_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006796 case FMAXNM_s:
6797 case FMAXNM_d:
6798 fmaxnm(vform, rd, rn, rm);
6799 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01006800 case FMINNM_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01006801 case FMINNM_s:
6802 case FMINNM_d:
6803 fminnm(vform, rd, rn, rm);
6804 break;
6805 default:
6806 VIXL_UNREACHABLE();
6807 }
6808 // Explicitly log the register update whilst we have type information.
6809 LogVRegister(instr->GetRd(), GetPrintRegisterFormatFP(vform));
6810}
6811
6812
6813void Simulator::VisitFPDataProcessing3Source(const Instruction* instr) {
6814 AssertSupportedFPCR();
6815
6816 unsigned fd = instr->GetRd();
6817 unsigned fn = instr->GetRn();
6818 unsigned fm = instr->GetRm();
6819 unsigned fa = instr->GetRa();
6820
6821 switch (instr->Mask(FPDataProcessing3SourceMask)) {
6822 // fd = fa +/- (fn * fm)
Jacob Bramleyca789742018-09-13 14:25:46 +01006823 case FMADD_h:
6824 WriteHRegister(fd,
6825 FPMulAdd(ReadHRegister(fa),
6826 ReadHRegister(fn),
6827 ReadHRegister(fm)));
6828 break;
6829 case FMSUB_h:
6830 WriteHRegister(fd,
6831 FPMulAdd(ReadHRegister(fa),
6832 -ReadHRegister(fn),
6833 ReadHRegister(fm)));
6834 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006835 case FMADD_s:
6836 WriteSRegister(fd,
6837 FPMulAdd(ReadSRegister(fa),
6838 ReadSRegister(fn),
6839 ReadSRegister(fm)));
6840 break;
6841 case FMSUB_s:
6842 WriteSRegister(fd,
6843 FPMulAdd(ReadSRegister(fa),
6844 -ReadSRegister(fn),
6845 ReadSRegister(fm)));
6846 break;
6847 case FMADD_d:
6848 WriteDRegister(fd,
6849 FPMulAdd(ReadDRegister(fa),
6850 ReadDRegister(fn),
6851 ReadDRegister(fm)));
6852 break;
6853 case FMSUB_d:
6854 WriteDRegister(fd,
6855 FPMulAdd(ReadDRegister(fa),
6856 -ReadDRegister(fn),
6857 ReadDRegister(fm)));
6858 break;
6859 // Negated variants of the above.
Jacob Bramleyca789742018-09-13 14:25:46 +01006860 case FNMADD_h:
6861 WriteHRegister(fd,
6862 FPMulAdd(-ReadHRegister(fa),
6863 -ReadHRegister(fn),
6864 ReadHRegister(fm)));
6865 break;
6866 case FNMSUB_h:
6867 WriteHRegister(fd,
6868 FPMulAdd(-ReadHRegister(fa),
6869 ReadHRegister(fn),
6870 ReadHRegister(fm)));
6871 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006872 case FNMADD_s:
6873 WriteSRegister(fd,
6874 FPMulAdd(-ReadSRegister(fa),
6875 -ReadSRegister(fn),
6876 ReadSRegister(fm)));
6877 break;
6878 case FNMSUB_s:
6879 WriteSRegister(fd,
6880 FPMulAdd(-ReadSRegister(fa),
6881 ReadSRegister(fn),
6882 ReadSRegister(fm)));
6883 break;
6884 case FNMADD_d:
6885 WriteDRegister(fd,
6886 FPMulAdd(-ReadDRegister(fa),
6887 -ReadDRegister(fn),
6888 ReadDRegister(fm)));
6889 break;
6890 case FNMSUB_d:
6891 WriteDRegister(fd,
6892 FPMulAdd(-ReadDRegister(fa),
6893 ReadDRegister(fn),
6894 ReadDRegister(fm)));
6895 break;
6896 default:
6897 VIXL_UNIMPLEMENTED();
6898 }
6899}
6900
6901
6902bool Simulator::FPProcessNaNs(const Instruction* instr) {
6903 unsigned fd = instr->GetRd();
6904 unsigned fn = instr->GetRn();
6905 unsigned fm = instr->GetRm();
6906 bool done = false;
6907
6908 if (instr->Mask(FP64) == FP64) {
6909 double result = FPProcessNaNs(ReadDRegister(fn), ReadDRegister(fm));
Jacob Bramleyca789742018-09-13 14:25:46 +01006910 if (IsNaN(result)) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01006911 WriteDRegister(fd, result);
6912 done = true;
6913 }
Jacob Bramleyca789742018-09-13 14:25:46 +01006914 } else if (instr->Mask(FP32) == FP32) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01006915 float result = FPProcessNaNs(ReadSRegister(fn), ReadSRegister(fm));
Jacob Bramleyca789742018-09-13 14:25:46 +01006916 if (IsNaN(result)) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01006917 WriteSRegister(fd, result);
6918 done = true;
6919 }
Jacob Bramleyca789742018-09-13 14:25:46 +01006920 } else {
6921 VIXL_ASSERT(instr->Mask(FP16) == FP16);
6922 VIXL_UNIMPLEMENTED();
Alexandre Ramesd3832962016-07-04 15:03:43 +01006923 }
6924
6925 return done;
6926}
6927
6928
mmc28a89bd9292025-01-31 14:31:14 +00006929bool Simulator::SysOp_W(int op, int64_t val) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01006930 switch (op) {
6931 case IVAU:
6932 case CVAC:
6933 case CVAU:
Jacob Bramley385eb902018-09-26 14:43:29 +01006934 case CVAP:
TatWai Chong684f5f72018-12-25 17:49:56 -08006935 case CVADP:
Martyn Capewell5c310da2022-03-16 17:04:37 +00006936 case CIVAC:
6937 case CGVAC:
6938 case CGDVAC:
6939 case CGVAP:
6940 case CGDVAP:
6941 case CIGVAC:
6942 case CIGDVAC: {
Martyn Capewelld42989c2020-11-10 14:32:56 +00006943 // Perform a placeholder memory access to ensure that we have read access
Martyn Capewell5c310da2022-03-16 17:04:37 +00006944 // to the specified address. The read access does not require a tag match,
6945 // so temporarily disable MTE.
6946 bool mte_enabled = MetaDataDepot::MetaDataMTE::IsActive();
6947 MetaDataDepot::MetaDataMTE::SetActive(false);
Chris Jones30e7bbd2024-02-15 15:05:25 +00006948 volatile uint8_t y = *MemRead<uint8_t>(val);
Martyn Capewell5c310da2022-03-16 17:04:37 +00006949 MetaDataDepot::MetaDataMTE::SetActive(mte_enabled);
Alexandre Ramesd3832962016-07-04 15:03:43 +01006950 USE(y);
Alexandre Ramesd3832962016-07-04 15:03:43 +01006951 break;
6952 }
mmc28a89bd9292025-01-31 14:31:14 +00006953 case ZVA: {
6954 if ((dczid_ & 0x10) != 0) { // Check dc zva is enabled.
6955 return false;
6956 }
6957 int blocksize = (1 << (dczid_ & 0xf)) * kWRegSizeInBytes;
6958 VIXL_ASSERT(IsMultiple(blocksize, sizeof(uint64_t)));
6959 uintptr_t addr = AlignDown(val, blocksize);
6960 for (int i = 0; i < blocksize; i += sizeof(uint64_t)) {
6961 MemWrite<uint64_t>(addr + i, 0);
6962 LogWriteU64(0, addr + i);
6963 }
6964 break;
6965 }
6966 // TODO: Implement GVA, GZVA.
Alexandre Ramesd3832962016-07-04 15:03:43 +01006967 default:
6968 VIXL_UNIMPLEMENTED();
mmc28a89bd9292025-01-31 14:31:14 +00006969 return false;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006970 }
mmc28a89bd9292025-01-31 14:31:14 +00006971 return true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01006972}
6973
mmc28a8c05ce72022-11-02 11:06:43 +00006974void Simulator::PACHelper(int dst,
6975 int src,
6976 PACKey key,
6977 decltype(&Simulator::AddPAC) pac_fn) {
6978 VIXL_ASSERT((dst == 17) || (dst == 30));
6979 VIXL_ASSERT((src == -1) || (src == 16) || (src == 31));
Alexandre Ramesd3832962016-07-04 15:03:43 +01006980
mmc28a8c05ce72022-11-02 11:06:43 +00006981 uint64_t modifier = (src == -1) ? 0 : ReadXRegister(src, Reg31IsStackPointer);
6982 uint64_t result =
6983 (this->*pac_fn)(ReadXRegister(dst), modifier, key, kInstructionPointer);
6984 WriteXRegister(dst, result);
6985}
Jacob Bramleyca789742018-09-13 14:25:46 +01006986
Alexandre Ramesd3832962016-07-04 15:03:43 +01006987void Simulator::VisitSystem(const Instruction* instr) {
mmc28a8c05ce72022-11-02 11:06:43 +00006988 PACKey pac_key = kPACKeyIA; // Default key for PAC/AUTH handling.
6989
6990 switch (form_hash_) {
6991 case "cfinv_m_pstate"_h:
6992 ReadNzcv().SetC(!ReadC());
6993 break;
6994 case "axflag_m_pstate"_h:
6995 ReadNzcv().SetN(0);
6996 ReadNzcv().SetZ(ReadNzcv().GetZ() | ReadNzcv().GetV());
6997 ReadNzcv().SetC(ReadNzcv().GetC() & ~ReadNzcv().GetV());
6998 ReadNzcv().SetV(0);
6999 break;
7000 case "xaflag_m_pstate"_h: {
7001 // Can't set the flags in place due to the logical dependencies.
7002 uint32_t n = (~ReadNzcv().GetC() & ~ReadNzcv().GetZ()) & 1;
7003 uint32_t z = ReadNzcv().GetZ() & ReadNzcv().GetC();
7004 uint32_t c = ReadNzcv().GetC() | ReadNzcv().GetZ();
7005 uint32_t v = ~ReadNzcv().GetC() & ReadNzcv().GetZ();
7006 ReadNzcv().SetN(n);
7007 ReadNzcv().SetZ(z);
7008 ReadNzcv().SetC(c);
7009 ReadNzcv().SetV(v);
7010 break;
Alexander Gilday2487f142018-11-05 13:07:27 +00007011 }
mmc28a8c05ce72022-11-02 11:06:43 +00007012 case "xpaclri_hi_hints"_h:
7013 WriteXRegister(30, StripPAC(ReadXRegister(30), kInstructionPointer));
7014 break;
7015 case "clrex_bn_barriers"_h:
7016 PrintExclusiveAccessWarning();
7017 ClearLocalMonitor();
7018 break;
7019 case "msr_sr_systemmove"_h:
7020 switch (instr->GetImmSystemRegister()) {
7021 case NZCV:
7022 ReadNzcv().SetRawValue(ReadWRegister(instr->GetRt()));
7023 LogSystemRegister(NZCV);
7024 break;
7025 case FPCR:
7026 ReadFpcr().SetRawValue(ReadWRegister(instr->GetRt()));
7027 LogSystemRegister(FPCR);
7028 break;
7029 default:
7030 VIXL_UNIMPLEMENTED();
7031 }
7032 break;
7033 case "mrs_rs_systemmove"_h:
7034 switch (instr->GetImmSystemRegister()) {
7035 case NZCV:
7036 WriteXRegister(instr->GetRt(), ReadNzcv().GetRawValue());
7037 break;
7038 case FPCR:
7039 WriteXRegister(instr->GetRt(), ReadFpcr().GetRawValue());
7040 break;
7041 case RNDR:
7042 case RNDRRS: {
TheLastRardfc2ffb2024-08-15 14:30:18 +01007043 uint64_t high = rand_gen_();
7044 uint64_t low = rand_gen_();
mmc28a8c05ce72022-11-02 11:06:43 +00007045 uint64_t rand_num = (high << 32) | (low & 0xffffffff);
7046 WriteXRegister(instr->GetRt(), rand_num);
7047 // Simulate successful random number generation.
7048 // TODO: Return failure occasionally as a random number cannot be
7049 // returned in a period of time.
7050 ReadNzcv().SetRawValue(NoFlag);
7051 LogSystemRegister(NZCV);
7052 break;
7053 }
mmc28a89bd9292025-01-31 14:31:14 +00007054 case DCZID_EL0:
7055 WriteXRegister(instr->GetRt(), dczid_);
7056 break;
mmc28a8c05ce72022-11-02 11:06:43 +00007057 default:
7058 VIXL_UNIMPLEMENTED();
7059 }
7060 break;
mmc28a3c407232024-06-19 15:03:55 +01007061 case "chkfeat_hf_hints"_h: {
7062 uint64_t feat_select = ReadXRegister(16);
7063 uint64_t gcs_enabled = IsGCSCheckEnabled() ? 1 : 0;
7064 feat_select &= ~gcs_enabled;
7065 WriteXRegister(16, feat_select);
7066 break;
7067 }
7068 case "hint_hm_hints"_h:
mmc28a8c05ce72022-11-02 11:06:43 +00007069 case "nop_hi_hints"_h:
Ryan Houdekf268dd82025-02-25 08:55:24 -08007070 case "yield_hi_hints"_h:
mmc28a8c05ce72022-11-02 11:06:43 +00007071 case "esb_hi_hints"_h:
7072 case "csdb_hi_hints"_h:
7073 break;
7074 case "bti_hb_hints"_h:
7075 switch (instr->GetImmHint()) {
7076 case BTI_jc:
7077 break;
7078 case BTI:
7079 if (PcIsInGuardedPage() && (ReadBType() != DefaultBType)) {
7080 VIXL_ABORT_WITH_MSG("Executing BTI with wrong BType.");
7081 }
7082 break;
7083 case BTI_c:
7084 if (PcIsInGuardedPage() &&
7085 (ReadBType() == BranchFromGuardedNotToIP)) {
7086 VIXL_ABORT_WITH_MSG("Executing BTI c with wrong BType.");
7087 }
7088 break;
7089 case BTI_j:
7090 if (PcIsInGuardedPage() && (ReadBType() == BranchAndLink)) {
7091 VIXL_ABORT_WITH_MSG("Executing BTI j with wrong BType.");
7092 }
7093 break;
7094 default:
7095 VIXL_UNREACHABLE();
7096 }
7097 return;
7098 case "pacib1716_hi_hints"_h:
7099 pac_key = kPACKeyIB;
7100 VIXL_FALLTHROUGH();
7101 case "pacia1716_hi_hints"_h:
7102 PACHelper(17, 16, pac_key, &Simulator::AddPAC);
7103 break;
7104 case "pacibsp_hi_hints"_h:
7105 pac_key = kPACKeyIB;
7106 VIXL_FALLTHROUGH();
7107 case "paciasp_hi_hints"_h:
7108 PACHelper(30, 31, pac_key, &Simulator::AddPAC);
7109
7110 // Check BType allows PACI[AB]SP instructions.
7111 if (PcIsInGuardedPage()) {
Martyn Capewellcb963f72018-10-22 15:25:28 +01007112 switch (ReadBType()) {
Martyn Capewellcb963f72018-10-22 15:25:28 +01007113 case BranchFromGuardedNotToIP:
7114 // TODO: This case depends on the value of SCTLR_EL1.BT0, which we
7115 // assume here to be zero. This allows execution of PACI[AB]SP when
7116 // BTYPE is BranchFromGuardedNotToIP (0b11).
Martyn Capewelldddf02d2019-02-12 10:41:17 +00007117 case DefaultBType:
Martyn Capewellcb963f72018-10-22 15:25:28 +01007118 case BranchFromUnguardedOrToIP:
7119 case BranchAndLink:
7120 break;
7121 }
7122 }
mmc28a8c05ce72022-11-02 11:06:43 +00007123 break;
7124 case "pacibz_hi_hints"_h:
7125 pac_key = kPACKeyIB;
7126 VIXL_FALLTHROUGH();
7127 case "paciaz_hi_hints"_h:
7128 PACHelper(30, -1, pac_key, &Simulator::AddPAC);
7129 break;
7130 case "autib1716_hi_hints"_h:
7131 pac_key = kPACKeyIB;
7132 VIXL_FALLTHROUGH();
7133 case "autia1716_hi_hints"_h:
7134 PACHelper(17, 16, pac_key, &Simulator::AuthPAC);
7135 break;
7136 case "autibsp_hi_hints"_h:
7137 pac_key = kPACKeyIB;
7138 VIXL_FALLTHROUGH();
7139 case "autiasp_hi_hints"_h:
7140 PACHelper(30, 31, pac_key, &Simulator::AuthPAC);
7141 break;
7142 case "autibz_hi_hints"_h:
7143 pac_key = kPACKeyIB;
7144 VIXL_FALLTHROUGH();
7145 case "autiaz_hi_hints"_h:
7146 PACHelper(30, -1, pac_key, &Simulator::AuthPAC);
7147 break;
7148 case "dsb_bo_barriers"_h:
7149 case "dmb_bo_barriers"_h:
7150 case "isb_bi_barriers"_h:
TheLastRar49d6efa2024-10-15 16:37:27 +01007151 VIXL_SYNC();
mmc28a8c05ce72022-11-02 11:06:43 +00007152 break;
mmc28a3c407232024-06-19 15:03:55 +01007153 case "sys_cr_systeminstrs"_h: {
7154 uint64_t rt = ReadXRegister(instr->GetRt());
7155 uint32_t sysop = instr->GetSysOp();
7156 if (sysop == GCSSS1) {
7157 uint64_t incoming_size = rt >> 32;
7158 // Drop upper 32 bits to get GCS index.
7159 uint64_t incoming_gcs = rt & 0xffffffff;
7160 uint64_t outgoing_gcs = ActivateGCS(incoming_gcs);
7161 uint64_t incoming_seal = GCSPop();
7162 if (((incoming_seal ^ rt) != 1) ||
7163 (GetActiveGCSPtr()->size() != incoming_size)) {
7164 char msg[128];
7165 snprintf(msg,
7166 sizeof(msg),
7167 "GCS: invalid incoming stack: 0x%016" PRIx64 "\n",
7168 incoming_seal);
7169 ReportGCSFailure(msg);
7170 }
7171 GCSPush(outgoing_gcs + 5);
7172 } else if (sysop == GCSPUSHM) {
7173 GCSPush(ReadXRegister(instr->GetRt()));
7174 } else {
mmc28a89bd9292025-01-31 14:31:14 +00007175 if (!SysOp_W(sysop, rt)) {
7176 VisitUnallocated(instr);
7177 }
mmc28a3c407232024-06-19 15:03:55 +01007178 }
mmc28a8c05ce72022-11-02 11:06:43 +00007179 break;
mmc28a3c407232024-06-19 15:03:55 +01007180 }
7181 case "sysl_rc_systeminstrs"_h: {
7182 uint32_t sysop = instr->GetSysOp();
7183 if (sysop == GCSPOPM) {
7184 uint64_t addr = GCSPop();
7185 WriteXRegister(instr->GetRt(), addr);
7186 } else if (sysop == GCSSS2) {
7187 uint64_t outgoing_gcs = GCSPop();
7188 // Check for token inserted by gcsss1.
7189 if ((outgoing_gcs & 7) != 5) {
7190 char msg[128];
7191 snprintf(msg,
7192 sizeof(msg),
7193 "GCS: outgoing stack has no token: 0x%016" PRIx64 "\n",
7194 outgoing_gcs);
7195 ReportGCSFailure(msg);
7196 }
7197 uint64_t incoming_gcs = ActivateGCS(outgoing_gcs);
7198 outgoing_gcs &= ~UINT64_C(0x3ff);
7199
7200 // Encode the size into the outgoing stack seal, to check later.
7201 uint64_t size = GetActiveGCSPtr()->size();
7202 VIXL_ASSERT(IsUint32(size));
7203 VIXL_ASSERT(IsUint32(outgoing_gcs + 1));
7204 uint64_t outgoing_seal = (size << 32) | (outgoing_gcs + 1);
7205 GCSPush(outgoing_seal);
7206 ActivateGCS(incoming_gcs);
7207 WriteXRegister(instr->GetRt(), outgoing_seal - 1);
7208 } else {
7209 VIXL_UNIMPLEMENTED();
7210 }
7211 break;
7212 }
mmc28a8c05ce72022-11-02 11:06:43 +00007213 default:
7214 VIXL_UNIMPLEMENTED();
Alexandre Ramesd3832962016-07-04 15:03:43 +01007215 }
7216}
7217
7218
7219void Simulator::VisitException(const Instruction* instr) {
7220 switch (instr->Mask(ExceptionMask)) {
7221 case HLT:
7222 switch (instr->GetImmException()) {
7223 case kUnreachableOpcode:
7224 DoUnreachable(instr);
7225 return;
7226 case kTraceOpcode:
7227 DoTrace(instr);
7228 return;
7229 case kLogOpcode:
7230 DoLog(instr);
7231 return;
7232 case kPrintfOpcode:
7233 DoPrintf(instr);
7234 return;
Alexandre Rames064e02d2016-07-12 11:53:13 +01007235 case kRuntimeCallOpcode:
7236 DoRuntimeCall(instr);
7237 return;
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +01007238 case kSetCPUFeaturesOpcode:
7239 case kEnableCPUFeaturesOpcode:
7240 case kDisableCPUFeaturesOpcode:
7241 DoConfigureCPUFeatures(instr);
7242 return;
7243 case kSaveCPUFeaturesOpcode:
7244 DoSaveCPUFeatures(instr);
7245 return;
7246 case kRestoreCPUFeaturesOpcode:
7247 DoRestoreCPUFeatures(instr);
7248 return;
TatWai Chong6767df02022-03-25 11:33:54 -07007249 case kMTEActive:
7250 MetaDataDepot::MetaDataMTE::SetActive(true);
7251 return;
7252 case kMTEInactive:
7253 MetaDataDepot::MetaDataMTE::SetActive(false);
7254 return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01007255 default:
7256 HostBreakpoint();
7257 return;
7258 }
7259 case BRK:
Chris Jonesa0a14392023-12-08 13:59:42 +00007260 if (debugger_enabled_) {
7261 uint64_t next_instr =
7262 reinterpret_cast<uint64_t>(pc_->GetNextInstruction());
7263 if (!debugger_->IsBreakpoint(next_instr)) {
7264 debugger_->RegisterBreakpoint(next_instr);
7265 }
7266 } else {
7267 HostBreakpoint();
7268 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01007269 return;
7270 default:
7271 VIXL_UNIMPLEMENTED();
7272 }
7273}
7274
7275
7276void Simulator::VisitCrypto2RegSHA(const Instruction* instr) {
mmc28a7eb48c62024-06-25 10:12:38 +01007277 SimVRegister& rd = ReadVRegister(instr->GetRd());
7278 SimVRegister& rn = ReadVRegister(instr->GetRn());
7279
7280 switch (form_hash_) {
7281 case "sha1h_ss_cryptosha2"_h:
7282 ror(kFormatS, rd, rn, 2);
7283 break;
7284 case "sha1su1_vv_cryptosha2"_h: {
7285 SimVRegister temp;
7286
7287 // temp = srcdst ^ (src >> 32);
7288 ext(kFormat16B, temp, rn, temp, 4);
7289 eor(kFormat16B, temp, rd, temp);
7290
7291 // srcdst = ROL(temp, 1) ^ (ROL(temp, 2) << 96)
7292 rol(kFormat4S, rd, temp, 1);
7293 rol(kFormatS, temp, temp, 2); // kFormatS will zero bits <127:32>
7294 ext(kFormat16B, temp, temp, temp, 4);
7295 eor(kFormat16B, rd, rd, temp);
7296 break;
7297 }
7298 case "sha256su0_vv_cryptosha2"_h:
mmc28aaabfa0c2024-06-25 13:35:22 +01007299 sha2su0(rd, rn);
mmc28a7eb48c62024-06-25 10:12:38 +01007300 break;
7301 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01007302}
7303
7304
7305void Simulator::VisitCrypto3RegSHA(const Instruction* instr) {
mmc28a7eb48c62024-06-25 10:12:38 +01007306 SimVRegister& rd = ReadVRegister(instr->GetRd());
7307 SimVRegister& rn = ReadVRegister(instr->GetRn());
7308 SimVRegister& rm = ReadVRegister(instr->GetRm());
7309
7310 switch (form_hash_) {
7311 case "sha1c_qsv_cryptosha3"_h:
7312 sha1<"choose"_h>(rd, rn, rm);
7313 break;
7314 case "sha1m_qsv_cryptosha3"_h:
7315 sha1<"majority"_h>(rd, rn, rm);
7316 break;
7317 case "sha1p_qsv_cryptosha3"_h:
7318 sha1<"parity"_h>(rd, rn, rm);
7319 break;
7320 case "sha1su0_vvv_cryptosha3"_h: {
7321 SimVRegister temp;
7322 ext(kFormat16B, temp, rd, rn, 8);
7323 eor(kFormat16B, temp, temp, rd);
7324 eor(kFormat16B, rd, temp, rm);
7325 break;
7326 }
mmc28aaabfa0c2024-06-25 13:35:22 +01007327 case "sha256h_qqv_cryptosha3"_h:
7328 sha2h(rd, rn, rm, /* part1 = */ true);
7329 break;
7330 case "sha256h2_qqv_cryptosha3"_h:
7331 sha2h(rd, rn, rm, /* part1 = */ false);
7332 break;
7333 case "sha256su1_vvv_cryptosha3"_h:
7334 sha2su1(rd, rn, rm);
7335 break;
mmc28a7eb48c62024-06-25 10:12:38 +01007336 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01007337}
7338
7339
7340void Simulator::VisitCryptoAES(const Instruction* instr) {
mmc28ada718c22024-07-18 13:33:12 +01007341 SimVRegister& rd = ReadVRegister(instr->GetRd());
7342 SimVRegister& rn = ReadVRegister(instr->GetRn());
7343 SimVRegister temp;
7344
7345 switch (form_hash_) {
7346 case "aesd_b_cryptoaes"_h:
7347 eor(kFormat16B, temp, rd, rn);
7348 aes(rd, temp, /* decrypt = */ true);
7349 break;
7350 case "aese_b_cryptoaes"_h:
7351 eor(kFormat16B, temp, rd, rn);
7352 aes(rd, temp, /* decrypt = */ false);
7353 break;
7354 case "aesimc_b_cryptoaes"_h:
7355 aesmix(rd, rn, /* inverse = */ true);
7356 break;
7357 case "aesmc_b_cryptoaes"_h:
7358 aesmix(rd, rn, /* inverse = */ false);
7359 break;
7360 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01007361}
7362
mmc28ab7ab6ec2024-07-24 11:06:17 +01007363void Simulator::VisitCryptoSM3(const Instruction* instr) {
7364 SimVRegister& rd = ReadVRegister(instr->GetRd());
7365 SimVRegister& rn = ReadVRegister(instr->GetRn());
7366 SimVRegister& rm = ReadVRegister(instr->GetRm());
7367 SimVRegister& ra = ReadVRegister(instr->GetRa());
7368 int index = instr->ExtractBits(13, 12);
7369
7370 bool is_a = false;
7371 switch (form_hash_) {
7372 case "sm3partw1_vvv4_cryptosha512_3"_h:
7373 sm3partw1(rd, rn, rm);
7374 break;
7375 case "sm3partw2_vvv4_cryptosha512_3"_h:
7376 sm3partw2(rd, rn, rm);
7377 break;
7378 case "sm3ss1_vvv4_crypto4"_h:
7379 sm3ss1(rd, rn, rm, ra);
7380 break;
7381 case "sm3tt1a_vvv4_crypto3_imm2"_h:
7382 is_a = true;
7383 VIXL_FALLTHROUGH();
7384 case "sm3tt1b_vvv4_crypto3_imm2"_h:
7385 sm3tt1(rd, rn, rm, index, is_a);
7386 break;
7387 case "sm3tt2a_vvv4_crypto3_imm2"_h:
7388 is_a = true;
7389 VIXL_FALLTHROUGH();
7390 case "sm3tt2b_vvv_crypto3_imm2"_h:
7391 sm3tt2(rd, rn, rm, index, is_a);
7392 break;
7393 }
7394}
7395
mmc28abdbc2252025-01-22 11:28:26 +00007396void Simulator::VisitCryptoSM4(const Instruction* instr) {
7397 SimVRegister& rd = ReadVRegister(instr->GetRd());
7398 SimVRegister& rn = ReadVRegister(instr->GetRn());
7399 SimVRegister& rm = ReadVRegister(instr->GetRm());
7400
7401 bool is_key = false;
7402 switch (form_hash_) {
7403 case "sm4ekey_vvv4_cryptosha512_3"_h:
7404 is_key = true;
7405 VIXL_FALLTHROUGH();
7406 case "sm4e_vv4_cryptosha512_2"_h:
7407 sm4(rd, rn, rm, is_key);
7408 break;
7409 }
7410}
7411
mmc28aa1856a32024-06-25 14:17:35 +01007412void Simulator::SimulateSHA512(const Instruction* instr) {
7413 SimVRegister& rd = ReadVRegister(instr->GetRd());
7414 SimVRegister& rn = ReadVRegister(instr->GetRn());
7415 SimVRegister& rm = ReadVRegister(instr->GetRm());
7416
7417 switch (form_hash_) {
7418 case "sha512h_qqv_cryptosha512_3"_h:
7419 sha512h(rd, rn, rm);
7420 break;
7421 case "sha512h2_qqv_cryptosha512_3"_h:
7422 sha512h2(rd, rn, rm);
7423 break;
7424 case "sha512su0_vv2_cryptosha512_2"_h:
7425 sha512su0(rd, rn);
7426 break;
7427 case "sha512su1_vvv2_cryptosha512_3"_h:
7428 sha512su1(rd, rn, rm);
7429 break;
7430 }
7431}
Alexandre Ramesd3832962016-07-04 15:03:43 +01007432
7433void Simulator::VisitNEON2RegMisc(const Instruction* instr) {
7434 NEONFormatDecoder nfd(instr);
7435 VectorFormat vf = nfd.GetVectorFormat();
7436
7437 static const NEONFormatMap map_lp =
7438 {{23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}};
7439 VectorFormat vf_lp = nfd.GetVectorFormat(&map_lp);
7440
7441 static const NEONFormatMap map_fcvtl = {{22}, {NF_4S, NF_2D}};
7442 VectorFormat vf_fcvtl = nfd.GetVectorFormat(&map_fcvtl);
7443
7444 static const NEONFormatMap map_fcvtn = {{22, 30},
7445 {NF_4H, NF_8H, NF_2S, NF_4S}};
7446 VectorFormat vf_fcvtn = nfd.GetVectorFormat(&map_fcvtn);
7447
7448 SimVRegister& rd = ReadVRegister(instr->GetRd());
7449 SimVRegister& rn = ReadVRegister(instr->GetRn());
7450
7451 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) {
7452 // These instructions all use a two bit size field, except NOT and RBIT,
7453 // which use the field to encode the operation.
7454 switch (instr->Mask(NEON2RegMiscMask)) {
7455 case NEON_REV64:
7456 rev64(vf, rd, rn);
7457 break;
7458 case NEON_REV32:
7459 rev32(vf, rd, rn);
7460 break;
7461 case NEON_REV16:
7462 rev16(vf, rd, rn);
7463 break;
7464 case NEON_SUQADD:
Martyn Capewell9b532192020-09-15 16:20:11 +01007465 suqadd(vf, rd, rd, rn);
Alexandre Ramesd3832962016-07-04 15:03:43 +01007466 break;
7467 case NEON_USQADD:
Martyn Capewell9b532192020-09-15 16:20:11 +01007468 usqadd(vf, rd, rd, rn);
Alexandre Ramesd3832962016-07-04 15:03:43 +01007469 break;
7470 case NEON_CLS:
7471 cls(vf, rd, rn);
7472 break;
7473 case NEON_CLZ:
7474 clz(vf, rd, rn);
7475 break;
7476 case NEON_CNT:
7477 cnt(vf, rd, rn);
7478 break;
7479 case NEON_SQABS:
7480 abs(vf, rd, rn).SignedSaturate(vf);
7481 break;
7482 case NEON_SQNEG:
7483 neg(vf, rd, rn).SignedSaturate(vf);
7484 break;
7485 case NEON_CMGT_zero:
7486 cmp(vf, rd, rn, 0, gt);
7487 break;
7488 case NEON_CMGE_zero:
7489 cmp(vf, rd, rn, 0, ge);
7490 break;
7491 case NEON_CMEQ_zero:
7492 cmp(vf, rd, rn, 0, eq);
7493 break;
7494 case NEON_CMLE_zero:
7495 cmp(vf, rd, rn, 0, le);
7496 break;
7497 case NEON_CMLT_zero:
7498 cmp(vf, rd, rn, 0, lt);
7499 break;
7500 case NEON_ABS:
7501 abs(vf, rd, rn);
7502 break;
7503 case NEON_NEG:
7504 neg(vf, rd, rn);
7505 break;
7506 case NEON_SADDLP:
7507 saddlp(vf_lp, rd, rn);
7508 break;
7509 case NEON_UADDLP:
7510 uaddlp(vf_lp, rd, rn);
7511 break;
7512 case NEON_SADALP:
7513 sadalp(vf_lp, rd, rn);
7514 break;
7515 case NEON_UADALP:
7516 uadalp(vf_lp, rd, rn);
7517 break;
7518 case NEON_RBIT_NOT:
7519 vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
7520 switch (instr->GetFPType()) {
7521 case 0:
7522 not_(vf, rd, rn);
7523 break;
7524 case 1:
7525 rbit(vf, rd, rn);
7526 break;
7527 default:
7528 VIXL_UNIMPLEMENTED();
7529 }
7530 break;
7531 }
7532 } else {
7533 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPFormatMap());
7534 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
7535 bool inexact_exception = false;
TatWai Chong04471812019-03-19 14:29:00 -07007536 FrintMode frint_mode = kFrintToInteger;
Alexandre Ramesd3832962016-07-04 15:03:43 +01007537
7538 // These instructions all use a one bit size field, except XTN, SQXTUN,
7539 // SHLL, SQXTN and UQXTN, which use a two bit size field.
7540 switch (instr->Mask(NEON2RegMiscFPMask)) {
7541 case NEON_FABS:
7542 fabs_(fpf, rd, rn);
7543 return;
7544 case NEON_FNEG:
7545 fneg(fpf, rd, rn);
7546 return;
7547 case NEON_FSQRT:
7548 fsqrt(fpf, rd, rn);
7549 return;
7550 case NEON_FCVTL:
7551 if (instr->Mask(NEON_Q)) {
7552 fcvtl2(vf_fcvtl, rd, rn);
7553 } else {
7554 fcvtl(vf_fcvtl, rd, rn);
7555 }
7556 return;
7557 case NEON_FCVTN:
7558 if (instr->Mask(NEON_Q)) {
7559 fcvtn2(vf_fcvtn, rd, rn);
7560 } else {
7561 fcvtn(vf_fcvtn, rd, rn);
7562 }
7563 return;
7564 case NEON_FCVTXN:
7565 if (instr->Mask(NEON_Q)) {
7566 fcvtxn2(vf_fcvtn, rd, rn);
7567 } else {
7568 fcvtxn(vf_fcvtn, rd, rn);
7569 }
7570 return;
7571
7572 // The following instructions break from the switch statement, rather
7573 // than return.
TatWai Chong04471812019-03-19 14:29:00 -07007574 case NEON_FRINT32X:
7575 inexact_exception = true;
7576 frint_mode = kFrintToInt32;
7577 break; // Use FPCR rounding mode.
7578 case NEON_FRINT32Z:
7579 inexact_exception = true;
7580 frint_mode = kFrintToInt32;
7581 fpcr_rounding = FPZero;
7582 break;
7583 case NEON_FRINT64X:
7584 inexact_exception = true;
7585 frint_mode = kFrintToInt64;
7586 break; // Use FPCR rounding mode.
7587 case NEON_FRINT64Z:
7588 inexact_exception = true;
7589 frint_mode = kFrintToInt64;
7590 fpcr_rounding = FPZero;
7591 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01007592 case NEON_FRINTI:
7593 break; // Use FPCR rounding mode.
7594 case NEON_FRINTX:
7595 inexact_exception = true;
7596 break;
7597 case NEON_FRINTA:
7598 fpcr_rounding = FPTieAway;
7599 break;
7600 case NEON_FRINTM:
7601 fpcr_rounding = FPNegativeInfinity;
7602 break;
7603 case NEON_FRINTN:
7604 fpcr_rounding = FPTieEven;
7605 break;
7606 case NEON_FRINTP:
7607 fpcr_rounding = FPPositiveInfinity;
7608 break;
7609 case NEON_FRINTZ:
7610 fpcr_rounding = FPZero;
7611 break;
7612
7613 case NEON_FCVTNS:
7614 fcvts(fpf, rd, rn, FPTieEven);
7615 return;
7616 case NEON_FCVTNU:
7617 fcvtu(fpf, rd, rn, FPTieEven);
7618 return;
7619 case NEON_FCVTPS:
7620 fcvts(fpf, rd, rn, FPPositiveInfinity);
7621 return;
7622 case NEON_FCVTPU:
7623 fcvtu(fpf, rd, rn, FPPositiveInfinity);
7624 return;
7625 case NEON_FCVTMS:
7626 fcvts(fpf, rd, rn, FPNegativeInfinity);
7627 return;
7628 case NEON_FCVTMU:
7629 fcvtu(fpf, rd, rn, FPNegativeInfinity);
7630 return;
7631 case NEON_FCVTZS:
7632 fcvts(fpf, rd, rn, FPZero);
7633 return;
7634 case NEON_FCVTZU:
7635 fcvtu(fpf, rd, rn, FPZero);
7636 return;
7637 case NEON_FCVTAS:
7638 fcvts(fpf, rd, rn, FPTieAway);
7639 return;
7640 case NEON_FCVTAU:
7641 fcvtu(fpf, rd, rn, FPTieAway);
7642 return;
7643 case NEON_SCVTF:
7644 scvtf(fpf, rd, rn, 0, fpcr_rounding);
7645 return;
7646 case NEON_UCVTF:
7647 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
7648 return;
7649 case NEON_URSQRTE:
7650 ursqrte(fpf, rd, rn);
7651 return;
7652 case NEON_URECPE:
7653 urecpe(fpf, rd, rn);
7654 return;
7655 case NEON_FRSQRTE:
7656 frsqrte(fpf, rd, rn);
7657 return;
7658 case NEON_FRECPE:
7659 frecpe(fpf, rd, rn, fpcr_rounding);
7660 return;
7661 case NEON_FCMGT_zero:
7662 fcmp_zero(fpf, rd, rn, gt);
7663 return;
7664 case NEON_FCMGE_zero:
7665 fcmp_zero(fpf, rd, rn, ge);
7666 return;
7667 case NEON_FCMEQ_zero:
7668 fcmp_zero(fpf, rd, rn, eq);
7669 return;
7670 case NEON_FCMLE_zero:
7671 fcmp_zero(fpf, rd, rn, le);
7672 return;
7673 case NEON_FCMLT_zero:
7674 fcmp_zero(fpf, rd, rn, lt);
7675 return;
7676 default:
7677 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) &&
7678 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) {
7679 switch (instr->Mask(NEON2RegMiscMask)) {
7680 case NEON_XTN:
7681 xtn(vf, rd, rn);
7682 return;
7683 case NEON_SQXTN:
7684 sqxtn(vf, rd, rn);
7685 return;
7686 case NEON_UQXTN:
7687 uqxtn(vf, rd, rn);
7688 return;
7689 case NEON_SQXTUN:
7690 sqxtun(vf, rd, rn);
7691 return;
7692 case NEON_SHLL:
7693 vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
7694 if (instr->Mask(NEON_Q)) {
7695 shll2(vf, rd, rn);
7696 } else {
7697 shll(vf, rd, rn);
7698 }
7699 return;
7700 default:
7701 VIXL_UNIMPLEMENTED();
7702 }
7703 } else {
7704 VIXL_UNIMPLEMENTED();
7705 }
7706 }
7707
7708 // Only FRINT* instructions fall through the switch above.
TatWai Chong04471812019-03-19 14:29:00 -07007709 frint(fpf, rd, rn, fpcr_rounding, inexact_exception, frint_mode);
Alexandre Ramesd3832962016-07-04 15:03:43 +01007710 }
7711}
7712
7713
Jacob Bramleyca789742018-09-13 14:25:46 +01007714void Simulator::VisitNEON2RegMiscFP16(const Instruction* instr) {
7715 static const NEONFormatMap map_half = {{30}, {NF_4H, NF_8H}};
7716 NEONFormatDecoder nfd(instr);
7717 VectorFormat fpf = nfd.GetVectorFormat(&map_half);
7718
7719 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
7720
7721 SimVRegister& rd = ReadVRegister(instr->GetRd());
7722 SimVRegister& rn = ReadVRegister(instr->GetRn());
7723
7724 switch (instr->Mask(NEON2RegMiscFP16Mask)) {
7725 case NEON_SCVTF_H:
7726 scvtf(fpf, rd, rn, 0, fpcr_rounding);
7727 return;
7728 case NEON_UCVTF_H:
7729 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
7730 return;
7731 case NEON_FCVTNS_H:
7732 fcvts(fpf, rd, rn, FPTieEven);
7733 return;
7734 case NEON_FCVTNU_H:
7735 fcvtu(fpf, rd, rn, FPTieEven);
7736 return;
7737 case NEON_FCVTPS_H:
7738 fcvts(fpf, rd, rn, FPPositiveInfinity);
7739 return;
7740 case NEON_FCVTPU_H:
7741 fcvtu(fpf, rd, rn, FPPositiveInfinity);
7742 return;
7743 case NEON_FCVTMS_H:
7744 fcvts(fpf, rd, rn, FPNegativeInfinity);
7745 return;
7746 case NEON_FCVTMU_H:
7747 fcvtu(fpf, rd, rn, FPNegativeInfinity);
7748 return;
7749 case NEON_FCVTZS_H:
7750 fcvts(fpf, rd, rn, FPZero);
7751 return;
7752 case NEON_FCVTZU_H:
7753 fcvtu(fpf, rd, rn, FPZero);
7754 return;
7755 case NEON_FCVTAS_H:
7756 fcvts(fpf, rd, rn, FPTieAway);
7757 return;
7758 case NEON_FCVTAU_H:
7759 fcvtu(fpf, rd, rn, FPTieAway);
7760 return;
7761 case NEON_FRINTI_H:
7762 frint(fpf, rd, rn, fpcr_rounding, false);
7763 return;
7764 case NEON_FRINTX_H:
7765 frint(fpf, rd, rn, fpcr_rounding, true);
7766 return;
7767 case NEON_FRINTA_H:
7768 frint(fpf, rd, rn, FPTieAway, false);
7769 return;
7770 case NEON_FRINTM_H:
7771 frint(fpf, rd, rn, FPNegativeInfinity, false);
7772 return;
7773 case NEON_FRINTN_H:
7774 frint(fpf, rd, rn, FPTieEven, false);
7775 return;
7776 case NEON_FRINTP_H:
7777 frint(fpf, rd, rn, FPPositiveInfinity, false);
7778 return;
7779 case NEON_FRINTZ_H:
7780 frint(fpf, rd, rn, FPZero, false);
7781 return;
7782 case NEON_FABS_H:
7783 fabs_(fpf, rd, rn);
7784 return;
7785 case NEON_FNEG_H:
7786 fneg(fpf, rd, rn);
7787 return;
7788 case NEON_FSQRT_H:
7789 fsqrt(fpf, rd, rn);
7790 return;
7791 case NEON_FRSQRTE_H:
7792 frsqrte(fpf, rd, rn);
7793 return;
7794 case NEON_FRECPE_H:
7795 frecpe(fpf, rd, rn, fpcr_rounding);
7796 return;
7797 case NEON_FCMGT_H_zero:
7798 fcmp_zero(fpf, rd, rn, gt);
7799 return;
7800 case NEON_FCMGE_H_zero:
7801 fcmp_zero(fpf, rd, rn, ge);
7802 return;
7803 case NEON_FCMEQ_H_zero:
7804 fcmp_zero(fpf, rd, rn, eq);
7805 return;
7806 case NEON_FCMLE_H_zero:
7807 fcmp_zero(fpf, rd, rn, le);
7808 return;
7809 case NEON_FCMLT_H_zero:
7810 fcmp_zero(fpf, rd, rn, lt);
7811 return;
7812 default:
7813 VIXL_UNIMPLEMENTED();
7814 return;
7815 }
7816}
7817
7818
Alexandre Ramesd3832962016-07-04 15:03:43 +01007819void Simulator::VisitNEON3Same(const Instruction* instr) {
7820 NEONFormatDecoder nfd(instr);
7821 SimVRegister& rd = ReadVRegister(instr->GetRd());
7822 SimVRegister& rn = ReadVRegister(instr->GetRn());
7823 SimVRegister& rm = ReadVRegister(instr->GetRm());
7824
7825 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) {
7826 VectorFormat vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
7827 switch (instr->Mask(NEON3SameLogicalMask)) {
7828 case NEON_AND:
7829 and_(vf, rd, rn, rm);
7830 break;
7831 case NEON_ORR:
7832 orr(vf, rd, rn, rm);
7833 break;
7834 case NEON_ORN:
7835 orn(vf, rd, rn, rm);
7836 break;
7837 case NEON_EOR:
7838 eor(vf, rd, rn, rm);
7839 break;
7840 case NEON_BIC:
7841 bic(vf, rd, rn, rm);
7842 break;
7843 case NEON_BIF:
7844 bif(vf, rd, rn, rm);
7845 break;
7846 case NEON_BIT:
7847 bit(vf, rd, rn, rm);
7848 break;
7849 case NEON_BSL:
Martyn Capewellb1b95782020-10-23 15:59:49 +01007850 bsl(vf, rd, rd, rn, rm);
Alexandre Ramesd3832962016-07-04 15:03:43 +01007851 break;
7852 default:
7853 VIXL_UNIMPLEMENTED();
7854 }
7855 } else if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
7856 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
7857 switch (instr->Mask(NEON3SameFPMask)) {
7858 case NEON_FADD:
7859 fadd(vf, rd, rn, rm);
7860 break;
7861 case NEON_FSUB:
7862 fsub(vf, rd, rn, rm);
7863 break;
7864 case NEON_FMUL:
7865 fmul(vf, rd, rn, rm);
7866 break;
7867 case NEON_FDIV:
7868 fdiv(vf, rd, rn, rm);
7869 break;
7870 case NEON_FMAX:
7871 fmax(vf, rd, rn, rm);
7872 break;
7873 case NEON_FMIN:
7874 fmin(vf, rd, rn, rm);
7875 break;
7876 case NEON_FMAXNM:
7877 fmaxnm(vf, rd, rn, rm);
7878 break;
7879 case NEON_FMINNM:
7880 fminnm(vf, rd, rn, rm);
7881 break;
7882 case NEON_FMLA:
TatWai Chongf8d29f12020-02-16 22:53:18 -08007883 fmla(vf, rd, rd, rn, rm);
Alexandre Ramesd3832962016-07-04 15:03:43 +01007884 break;
7885 case NEON_FMLS:
TatWai Chongf8d29f12020-02-16 22:53:18 -08007886 fmls(vf, rd, rd, rn, rm);
Alexandre Ramesd3832962016-07-04 15:03:43 +01007887 break;
7888 case NEON_FMULX:
7889 fmulx(vf, rd, rn, rm);
7890 break;
7891 case NEON_FACGE:
7892 fabscmp(vf, rd, rn, rm, ge);
7893 break;
7894 case NEON_FACGT:
7895 fabscmp(vf, rd, rn, rm, gt);
7896 break;
7897 case NEON_FCMEQ:
7898 fcmp(vf, rd, rn, rm, eq);
7899 break;
7900 case NEON_FCMGE:
7901 fcmp(vf, rd, rn, rm, ge);
7902 break;
7903 case NEON_FCMGT:
7904 fcmp(vf, rd, rn, rm, gt);
7905 break;
7906 case NEON_FRECPS:
7907 frecps(vf, rd, rn, rm);
7908 break;
7909 case NEON_FRSQRTS:
7910 frsqrts(vf, rd, rn, rm);
7911 break;
7912 case NEON_FABD:
7913 fabd(vf, rd, rn, rm);
7914 break;
7915 case NEON_FADDP:
7916 faddp(vf, rd, rn, rm);
7917 break;
7918 case NEON_FMAXP:
7919 fmaxp(vf, rd, rn, rm);
7920 break;
7921 case NEON_FMAXNMP:
7922 fmaxnmp(vf, rd, rn, rm);
7923 break;
7924 case NEON_FMINP:
7925 fminp(vf, rd, rn, rm);
7926 break;
7927 case NEON_FMINNMP:
7928 fminnmp(vf, rd, rn, rm);
7929 break;
7930 default:
Jacob Bramley8f36e7f2018-08-23 17:45:37 +01007931 // FMLAL{2} and FMLSL{2} have special-case encodings.
7932 switch (instr->Mask(NEON3SameFHMMask)) {
7933 case NEON_FMLAL:
7934 fmlal(vf, rd, rn, rm);
7935 break;
7936 case NEON_FMLAL2:
7937 fmlal2(vf, rd, rn, rm);
7938 break;
7939 case NEON_FMLSL:
7940 fmlsl(vf, rd, rn, rm);
7941 break;
7942 case NEON_FMLSL2:
7943 fmlsl2(vf, rd, rn, rm);
7944 break;
7945 default:
7946 VIXL_UNIMPLEMENTED();
7947 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01007948 }
7949 } else {
7950 VectorFormat vf = nfd.GetVectorFormat();
7951 switch (instr->Mask(NEON3SameMask)) {
7952 case NEON_ADD:
7953 add(vf, rd, rn, rm);
7954 break;
7955 case NEON_ADDP:
7956 addp(vf, rd, rn, rm);
7957 break;
7958 case NEON_CMEQ:
7959 cmp(vf, rd, rn, rm, eq);
7960 break;
7961 case NEON_CMGE:
7962 cmp(vf, rd, rn, rm, ge);
7963 break;
7964 case NEON_CMGT:
7965 cmp(vf, rd, rn, rm, gt);
7966 break;
7967 case NEON_CMHI:
7968 cmp(vf, rd, rn, rm, hi);
7969 break;
7970 case NEON_CMHS:
7971 cmp(vf, rd, rn, rm, hs);
7972 break;
7973 case NEON_CMTST:
7974 cmptst(vf, rd, rn, rm);
7975 break;
7976 case NEON_MLS:
Jacob Bramley22023df2019-05-14 17:55:43 +01007977 mls(vf, rd, rd, rn, rm);
Alexandre Ramesd3832962016-07-04 15:03:43 +01007978 break;
7979 case NEON_MLA:
Jacob Bramley22023df2019-05-14 17:55:43 +01007980 mla(vf, rd, rd, rn, rm);
Alexandre Ramesd3832962016-07-04 15:03:43 +01007981 break;
7982 case NEON_MUL:
7983 mul(vf, rd, rn, rm);
7984 break;
7985 case NEON_PMUL:
7986 pmul(vf, rd, rn, rm);
7987 break;
7988 case NEON_SMAX:
7989 smax(vf, rd, rn, rm);
7990 break;
7991 case NEON_SMAXP:
7992 smaxp(vf, rd, rn, rm);
7993 break;
7994 case NEON_SMIN:
7995 smin(vf, rd, rn, rm);
7996 break;
7997 case NEON_SMINP:
7998 sminp(vf, rd, rn, rm);
7999 break;
8000 case NEON_SUB:
8001 sub(vf, rd, rn, rm);
8002 break;
8003 case NEON_UMAX:
8004 umax(vf, rd, rn, rm);
8005 break;
8006 case NEON_UMAXP:
8007 umaxp(vf, rd, rn, rm);
8008 break;
8009 case NEON_UMIN:
8010 umin(vf, rd, rn, rm);
8011 break;
8012 case NEON_UMINP:
8013 uminp(vf, rd, rn, rm);
8014 break;
8015 case NEON_SSHL:
8016 sshl(vf, rd, rn, rm);
8017 break;
8018 case NEON_USHL:
8019 ushl(vf, rd, rn, rm);
8020 break;
8021 case NEON_SABD:
8022 absdiff(vf, rd, rn, rm, true);
8023 break;
8024 case NEON_UABD:
8025 absdiff(vf, rd, rn, rm, false);
8026 break;
8027 case NEON_SABA:
8028 saba(vf, rd, rn, rm);
8029 break;
8030 case NEON_UABA:
8031 uaba(vf, rd, rn, rm);
8032 break;
8033 case NEON_UQADD:
8034 add(vf, rd, rn, rm).UnsignedSaturate(vf);
8035 break;
8036 case NEON_SQADD:
8037 add(vf, rd, rn, rm).SignedSaturate(vf);
8038 break;
8039 case NEON_UQSUB:
8040 sub(vf, rd, rn, rm).UnsignedSaturate(vf);
8041 break;
8042 case NEON_SQSUB:
8043 sub(vf, rd, rn, rm).SignedSaturate(vf);
8044 break;
8045 case NEON_SQDMULH:
8046 sqdmulh(vf, rd, rn, rm);
8047 break;
8048 case NEON_SQRDMULH:
8049 sqrdmulh(vf, rd, rn, rm);
8050 break;
8051 case NEON_UQSHL:
8052 ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
8053 break;
8054 case NEON_SQSHL:
8055 sshl(vf, rd, rn, rm).SignedSaturate(vf);
8056 break;
8057 case NEON_URSHL:
8058 ushl(vf, rd, rn, rm).Round(vf);
8059 break;
8060 case NEON_SRSHL:
8061 sshl(vf, rd, rn, rm).Round(vf);
8062 break;
8063 case NEON_UQRSHL:
8064 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
8065 break;
8066 case NEON_SQRSHL:
8067 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
8068 break;
8069 case NEON_UHADD:
8070 add(vf, rd, rn, rm).Uhalve(vf);
8071 break;
8072 case NEON_URHADD:
8073 add(vf, rd, rn, rm).Uhalve(vf).Round(vf);
8074 break;
8075 case NEON_SHADD:
8076 add(vf, rd, rn, rm).Halve(vf);
8077 break;
8078 case NEON_SRHADD:
8079 add(vf, rd, rn, rm).Halve(vf).Round(vf);
8080 break;
8081 case NEON_UHSUB:
8082 sub(vf, rd, rn, rm).Uhalve(vf);
8083 break;
8084 case NEON_SHSUB:
8085 sub(vf, rd, rn, rm).Halve(vf);
8086 break;
8087 default:
8088 VIXL_UNIMPLEMENTED();
8089 }
8090 }
8091}
8092
8093
Jacob Bramleyca789742018-09-13 14:25:46 +01008094void Simulator::VisitNEON3SameFP16(const Instruction* instr) {
8095 NEONFormatDecoder nfd(instr);
8096 SimVRegister& rd = ReadVRegister(instr->GetRd());
8097 SimVRegister& rn = ReadVRegister(instr->GetRn());
8098 SimVRegister& rm = ReadVRegister(instr->GetRm());
8099
8100 VectorFormat vf = nfd.GetVectorFormat(nfd.FP16FormatMap());
8101 switch (instr->Mask(NEON3SameFP16Mask)) {
8102#define SIM_FUNC(A, B) \
8103 case NEON_##A##_H: \
8104 B(vf, rd, rn, rm); \
8105 break;
8106 SIM_FUNC(FMAXNM, fmaxnm);
Jacob Bramleyca789742018-09-13 14:25:46 +01008107 SIM_FUNC(FADD, fadd);
8108 SIM_FUNC(FMULX, fmulx);
8109 SIM_FUNC(FMAX, fmax);
8110 SIM_FUNC(FRECPS, frecps);
8111 SIM_FUNC(FMINNM, fminnm);
Jacob Bramleyca789742018-09-13 14:25:46 +01008112 SIM_FUNC(FSUB, fsub);
8113 SIM_FUNC(FMIN, fmin);
8114 SIM_FUNC(FRSQRTS, frsqrts);
8115 SIM_FUNC(FMAXNMP, fmaxnmp);
8116 SIM_FUNC(FADDP, faddp);
8117 SIM_FUNC(FMUL, fmul);
8118 SIM_FUNC(FMAXP, fmaxp);
8119 SIM_FUNC(FDIV, fdiv);
8120 SIM_FUNC(FMINNMP, fminnmp);
8121 SIM_FUNC(FABD, fabd);
8122 SIM_FUNC(FMINP, fminp);
8123#undef SIM_FUNC
TatWai Chongf8d29f12020-02-16 22:53:18 -08008124 case NEON_FMLA_H:
8125 fmla(vf, rd, rd, rn, rm);
8126 break;
8127 case NEON_FMLS_H:
8128 fmls(vf, rd, rd, rn, rm);
8129 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01008130 case NEON_FCMEQ_H:
8131 fcmp(vf, rd, rn, rm, eq);
8132 break;
8133 case NEON_FCMGE_H:
8134 fcmp(vf, rd, rn, rm, ge);
8135 break;
8136 case NEON_FACGE_H:
8137 fabscmp(vf, rd, rn, rm, ge);
8138 break;
8139 case NEON_FCMGT_H:
8140 fcmp(vf, rd, rn, rm, gt);
8141 break;
8142 case NEON_FACGT_H:
8143 fabscmp(vf, rd, rn, rm, gt);
8144 break;
8145 default:
8146 VIXL_UNIMPLEMENTED();
8147 break;
8148 }
8149}
8150
Carey Williams2809e6c2018-03-13 12:24:16 +00008151void Simulator::VisitNEON3SameExtra(const Instruction* instr) {
8152 NEONFormatDecoder nfd(instr);
8153 SimVRegister& rd = ReadVRegister(instr->GetRd());
8154 SimVRegister& rn = ReadVRegister(instr->GetRn());
8155 SimVRegister& rm = ReadVRegister(instr->GetRm());
8156 int rot = 0;
8157 VectorFormat vf = nfd.GetVectorFormat();
Martyn Capewell09925d42021-08-31 11:17:16 +01008158
8159 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01008160 case "fcmla_asimdsame2_c"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008161 rot = instr->GetImmRotFcmlaVec();
8162 fcmla(vf, rd, rn, rm, rd, rot);
8163 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008164 case "fcadd_asimdsame2_c"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008165 rot = instr->GetImmRotFcadd();
8166 fcadd(vf, rd, rn, rm, rot);
8167 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008168 case "sdot_asimdsame2_d"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008169 sdot(vf, rd, rn, rm);
8170 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008171 case "udot_asimdsame2_d"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008172 udot(vf, rd, rn, rm);
8173 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008174 case "usdot_asimdsame2_d"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008175 usdot(vf, rd, rn, rm);
8176 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008177 case "sqrdmlah_asimdsame2_only"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008178 sqrdmlah(vf, rd, rn, rm);
8179 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008180 case "sqrdmlsh_asimdsame2_only"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008181 sqrdmlsh(vf, rd, rn, rm);
8182 break;
Carey Williams2809e6c2018-03-13 12:24:16 +00008183 }
8184}
8185
8186
Alexandre Ramesd3832962016-07-04 15:03:43 +01008187void Simulator::VisitNEON3Different(const Instruction* instr) {
8188 NEONFormatDecoder nfd(instr);
8189 VectorFormat vf = nfd.GetVectorFormat();
8190 VectorFormat vf_l = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
8191
8192 SimVRegister& rd = ReadVRegister(instr->GetRd());
8193 SimVRegister& rn = ReadVRegister(instr->GetRn());
8194 SimVRegister& rm = ReadVRegister(instr->GetRm());
mmc28a5a2144d2024-02-23 17:23:23 +00008195 int size = instr->GetNEONSize();
Alexandre Ramesd3832962016-07-04 15:03:43 +01008196
8197 switch (instr->Mask(NEON3DifferentMask)) {
8198 case NEON_PMULL:
mmc28a5a2144d2024-02-23 17:23:23 +00008199 if ((size == 1) || (size == 2)) { // S/D reserved.
8200 VisitUnallocated(instr);
8201 } else {
8202 if (size == 3) vf_l = kFormat1Q;
8203 pmull(vf_l, rd, rn, rm);
8204 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01008205 break;
8206 case NEON_PMULL2:
mmc28a5a2144d2024-02-23 17:23:23 +00008207 if ((size == 1) || (size == 2)) { // S/D reserved.
8208 VisitUnallocated(instr);
8209 } else {
8210 if (size == 3) vf_l = kFormat1Q;
8211 pmull2(vf_l, rd, rn, rm);
8212 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01008213 break;
8214 case NEON_UADDL:
8215 uaddl(vf_l, rd, rn, rm);
8216 break;
8217 case NEON_UADDL2:
8218 uaddl2(vf_l, rd, rn, rm);
8219 break;
8220 case NEON_SADDL:
8221 saddl(vf_l, rd, rn, rm);
8222 break;
8223 case NEON_SADDL2:
8224 saddl2(vf_l, rd, rn, rm);
8225 break;
8226 case NEON_USUBL:
8227 usubl(vf_l, rd, rn, rm);
8228 break;
8229 case NEON_USUBL2:
8230 usubl2(vf_l, rd, rn, rm);
8231 break;
8232 case NEON_SSUBL:
8233 ssubl(vf_l, rd, rn, rm);
8234 break;
8235 case NEON_SSUBL2:
8236 ssubl2(vf_l, rd, rn, rm);
8237 break;
8238 case NEON_SABAL:
8239 sabal(vf_l, rd, rn, rm);
8240 break;
8241 case NEON_SABAL2:
8242 sabal2(vf_l, rd, rn, rm);
8243 break;
8244 case NEON_UABAL:
8245 uabal(vf_l, rd, rn, rm);
8246 break;
8247 case NEON_UABAL2:
8248 uabal2(vf_l, rd, rn, rm);
8249 break;
8250 case NEON_SABDL:
8251 sabdl(vf_l, rd, rn, rm);
8252 break;
8253 case NEON_SABDL2:
8254 sabdl2(vf_l, rd, rn, rm);
8255 break;
8256 case NEON_UABDL:
8257 uabdl(vf_l, rd, rn, rm);
8258 break;
8259 case NEON_UABDL2:
8260 uabdl2(vf_l, rd, rn, rm);
8261 break;
8262 case NEON_SMLAL:
8263 smlal(vf_l, rd, rn, rm);
8264 break;
8265 case NEON_SMLAL2:
8266 smlal2(vf_l, rd, rn, rm);
8267 break;
8268 case NEON_UMLAL:
8269 umlal(vf_l, rd, rn, rm);
8270 break;
8271 case NEON_UMLAL2:
8272 umlal2(vf_l, rd, rn, rm);
8273 break;
8274 case NEON_SMLSL:
8275 smlsl(vf_l, rd, rn, rm);
8276 break;
8277 case NEON_SMLSL2:
8278 smlsl2(vf_l, rd, rn, rm);
8279 break;
8280 case NEON_UMLSL:
8281 umlsl(vf_l, rd, rn, rm);
8282 break;
8283 case NEON_UMLSL2:
8284 umlsl2(vf_l, rd, rn, rm);
8285 break;
8286 case NEON_SMULL:
8287 smull(vf_l, rd, rn, rm);
8288 break;
8289 case NEON_SMULL2:
8290 smull2(vf_l, rd, rn, rm);
8291 break;
8292 case NEON_UMULL:
8293 umull(vf_l, rd, rn, rm);
8294 break;
8295 case NEON_UMULL2:
8296 umull2(vf_l, rd, rn, rm);
8297 break;
8298 case NEON_SQDMLAL:
8299 sqdmlal(vf_l, rd, rn, rm);
8300 break;
8301 case NEON_SQDMLAL2:
8302 sqdmlal2(vf_l, rd, rn, rm);
8303 break;
8304 case NEON_SQDMLSL:
8305 sqdmlsl(vf_l, rd, rn, rm);
8306 break;
8307 case NEON_SQDMLSL2:
8308 sqdmlsl2(vf_l, rd, rn, rm);
8309 break;
8310 case NEON_SQDMULL:
8311 sqdmull(vf_l, rd, rn, rm);
8312 break;
8313 case NEON_SQDMULL2:
8314 sqdmull2(vf_l, rd, rn, rm);
8315 break;
8316 case NEON_UADDW:
8317 uaddw(vf_l, rd, rn, rm);
8318 break;
8319 case NEON_UADDW2:
8320 uaddw2(vf_l, rd, rn, rm);
8321 break;
8322 case NEON_SADDW:
8323 saddw(vf_l, rd, rn, rm);
8324 break;
8325 case NEON_SADDW2:
8326 saddw2(vf_l, rd, rn, rm);
8327 break;
8328 case NEON_USUBW:
8329 usubw(vf_l, rd, rn, rm);
8330 break;
8331 case NEON_USUBW2:
8332 usubw2(vf_l, rd, rn, rm);
8333 break;
8334 case NEON_SSUBW:
8335 ssubw(vf_l, rd, rn, rm);
8336 break;
8337 case NEON_SSUBW2:
8338 ssubw2(vf_l, rd, rn, rm);
8339 break;
8340 case NEON_ADDHN:
8341 addhn(vf, rd, rn, rm);
8342 break;
8343 case NEON_ADDHN2:
8344 addhn2(vf, rd, rn, rm);
8345 break;
8346 case NEON_RADDHN:
8347 raddhn(vf, rd, rn, rm);
8348 break;
8349 case NEON_RADDHN2:
8350 raddhn2(vf, rd, rn, rm);
8351 break;
8352 case NEON_SUBHN:
8353 subhn(vf, rd, rn, rm);
8354 break;
8355 case NEON_SUBHN2:
8356 subhn2(vf, rd, rn, rm);
8357 break;
8358 case NEON_RSUBHN:
8359 rsubhn(vf, rd, rn, rm);
8360 break;
8361 case NEON_RSUBHN2:
8362 rsubhn2(vf, rd, rn, rm);
8363 break;
8364 default:
8365 VIXL_UNIMPLEMENTED();
8366 }
8367}
8368
8369
8370void Simulator::VisitNEONAcrossLanes(const Instruction* instr) {
8371 NEONFormatDecoder nfd(instr);
8372
Jacob Bramleyca789742018-09-13 14:25:46 +01008373 static const NEONFormatMap map_half = {{30}, {NF_4H, NF_8H}};
8374
Alexandre Ramesd3832962016-07-04 15:03:43 +01008375 SimVRegister& rd = ReadVRegister(instr->GetRd());
8376 SimVRegister& rn = ReadVRegister(instr->GetRn());
8377
Jacob Bramleyca789742018-09-13 14:25:46 +01008378 if (instr->Mask(NEONAcrossLanesFP16FMask) == NEONAcrossLanesFP16Fixed) {
8379 VectorFormat vf = nfd.GetVectorFormat(&map_half);
8380 switch (instr->Mask(NEONAcrossLanesFP16Mask)) {
8381 case NEON_FMAXV_H:
8382 fmaxv(vf, rd, rn);
8383 break;
8384 case NEON_FMINV_H:
8385 fminv(vf, rd, rn);
8386 break;
8387 case NEON_FMAXNMV_H:
8388 fmaxnmv(vf, rd, rn);
8389 break;
8390 case NEON_FMINNMV_H:
8391 fminnmv(vf, rd, rn);
8392 break;
8393 default:
8394 VIXL_UNIMPLEMENTED();
8395 }
8396 } else if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
8397 // The input operand's VectorFormat is passed for these instructions.
Alexandre Ramesd3832962016-07-04 15:03:43 +01008398 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
8399
8400 switch (instr->Mask(NEONAcrossLanesFPMask)) {
8401 case NEON_FMAXV:
8402 fmaxv(vf, rd, rn);
8403 break;
8404 case NEON_FMINV:
8405 fminv(vf, rd, rn);
8406 break;
8407 case NEON_FMAXNMV:
8408 fmaxnmv(vf, rd, rn);
8409 break;
8410 case NEON_FMINNMV:
8411 fminnmv(vf, rd, rn);
8412 break;
8413 default:
8414 VIXL_UNIMPLEMENTED();
8415 }
8416 } else {
8417 VectorFormat vf = nfd.GetVectorFormat();
8418
8419 switch (instr->Mask(NEONAcrossLanesMask)) {
8420 case NEON_ADDV:
8421 addv(vf, rd, rn);
8422 break;
8423 case NEON_SMAXV:
8424 smaxv(vf, rd, rn);
8425 break;
8426 case NEON_SMINV:
8427 sminv(vf, rd, rn);
8428 break;
8429 case NEON_UMAXV:
8430 umaxv(vf, rd, rn);
8431 break;
8432 case NEON_UMINV:
8433 uminv(vf, rd, rn);
8434 break;
8435 case NEON_SADDLV:
8436 saddlv(vf, rd, rn);
8437 break;
8438 case NEON_UADDLV:
8439 uaddlv(vf, rd, rn);
8440 break;
8441 default:
8442 VIXL_UNIMPLEMENTED();
8443 }
8444 }
8445}
8446
Martyn Capewell876aace2021-09-02 13:55:48 +01008447void Simulator::SimulateNEONMulByElementLong(const Instruction* instr) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01008448 NEONFormatDecoder nfd(instr);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008449 VectorFormat vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
Alexandre Ramesd3832962016-07-04 15:03:43 +01008450 SimVRegister& rd = ReadVRegister(instr->GetRd());
8451 SimVRegister& rn = ReadVRegister(instr->GetRn());
8452
mmc28ad17400f2025-01-17 10:47:22 +00008453 std::pair<int, int> rm_and_index = instr->GetNEONMulRmAndIndex();
Martyn Capewell876aace2021-09-02 13:55:48 +01008454 SimVRegister temp;
8455 VectorFormat indexform =
8456 VectorFormatHalfWidthDoubleLanes(VectorFormatFillQ(vf));
mmc28ad17400f2025-01-17 10:47:22 +00008457 dup_elements_to_segments(indexform, temp, rm_and_index);
Martyn Capewell876aace2021-09-02 13:55:48 +01008458
8459 bool is_2 = instr->Mask(NEON_Q) ? true : false;
8460
8461 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01008462 case "smull_asimdelem_l"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008463 smull(vf, rd, rn, temp, is_2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008464 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008465 case "umull_asimdelem_l"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008466 umull(vf, rd, rn, temp, is_2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008467 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008468 case "smlal_asimdelem_l"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008469 smlal(vf, rd, rn, temp, is_2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008470 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008471 case "umlal_asimdelem_l"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008472 umlal(vf, rd, rn, temp, is_2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008473 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008474 case "smlsl_asimdelem_l"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008475 smlsl(vf, rd, rn, temp, is_2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008476 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008477 case "umlsl_asimdelem_l"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008478 umlsl(vf, rd, rn, temp, is_2);
Alexander Gilday560332d2018-04-05 13:25:17 +01008479 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008480 case "sqdmull_asimdelem_l"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008481 sqdmull(vf, rd, rn, temp, is_2);
Alexander Gilday43785642018-04-04 13:42:33 +01008482 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008483 case "sqdmlal_asimdelem_l"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008484 sqdmlal(vf, rd, rn, temp, is_2);
Alexander Gilday560332d2018-04-05 13:25:17 +01008485 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008486 case "sqdmlsl_asimdelem_l"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008487 sqdmlsl(vf, rd, rn, temp, is_2);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008488 break;
8489 default:
Martyn Capewell876aace2021-09-02 13:55:48 +01008490 VIXL_UNREACHABLE();
8491 }
8492}
Alexandre Ramesd3832962016-07-04 15:03:43 +01008493
Martyn Capewell876aace2021-09-02 13:55:48 +01008494void Simulator::SimulateNEONFPMulByElementLong(const Instruction* instr) {
8495 VectorFormat vform = instr->GetNEONQ() ? kFormat4S : kFormat2S;
8496 SimVRegister& rd = ReadVRegister(instr->GetRd());
8497 SimVRegister& rn = ReadVRegister(instr->GetRn());
8498 SimVRegister& rm = ReadVRegister(instr->GetRmLow16());
Alexandre Ramesd3832962016-07-04 15:03:43 +01008499
Martyn Capewell876aace2021-09-02 13:55:48 +01008500 int index =
8501 (instr->GetNEONH() << 2) | (instr->GetNEONL() << 1) | instr->GetNEONM();
8502
8503 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01008504 case "fmlal_asimdelem_lh"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008505 fmlal(vform, rd, rn, rm, index);
8506 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008507 case "fmlal2_asimdelem_lh"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008508 fmlal2(vform, rd, rn, rm, index);
8509 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008510 case "fmlsl_asimdelem_lh"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008511 fmlsl(vform, rd, rn, rm, index);
8512 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008513 case "fmlsl2_asimdelem_lh"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008514 fmlsl2(vform, rd, rn, rm, index);
8515 break;
8516 default:
8517 VIXL_UNREACHABLE();
8518 }
8519}
8520
8521void Simulator::SimulateNEONFPMulByElement(const Instruction* instr) {
8522 NEONFormatDecoder nfd(instr);
8523 static const NEONFormatMap map =
8524 {{23, 22, 30},
8525 {NF_4H, NF_8H, NF_UNDEF, NF_UNDEF, NF_2S, NF_4S, NF_UNDEF, NF_2D}};
8526 VectorFormat vform = nfd.GetVectorFormat(&map);
8527
8528 SimVRegister& rd = ReadVRegister(instr->GetRd());
8529 SimVRegister& rn = ReadVRegister(instr->GetRn());
8530
mmc28ad17400f2025-01-17 10:47:22 +00008531 std::pair<int, int> rm_and_index = instr->GetNEONMulRmAndIndex();
8532 SimVRegister& rm = ReadVRegister(rm_and_index.first);
8533 int index = rm_and_index.second;
Martyn Capewell876aace2021-09-02 13:55:48 +01008534
8535 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01008536 case "fmul_asimdelem_rh_h"_h:
8537 case "fmul_asimdelem_r_sd"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008538 fmul(vform, rd, rn, rm, index);
8539 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008540 case "fmla_asimdelem_rh_h"_h:
8541 case "fmla_asimdelem_r_sd"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008542 fmla(vform, rd, rn, rm, index);
8543 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008544 case "fmls_asimdelem_rh_h"_h:
8545 case "fmls_asimdelem_r_sd"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008546 fmls(vform, rd, rn, rm, index);
8547 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008548 case "fmulx_asimdelem_rh_h"_h:
8549 case "fmulx_asimdelem_r_sd"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008550 fmulx(vform, rd, rn, rm, index);
8551 break;
8552 default:
8553 VIXL_UNREACHABLE();
8554 }
8555}
8556
8557void Simulator::SimulateNEONComplexMulByElement(const Instruction* instr) {
8558 VectorFormat vform = instr->GetNEONQ() ? kFormat8H : kFormat4H;
8559 SimVRegister& rd = ReadVRegister(instr->GetRd());
8560 SimVRegister& rn = ReadVRegister(instr->GetRn());
8561 SimVRegister& rm = ReadVRegister(instr->GetRm());
8562 int index = (instr->GetNEONH() << 1) | instr->GetNEONL();
8563
8564 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01008565 case "fcmla_asimdelem_c_s"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008566 vform = kFormat4S;
8567 index >>= 1;
8568 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +01008569 case "fcmla_asimdelem_c_h"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008570 fcmla(vform, rd, rn, rm, index, instr->GetImmRotFcmlaSca());
8571 break;
8572 default:
8573 VIXL_UNREACHABLE();
8574 }
8575}
8576
Martyn Capewell09925d42021-08-31 11:17:16 +01008577void Simulator::SimulateNEONDotProdByElement(const Instruction* instr) {
8578 VectorFormat vform = instr->GetNEONQ() ? kFormat4S : kFormat2S;
8579
8580 SimVRegister& rd = ReadVRegister(instr->GetRd());
8581 SimVRegister& rn = ReadVRegister(instr->GetRn());
8582 SimVRegister& rm = ReadVRegister(instr->GetRm());
8583 int index = (instr->GetNEONH() << 1) | instr->GetNEONL();
8584
8585 SimVRegister temp;
8586 // NEON indexed `dot` allows the index value exceed the register size.
8587 // Promote the format to Q-sized vector format before the duplication.
8588 dup_elements_to_segments(VectorFormatFillQ(vform), temp, rm, index);
8589
8590 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01008591 case "sdot_asimdelem_d"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008592 sdot(vform, rd, rn, temp);
8593 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008594 case "udot_asimdelem_d"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008595 udot(vform, rd, rn, temp);
8596 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008597 case "sudot_asimdelem_d"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008598 usdot(vform, rd, temp, rn);
8599 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008600 case "usdot_asimdelem_d"_h:
Martyn Capewell09925d42021-08-31 11:17:16 +01008601 usdot(vform, rd, rn, temp);
8602 break;
8603 }
8604}
8605
Martyn Capewell876aace2021-09-02 13:55:48 +01008606void Simulator::VisitNEONByIndexedElement(const Instruction* instr) {
8607 NEONFormatDecoder nfd(instr);
8608 VectorFormat vform = nfd.GetVectorFormat();
8609
8610 SimVRegister& rd = ReadVRegister(instr->GetRd());
8611 SimVRegister& rn = ReadVRegister(instr->GetRn());
8612
mmc28ad17400f2025-01-17 10:47:22 +00008613 std::pair<int, int> rm_and_index = instr->GetNEONMulRmAndIndex();
8614 SimVRegister& rm = ReadVRegister(rm_and_index.first);
8615 int index = rm_and_index.second;
Martyn Capewell876aace2021-09-02 13:55:48 +01008616
8617 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +01008618 case "mul_asimdelem_r"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008619 mul(vform, rd, rn, rm, index);
8620 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008621 case "mla_asimdelem_r"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008622 mla(vform, rd, rn, rm, index);
8623 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008624 case "mls_asimdelem_r"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008625 mls(vform, rd, rn, rm, index);
8626 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008627 case "sqdmulh_asimdelem_r"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008628 sqdmulh(vform, rd, rn, rm, index);
8629 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008630 case "sqrdmulh_asimdelem_r"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008631 sqrdmulh(vform, rd, rn, rm, index);
8632 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008633 case "sqrdmlah_asimdelem_r"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008634 sqrdmlah(vform, rd, rn, rm, index);
8635 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +01008636 case "sqrdmlsh_asimdelem_r"_h:
Martyn Capewell876aace2021-09-02 13:55:48 +01008637 sqrdmlsh(vform, rd, rn, rm, index);
8638 break;
8639 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01008640}
8641
8642
8643void Simulator::VisitNEONCopy(const Instruction* instr) {
8644 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap());
8645 VectorFormat vf = nfd.GetVectorFormat();
8646
8647 SimVRegister& rd = ReadVRegister(instr->GetRd());
8648 SimVRegister& rn = ReadVRegister(instr->GetRn());
8649 int imm5 = instr->GetImmNEON5();
8650 int tz = CountTrailingZeros(imm5, 32);
Martyn Capewelled5e03d2021-06-24 16:44:24 +01008651 int reg_index = ExtractSignedBitfield32(31, tz + 1, imm5);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008652
8653 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) {
8654 int imm4 = instr->GetImmNEON4();
Martyn Capewelled5e03d2021-06-24 16:44:24 +01008655 int rn_index = ExtractSignedBitfield32(31, tz, imm4);
mmc28a2cdba9e2024-05-16 15:27:20 +01008656 mov(kFormat16B, rd, rd); // Zero bits beyond the MSB of a Q register.
Alexandre Ramesd3832962016-07-04 15:03:43 +01008657 ins_element(vf, rd, reg_index, rn, rn_index);
8658 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) {
mmc28a2cdba9e2024-05-16 15:27:20 +01008659 mov(kFormat16B, rd, rd); // Zero bits beyond the MSB of a Q register.
Alexandre Ramesd3832962016-07-04 15:03:43 +01008660 ins_immediate(vf, rd, reg_index, ReadXRegister(instr->GetRn()));
8661 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) {
8662 uint64_t value = LogicVRegister(rn).Uint(vf, reg_index);
8663 value &= MaxUintFromFormat(vf);
8664 WriteXRegister(instr->GetRd(), value);
8665 } else if (instr->Mask(NEONCopyUmovMask) == NEON_SMOV) {
8666 int64_t value = LogicVRegister(rn).Int(vf, reg_index);
8667 if (instr->GetNEONQ()) {
8668 WriteXRegister(instr->GetRd(), value);
8669 } else {
8670 WriteWRegister(instr->GetRd(), (int32_t)value);
8671 }
8672 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) {
8673 dup_element(vf, rd, rn, reg_index);
8674 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) {
8675 dup_immediate(vf, rd, ReadXRegister(instr->GetRn()));
8676 } else {
8677 VIXL_UNIMPLEMENTED();
8678 }
8679}
8680
8681
8682void Simulator::VisitNEONExtract(const Instruction* instr) {
8683 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
8684 VectorFormat vf = nfd.GetVectorFormat();
8685 SimVRegister& rd = ReadVRegister(instr->GetRd());
8686 SimVRegister& rn = ReadVRegister(instr->GetRn());
8687 SimVRegister& rm = ReadVRegister(instr->GetRm());
8688 if (instr->Mask(NEONExtractMask) == NEON_EXT) {
8689 int index = instr->GetImmNEONExt();
8690 ext(vf, rd, rn, rm, index);
8691 } else {
8692 VIXL_UNIMPLEMENTED();
8693 }
8694}
8695
8696
8697void Simulator::NEONLoadStoreMultiStructHelper(const Instruction* instr,
8698 AddrMode addr_mode) {
8699 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
8700 VectorFormat vf = nfd.GetVectorFormat();
8701
8702 uint64_t addr_base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
8703 int reg_size = RegisterSizeInBytesFromFormat(vf);
8704
8705 int reg[4];
8706 uint64_t addr[4];
8707 for (int i = 0; i < 4; i++) {
8708 reg[i] = (instr->GetRt() + i) % kNumberOfVRegisters;
8709 addr[i] = addr_base + (i * reg_size);
8710 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008711 int struct_parts = 1;
8712 int reg_count = 1;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008713 bool log_read = true;
8714
Martyn Capewell32009e32016-10-27 11:00:37 +01008715 // Bit 23 determines whether this is an offset or post-index addressing mode.
8716 // In offset mode, bits 20 to 16 should be zero; these bits encode the
8717 // register or immediate in post-index mode.
8718 if ((instr->ExtractBit(23) == 0) && (instr->ExtractBits(20, 16) != 0)) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01008719 VIXL_UNREACHABLE();
8720 }
8721
8722 // We use the PostIndex mask here, as it works in this case for both Offset
8723 // and PostIndex addressing.
8724 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {
8725 case NEON_LD1_4v:
8726 case NEON_LD1_4v_post:
Chris Jones30e7bbd2024-02-15 15:05:25 +00008727 if (!ld1(vf, ReadVRegister(reg[3]), addr[3])) {
8728 return;
8729 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008730 reg_count++;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008731 VIXL_FALLTHROUGH();
8732 case NEON_LD1_3v:
8733 case NEON_LD1_3v_post:
Chris Jones30e7bbd2024-02-15 15:05:25 +00008734 if (!ld1(vf, ReadVRegister(reg[2]), addr[2])) {
8735 return;
8736 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008737 reg_count++;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008738 VIXL_FALLTHROUGH();
8739 case NEON_LD1_2v:
8740 case NEON_LD1_2v_post:
Chris Jones30e7bbd2024-02-15 15:05:25 +00008741 if (!ld1(vf, ReadVRegister(reg[1]), addr[1])) {
8742 return;
8743 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008744 reg_count++;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008745 VIXL_FALLTHROUGH();
8746 case NEON_LD1_1v:
8747 case NEON_LD1_1v_post:
Chris Jones30e7bbd2024-02-15 15:05:25 +00008748 if (!ld1(vf, ReadVRegister(reg[0]), addr[0])) {
8749 return;
8750 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01008751 break;
8752 case NEON_ST1_4v:
8753 case NEON_ST1_4v_post:
Chris Jones3134e252024-02-29 13:44:20 +00008754 if (!st1(vf, ReadVRegister(reg[3]), addr[3])) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00008755 reg_count++;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008756 VIXL_FALLTHROUGH();
8757 case NEON_ST1_3v:
8758 case NEON_ST1_3v_post:
Chris Jones3134e252024-02-29 13:44:20 +00008759 if (!st1(vf, ReadVRegister(reg[2]), addr[2])) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00008760 reg_count++;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008761 VIXL_FALLTHROUGH();
8762 case NEON_ST1_2v:
8763 case NEON_ST1_2v_post:
Chris Jones3134e252024-02-29 13:44:20 +00008764 if (!st1(vf, ReadVRegister(reg[1]), addr[1])) return;
Jacob Bramley423e5422019-11-13 19:15:55 +00008765 reg_count++;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008766 VIXL_FALLTHROUGH();
8767 case NEON_ST1_1v:
8768 case NEON_ST1_1v_post:
Chris Jones3134e252024-02-29 13:44:20 +00008769 if (!st1(vf, ReadVRegister(reg[0]), addr[0])) return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008770 log_read = false;
8771 break;
8772 case NEON_LD2_post:
8773 case NEON_LD2:
Chris Jones89dfbc02024-04-16 16:21:03 +01008774 if (!ld2(vf, ReadVRegister(reg[0]), ReadVRegister(reg[1]), addr[0])) {
8775 return;
8776 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008777 struct_parts = 2;
8778 reg_count = 2;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008779 break;
8780 case NEON_ST2:
8781 case NEON_ST2_post:
Chris Jones3134e252024-02-29 13:44:20 +00008782 if (!st2(vf, ReadVRegister(reg[0]), ReadVRegister(reg[1]), addr[0])) {
8783 return;
8784 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008785 struct_parts = 2;
8786 reg_count = 2;
Jacob Bramley3728a462016-10-26 16:04:44 +01008787 log_read = false;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008788 break;
8789 case NEON_LD3_post:
8790 case NEON_LD3:
Chris Jones89dfbc02024-04-16 16:21:03 +01008791 if (!ld3(vf,
8792 ReadVRegister(reg[0]),
8793 ReadVRegister(reg[1]),
8794 ReadVRegister(reg[2]),
8795 addr[0])) {
8796 return;
8797 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008798 struct_parts = 3;
8799 reg_count = 3;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008800 break;
8801 case NEON_ST3:
8802 case NEON_ST3_post:
Chris Jones3134e252024-02-29 13:44:20 +00008803 if (!st3(vf,
8804 ReadVRegister(reg[0]),
8805 ReadVRegister(reg[1]),
8806 ReadVRegister(reg[2]),
8807 addr[0])) {
8808 return;
8809 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008810 struct_parts = 3;
8811 reg_count = 3;
Jacob Bramley3728a462016-10-26 16:04:44 +01008812 log_read = false;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008813 break;
8814 case NEON_ST4:
8815 case NEON_ST4_post:
Chris Jones3134e252024-02-29 13:44:20 +00008816 if (!st4(vf,
8817 ReadVRegister(reg[0]),
8818 ReadVRegister(reg[1]),
8819 ReadVRegister(reg[2]),
8820 ReadVRegister(reg[3]),
8821 addr[0])) {
8822 return;
8823 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008824 struct_parts = 4;
8825 reg_count = 4;
Jacob Bramley3728a462016-10-26 16:04:44 +01008826 log_read = false;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008827 break;
8828 case NEON_LD4_post:
8829 case NEON_LD4:
Chris Jones30e7bbd2024-02-15 15:05:25 +00008830 if (!ld4(vf,
8831 ReadVRegister(reg[0]),
8832 ReadVRegister(reg[1]),
8833 ReadVRegister(reg[2]),
8834 ReadVRegister(reg[3]),
8835 addr[0])) {
8836 return;
8837 }
Jacob Bramley423e5422019-11-13 19:15:55 +00008838 struct_parts = 4;
8839 reg_count = 4;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008840 break;
8841 default:
8842 VIXL_UNIMPLEMENTED();
8843 }
8844
Jacob Bramley7eb3e212019-11-22 17:28:05 +00008845 bool do_trace = log_read ? ShouldTraceVRegs() : ShouldTraceWrites();
Jacob Bramley423e5422019-11-13 19:15:55 +00008846 if (do_trace) {
8847 PrintRegisterFormat print_format =
8848 GetPrintRegisterFormatTryFP(GetPrintRegisterFormat(vf));
8849 const char* op;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008850 if (log_read) {
Jacob Bramley423e5422019-11-13 19:15:55 +00008851 op = "<-";
Alexandre Ramesd3832962016-07-04 15:03:43 +01008852 } else {
Jacob Bramley423e5422019-11-13 19:15:55 +00008853 op = "->";
8854 // Stores don't represent a change to the source register's value, so only
8855 // print the relevant part of the value.
8856 print_format = GetPrintRegPartial(print_format);
8857 }
8858
8859 VIXL_ASSERT((struct_parts == reg_count) || (struct_parts == 1));
8860 for (int s = reg_count - struct_parts; s >= 0; s -= struct_parts) {
8861 uintptr_t address = addr_base + (s * RegisterSizeInBytesFromFormat(vf));
8862 PrintVStructAccess(reg[s], struct_parts, print_format, op, address);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008863 }
8864 }
8865
8866 if (addr_mode == PostIndex) {
8867 int rm = instr->GetRm();
8868 // The immediate post index addressing mode is indicated by rm = 31.
8869 // The immediate is implied by the number of vector registers used.
Jacob Bramley423e5422019-11-13 19:15:55 +00008870 addr_base += (rm == 31) ? (RegisterSizeInBytesFromFormat(vf) * reg_count)
Alexandre Ramesd3832962016-07-04 15:03:43 +01008871 : ReadXRegister(rm);
Ryan Houdekb13d3bf2023-08-15 09:59:08 -07008872 WriteXRegister(instr->GetRn(),
8873 addr_base,
8874 LogRegWrites,
8875 Reg31IsStackPointer);
Alexandre Ramesd3832962016-07-04 15:03:43 +01008876 } else {
8877 VIXL_ASSERT(addr_mode == Offset);
8878 }
8879}
8880
8881
8882void Simulator::VisitNEONLoadStoreMultiStruct(const Instruction* instr) {
8883 NEONLoadStoreMultiStructHelper(instr, Offset);
8884}
8885
8886
8887void Simulator::VisitNEONLoadStoreMultiStructPostIndex(
8888 const Instruction* instr) {
8889 NEONLoadStoreMultiStructHelper(instr, PostIndex);
8890}
8891
8892
8893void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
8894 AddrMode addr_mode) {
8895 uint64_t addr = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
8896 int rt = instr->GetRt();
8897
Martyn Capewell32009e32016-10-27 11:00:37 +01008898 // Bit 23 determines whether this is an offset or post-index addressing mode.
8899 // In offset mode, bits 20 to 16 should be zero; these bits encode the
8900 // register or immediate in post-index mode.
8901 if ((instr->ExtractBit(23) == 0) && (instr->ExtractBits(20, 16) != 0)) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01008902 VIXL_UNREACHABLE();
8903 }
8904
8905 // We use the PostIndex mask here, as it works in this case for both Offset
8906 // and PostIndex addressing.
8907 bool do_load = false;
8908
Jacob Bramley423e5422019-11-13 19:15:55 +00008909 bool replicating = false;
8910
Alexandre Ramesd3832962016-07-04 15:03:43 +01008911 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
8912 VectorFormat vf_t = nfd.GetVectorFormat();
8913
8914 VectorFormat vf = kFormat16B;
8915 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {
8916 case NEON_LD1_b:
8917 case NEON_LD1_b_post:
8918 case NEON_LD2_b:
8919 case NEON_LD2_b_post:
8920 case NEON_LD3_b:
8921 case NEON_LD3_b_post:
8922 case NEON_LD4_b:
8923 case NEON_LD4_b_post:
8924 do_load = true;
8925 VIXL_FALLTHROUGH();
8926 case NEON_ST1_b:
8927 case NEON_ST1_b_post:
8928 case NEON_ST2_b:
8929 case NEON_ST2_b_post:
8930 case NEON_ST3_b:
8931 case NEON_ST3_b_post:
8932 case NEON_ST4_b:
8933 case NEON_ST4_b_post:
8934 break;
8935
8936 case NEON_LD1_h:
8937 case NEON_LD1_h_post:
8938 case NEON_LD2_h:
8939 case NEON_LD2_h_post:
8940 case NEON_LD3_h:
8941 case NEON_LD3_h_post:
8942 case NEON_LD4_h:
8943 case NEON_LD4_h_post:
8944 do_load = true;
8945 VIXL_FALLTHROUGH();
8946 case NEON_ST1_h:
8947 case NEON_ST1_h_post:
8948 case NEON_ST2_h:
8949 case NEON_ST2_h_post:
8950 case NEON_ST3_h:
8951 case NEON_ST3_h_post:
8952 case NEON_ST4_h:
8953 case NEON_ST4_h_post:
8954 vf = kFormat8H;
8955 break;
8956 case NEON_LD1_s:
8957 case NEON_LD1_s_post:
8958 case NEON_LD2_s:
8959 case NEON_LD2_s_post:
8960 case NEON_LD3_s:
8961 case NEON_LD3_s_post:
8962 case NEON_LD4_s:
8963 case NEON_LD4_s_post:
8964 do_load = true;
8965 VIXL_FALLTHROUGH();
8966 case NEON_ST1_s:
8967 case NEON_ST1_s_post:
8968 case NEON_ST2_s:
8969 case NEON_ST2_s_post:
8970 case NEON_ST3_s:
8971 case NEON_ST3_s_post:
8972 case NEON_ST4_s:
8973 case NEON_ST4_s_post: {
8974 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);
8975 VIXL_STATIC_ASSERT((NEON_LD1_s_post | (1 << NEONLSSize_offset)) ==
8976 NEON_LD1_d_post);
8977 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);
8978 VIXL_STATIC_ASSERT((NEON_ST1_s_post | (1 << NEONLSSize_offset)) ==
8979 NEON_ST1_d_post);
8980 vf = ((instr->GetNEONLSSize() & 1) == 0) ? kFormat4S : kFormat2D;
8981 break;
8982 }
8983
8984 case NEON_LD1R:
Jacob Bramley423e5422019-11-13 19:15:55 +00008985 case NEON_LD1R_post:
Alexandre Ramesd3832962016-07-04 15:03:43 +01008986 case NEON_LD2R:
Jacob Bramley423e5422019-11-13 19:15:55 +00008987 case NEON_LD2R_post:
Alexandre Ramesd3832962016-07-04 15:03:43 +01008988 case NEON_LD3R:
Jacob Bramley423e5422019-11-13 19:15:55 +00008989 case NEON_LD3R_post:
Alexandre Ramesd3832962016-07-04 15:03:43 +01008990 case NEON_LD4R:
Jacob Bramley423e5422019-11-13 19:15:55 +00008991 case NEON_LD4R_post:
Alexandre Ramesd3832962016-07-04 15:03:43 +01008992 vf = vf_t;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008993 do_load = true;
Jacob Bramley423e5422019-11-13 19:15:55 +00008994 replicating = true;
Alexandre Ramesd3832962016-07-04 15:03:43 +01008995 break;
Jacob Bramley423e5422019-11-13 19:15:55 +00008996
Alexandre Ramesd3832962016-07-04 15:03:43 +01008997 default:
8998 VIXL_UNIMPLEMENTED();
8999 }
9000
Alexandre Ramesd3832962016-07-04 15:03:43 +01009001 int index_shift = LaneSizeInBytesLog2FromFormat(vf);
9002 int lane = instr->GetNEONLSIndex(index_shift);
Jacob Bramley423e5422019-11-13 19:15:55 +00009003 int reg_count = 0;
Alexandre Ramesd3832962016-07-04 15:03:43 +01009004 int rt2 = (rt + 1) % kNumberOfVRegisters;
9005 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
9006 int rt4 = (rt3 + 1) % kNumberOfVRegisters;
9007 switch (instr->Mask(NEONLoadStoreSingleLenMask)) {
9008 case NEONLoadStoreSingle1:
Jacob Bramley423e5422019-11-13 19:15:55 +00009009 reg_count = 1;
9010 if (replicating) {
9011 VIXL_ASSERT(do_load);
Chris Jones30e7bbd2024-02-15 15:05:25 +00009012 if (!ld1r(vf, ReadVRegister(rt), addr)) {
9013 return;
9014 }
Jacob Bramley423e5422019-11-13 19:15:55 +00009015 } else if (do_load) {
Chris Jones30e7bbd2024-02-15 15:05:25 +00009016 if (!ld1(vf, ReadVRegister(rt), lane, addr)) {
9017 return;
9018 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01009019 } else {
Chris Jones3134e252024-02-29 13:44:20 +00009020 if (!st1(vf, ReadVRegister(rt), lane, addr)) return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01009021 }
9022 break;
9023 case NEONLoadStoreSingle2:
Jacob Bramley423e5422019-11-13 19:15:55 +00009024 reg_count = 2;
9025 if (replicating) {
9026 VIXL_ASSERT(do_load);
Chris Jones30e7bbd2024-02-15 15:05:25 +00009027 if (!ld2r(vf, ReadVRegister(rt), ReadVRegister(rt2), addr)) {
9028 return;
9029 }
Jacob Bramley423e5422019-11-13 19:15:55 +00009030 } else if (do_load) {
Chris Jones30e7bbd2024-02-15 15:05:25 +00009031 if (!ld2(vf, ReadVRegister(rt), ReadVRegister(rt2), lane, addr)) {
9032 return;
9033 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01009034 } else {
Chris Jones3134e252024-02-29 13:44:20 +00009035 if (!st2(vf, ReadVRegister(rt), ReadVRegister(rt2), lane, addr)) return;
Alexandre Ramesd3832962016-07-04 15:03:43 +01009036 }
9037 break;
9038 case NEONLoadStoreSingle3:
Jacob Bramley423e5422019-11-13 19:15:55 +00009039 reg_count = 3;
9040 if (replicating) {
9041 VIXL_ASSERT(do_load);
Chris Jones30e7bbd2024-02-15 15:05:25 +00009042 if (!ld3r(vf,
9043 ReadVRegister(rt),
9044 ReadVRegister(rt2),
9045 ReadVRegister(rt3),
9046 addr)) {
9047 return;
9048 }
Jacob Bramley423e5422019-11-13 19:15:55 +00009049 } else if (do_load) {
Chris Jones30e7bbd2024-02-15 15:05:25 +00009050 if (!ld3(vf,
9051 ReadVRegister(rt),
9052 ReadVRegister(rt2),
9053 ReadVRegister(rt3),
9054 lane,
9055 addr)) {
9056 return;
9057 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01009058 } else {
Chris Jones3134e252024-02-29 13:44:20 +00009059 if (!st3(vf,
9060 ReadVRegister(rt),
9061 ReadVRegister(rt2),
9062 ReadVRegister(rt3),
9063 lane,
9064 addr)) {
9065 return;
9066 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01009067 }
9068 break;
9069 case NEONLoadStoreSingle4:
Jacob Bramley423e5422019-11-13 19:15:55 +00009070 reg_count = 4;
9071 if (replicating) {
9072 VIXL_ASSERT(do_load);
Chris Jones30e7bbd2024-02-15 15:05:25 +00009073 if (!ld4r(vf,
9074 ReadVRegister(rt),
9075 ReadVRegister(rt2),
9076 ReadVRegister(rt3),
9077 ReadVRegister(rt4),
9078 addr)) {
9079 return;
9080 }
Jacob Bramley423e5422019-11-13 19:15:55 +00009081 } else if (do_load) {
Chris Jones30e7bbd2024-02-15 15:05:25 +00009082 if (!ld4(vf,
9083 ReadVRegister(rt),
9084 ReadVRegister(rt2),
9085 ReadVRegister(rt3),
9086 ReadVRegister(rt4),
9087 lane,
9088 addr)) {
9089 return;
9090 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01009091 } else {
Chris Jones3134e252024-02-29 13:44:20 +00009092 if (!st4(vf,
9093 ReadVRegister(rt),
9094 ReadVRegister(rt2),
9095 ReadVRegister(rt3),
9096 ReadVRegister(rt4),
9097 lane,
9098 addr)) {
9099 return;
9100 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01009101 }
9102 break;
9103 default:
9104 VIXL_UNIMPLEMENTED();
9105 }
9106
Jacob Bramley423e5422019-11-13 19:15:55 +00009107 // Trace registers and/or memory writes.
9108 PrintRegisterFormat print_format =
9109 GetPrintRegisterFormatTryFP(GetPrintRegisterFormat(vf));
9110 if (do_load) {
9111 if (ShouldTraceVRegs()) {
9112 if (replicating) {
9113 PrintVReplicatingStructAccess(rt, reg_count, print_format, "<-", addr);
9114 } else {
9115 PrintVSingleStructAccess(rt, reg_count, lane, print_format, "<-", addr);
9116 }
9117 }
9118 } else {
9119 if (ShouldTraceWrites()) {
9120 // Stores don't represent a change to the source register's value, so only
9121 // print the relevant part of the value.
9122 print_format = GetPrintRegPartial(print_format);
9123 PrintVSingleStructAccess(rt, reg_count, lane, print_format, "->", addr);
9124 }
9125 }
9126
Alexandre Ramesd3832962016-07-04 15:03:43 +01009127 if (addr_mode == PostIndex) {
9128 int rm = instr->GetRm();
9129 int lane_size = LaneSizeInBytesFromFormat(vf);
9130 WriteXRegister(instr->GetRn(),
Jacob Bramley423e5422019-11-13 19:15:55 +00009131 addr + ((rm == 31) ? (reg_count * lane_size)
Ryan Houdekb13d3bf2023-08-15 09:59:08 -07009132 : ReadXRegister(rm)),
9133 LogRegWrites,
9134 Reg31IsStackPointer);
Alexandre Ramesd3832962016-07-04 15:03:43 +01009135 }
9136}
9137
9138
9139void Simulator::VisitNEONLoadStoreSingleStruct(const Instruction* instr) {
9140 NEONLoadStoreSingleStructHelper(instr, Offset);
9141}
9142
9143
9144void Simulator::VisitNEONLoadStoreSingleStructPostIndex(
9145 const Instruction* instr) {
9146 NEONLoadStoreSingleStructHelper(instr, PostIndex);
9147}
9148
9149
9150void Simulator::VisitNEONModifiedImmediate(const Instruction* instr) {
9151 SimVRegister& rd = ReadVRegister(instr->GetRd());
9152 int cmode = instr->GetNEONCmode();
9153 int cmode_3_1 = (cmode >> 1) & 7;
9154 int cmode_3 = (cmode >> 3) & 1;
9155 int cmode_2 = (cmode >> 2) & 1;
9156 int cmode_1 = (cmode >> 1) & 1;
9157 int cmode_0 = cmode & 1;
Carey Williamsd8bb3572018-04-10 11:58:07 +01009158 int half_enc = instr->ExtractBit(11);
Alexandre Ramesd3832962016-07-04 15:03:43 +01009159 int q = instr->GetNEONQ();
9160 int op_bit = instr->GetNEONModImmOp();
9161 uint64_t imm8 = instr->GetImmNEONabcdefgh();
Alexandre Ramesd3832962016-07-04 15:03:43 +01009162 // Find the format and immediate value
9163 uint64_t imm = 0;
9164 VectorFormat vform = kFormatUndefined;
9165 switch (cmode_3_1) {
9166 case 0x0:
9167 case 0x1:
9168 case 0x2:
9169 case 0x3:
9170 vform = (q == 1) ? kFormat4S : kFormat2S;
9171 imm = imm8 << (8 * cmode_3_1);
9172 break;
9173 case 0x4:
9174 case 0x5:
9175 vform = (q == 1) ? kFormat8H : kFormat4H;
9176 imm = imm8 << (8 * cmode_1);
9177 break;
9178 case 0x6:
9179 vform = (q == 1) ? kFormat4S : kFormat2S;
9180 if (cmode_0 == 0) {
9181 imm = imm8 << 8 | 0x000000ff;
9182 } else {
9183 imm = imm8 << 16 | 0x0000ffff;
9184 }
9185 break;
9186 case 0x7:
9187 if (cmode_0 == 0 && op_bit == 0) {
9188 vform = q ? kFormat16B : kFormat8B;
9189 imm = imm8;
9190 } else if (cmode_0 == 0 && op_bit == 1) {
9191 vform = q ? kFormat2D : kFormat1D;
9192 imm = 0;
9193 for (int i = 0; i < 8; ++i) {
TheLastRar49d6efa2024-10-15 16:37:27 +01009194 if (imm8 & (uint64_t{1} << i)) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01009195 imm |= (UINT64_C(0xff) << (8 * i));
9196 }
9197 }
9198 } else { // cmode_0 == 1, cmode == 0xf.
Carey Williamsd8bb3572018-04-10 11:58:07 +01009199 if (half_enc == 1) {
9200 vform = q ? kFormat8H : kFormat4H;
Jacob Bramleyca789742018-09-13 14:25:46 +01009201 imm = Float16ToRawbits(instr->GetImmNEONFP16());
Carey Williamsd8bb3572018-04-10 11:58:07 +01009202 } else if (op_bit == 0) {
Alexandre Ramesd3832962016-07-04 15:03:43 +01009203 vform = q ? kFormat4S : kFormat2S;
9204 imm = FloatToRawbits(instr->GetImmNEONFP32());
9205 } else if (q == 1) {
9206 vform = kFormat2D;
9207 imm = DoubleToRawbits(instr->GetImmNEONFP64());
9208 } else {
9209 VIXL_ASSERT((q == 0) && (op_bit == 1) && (cmode == 0xf));
9210 VisitUnallocated(instr);
9211 }
9212 }
9213 break;
9214 default:
9215 VIXL_UNREACHABLE();
9216 break;
9217 }
9218
9219 // Find the operation
9220 NEONModifiedImmediateOp op;
9221 if (cmode_3 == 0) {
9222 if (cmode_0 == 0) {
9223 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
9224 } else { // cmode<0> == '1'
9225 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
9226 }
9227 } else { // cmode<3> == '1'
9228 if (cmode_2 == 0) {
9229 if (cmode_0 == 0) {
9230 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
9231 } else { // cmode<0> == '1'
9232 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
9233 }
9234 } else { // cmode<2> == '1'
9235 if (cmode_1 == 0) {
9236 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
9237 } else { // cmode<1> == '1'
9238 if (cmode_0 == 0) {
9239 op = NEONModifiedImmediate_MOVI;
9240 } else { // cmode<0> == '1'
9241 op = NEONModifiedImmediate_MOVI;
9242 }
9243 }
9244 }
9245 }
9246
9247 // Call the logic function
9248 if (op == NEONModifiedImmediate_ORR) {
9249 orr(vform, rd, rd, imm);
9250 } else if (op == NEONModifiedImmediate_BIC) {
9251 bic(vform, rd, rd, imm);
9252 } else if (op == NEONModifiedImmediate_MOVI) {
9253 movi(vform, rd, imm);
9254 } else if (op == NEONModifiedImmediate_MVNI) {
9255 mvni(vform, rd, imm);
9256 } else {
9257 VisitUnimplemented(instr);
9258 }
9259}
9260
9261
9262void Simulator::VisitNEONScalar2RegMisc(const Instruction* instr) {
9263 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
9264 VectorFormat vf = nfd.GetVectorFormat();
9265
9266 SimVRegister& rd = ReadVRegister(instr->GetRd());
9267 SimVRegister& rn = ReadVRegister(instr->GetRn());
9268
9269 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) {
9270 // These instructions all use a two bit size field, except NOT and RBIT,
9271 // which use the field to encode the operation.
9272 switch (instr->Mask(NEONScalar2RegMiscMask)) {
9273 case NEON_CMEQ_zero_scalar:
9274 cmp(vf, rd, rn, 0, eq);
9275 break;
9276 case NEON_CMGE_zero_scalar:
9277 cmp(vf, rd, rn, 0, ge);
9278 break;
9279 case NEON_CMGT_zero_scalar:
9280 cmp(vf, rd, rn, 0, gt);
9281 break;
9282 case NEON_CMLT_zero_scalar:
9283 cmp(vf, rd, rn, 0, lt);
9284 break;
9285 case NEON_CMLE_zero_scalar:
9286 cmp(vf, rd, rn, 0, le);
9287 break;
9288 case NEON_ABS_scalar:
9289 abs(vf, rd, rn);
9290 break;
9291 case NEON_SQABS_scalar:
9292 abs(vf, rd, rn).SignedSaturate(vf);
9293 break;
9294 case NEON_NEG_scalar:
9295 neg(vf, rd, rn);
9296 break;
9297 case NEON_SQNEG_scalar:
9298 neg(vf, rd, rn).SignedSaturate(vf);
9299 break;
9300 case NEON_SUQADD_scalar:
Martyn Capewell9b532192020-09-15 16:20:11 +01009301 suqadd(vf, rd, rd, rn);
Alexandre Ramesd3832962016-07-04 15:03:43 +01009302 break;
9303 case NEON_USQADD_scalar:
Martyn Capewell9b532192020-09-15 16:20:11 +01009304 usqadd(vf, rd, rd, rn);
Alexandre Ramesd3832962016-07-04 15:03:43 +01009305 break;
9306 default:
9307 VIXL_UNIMPLEMENTED();
9308 break;
9309 }
9310 } else {
9311 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
9312 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
9313
9314 // These instructions all use a one bit size field, except SQXTUN, SQXTN
9315 // and UQXTN, which use a two bit size field.
9316 switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
9317 case NEON_FRECPE_scalar:
9318 frecpe(fpf, rd, rn, fpcr_rounding);
9319 break;
9320 case NEON_FRECPX_scalar:
9321 frecpx(fpf, rd, rn);
9322 break;
9323 case NEON_FRSQRTE_scalar:
9324 frsqrte(fpf, rd, rn);
9325 break;
9326 case NEON_FCMGT_zero_scalar:
9327 fcmp_zero(fpf, rd, rn, gt);
9328 break;
9329 case NEON_FCMGE_zero_scalar:
9330 fcmp_zero(fpf, rd, rn, ge);
9331 break;
9332 case NEON_FCMEQ_zero_scalar:
9333 fcmp_zero(fpf, rd, rn, eq);
9334 break;
9335 case NEON_FCMLE_zero_scalar:
9336 fcmp_zero(fpf, rd, rn, le);
9337 break;
9338 case NEON_FCMLT_zero_scalar:
9339 fcmp_zero(fpf, rd, rn, lt);
9340 break;
9341 case NEON_SCVTF_scalar:
9342 scvtf(fpf, rd, rn, 0, fpcr_rounding);
9343 break;
9344 case NEON_UCVTF_scalar:
9345 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
9346 break;
9347 case NEON_FCVTNS_scalar:
9348 fcvts(fpf, rd, rn, FPTieEven);
9349 break;
9350 case NEON_FCVTNU_scalar:
9351 fcvtu(fpf, rd, rn, FPTieEven);
9352 break;
9353 case NEON_FCVTPS_scalar:
9354 fcvts(fpf, rd, rn, FPPositiveInfinity);
9355 break;
9356 case NEON_FCVTPU_scalar:
9357 fcvtu(fpf, rd, rn, FPPositiveInfinity);
9358 break;
9359 case NEON_FCVTMS_scalar:
9360 fcvts(fpf, rd, rn, FPNegativeInfinity);
9361 break;
9362 case NEON_FCVTMU_scalar:
9363 fcvtu(fpf, rd, rn, FPNegativeInfinity);
9364 break;
9365 case NEON_FCVTZS_scalar:
9366 fcvts(fpf, rd, rn, FPZero);
9367 break;
9368 case NEON_FCVTZU_scalar:
9369 fcvtu(fpf, rd, rn, FPZero);
9370 break;
9371 case NEON_FCVTAS_scalar:
9372 fcvts(fpf, rd, rn, FPTieAway);
9373 break;
9374 case NEON_FCVTAU_scalar:
9375 fcvtu(fpf, rd, rn, FPTieAway);
9376 break;
9377 case NEON_FCVTXN_scalar:
9378 // Unlike all of the other FP instructions above, fcvtxn encodes dest
9379 // size S as size<0>=1. There's only one case, so we ignore the form.
9380 VIXL_ASSERT(instr->ExtractBit(22) == 1);
9381 fcvtxn(kFormatS, rd, rn);
9382 break;
9383 default:
9384 switch (instr->Mask(NEONScalar2RegMiscMask)) {
9385 case NEON_SQXTN_scalar:
9386 sqxtn(vf, rd, rn);
9387 break;
9388 case NEON_UQXTN_scalar:
9389 uqxtn(vf, rd, rn);
9390 break;
9391 case NEON_SQXTUN_scalar:
9392 sqxtun(vf, rd, rn);
9393 break;
9394 default:
9395 VIXL_UNIMPLEMENTED();
9396 }
9397 }
9398 }
9399}
9400
9401
Jacob Bramleyca789742018-09-13 14:25:46 +01009402void Simulator::VisitNEONScalar2RegMiscFP16(const Instruction* instr) {
9403 VectorFormat fpf = kFormatH;
9404 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
9405
9406 SimVRegister& rd = ReadVRegister(instr->GetRd());
9407 SimVRegister& rn = ReadVRegister(instr->GetRn());
9408
9409 switch (instr->Mask(NEONScalar2RegMiscFP16Mask)) {
9410 case NEON_FRECPE_H_scalar:
9411 frecpe(fpf, rd, rn, fpcr_rounding);
9412 break;
9413 case NEON_FRECPX_H_scalar:
9414 frecpx(fpf, rd, rn);
9415 break;
9416 case NEON_FRSQRTE_H_scalar:
9417 frsqrte(fpf, rd, rn);
9418 break;
9419 case NEON_FCMGT_H_zero_scalar:
9420 fcmp_zero(fpf, rd, rn, gt);
9421 break;
9422 case NEON_FCMGE_H_zero_scalar:
9423 fcmp_zero(fpf, rd, rn, ge);
9424 break;
9425 case NEON_FCMEQ_H_zero_scalar:
9426 fcmp_zero(fpf, rd, rn, eq);
9427 break;
9428 case NEON_FCMLE_H_zero_scalar:
9429 fcmp_zero(fpf, rd, rn, le);
9430 break;
9431 case NEON_FCMLT_H_zero_scalar:
9432 fcmp_zero(fpf, rd, rn, lt);
9433 break;
9434 case NEON_SCVTF_H_scalar:
9435 scvtf(fpf, rd, rn, 0, fpcr_rounding);
9436 break;
9437 case NEON_UCVTF_H_scalar:
9438 ucvtf(fpf, rd, rn, 0, fpcr_rounding);
9439 break;
9440 case NEON_FCVTNS_H_scalar:
9441 fcvts(fpf, rd, rn, FPTieEven);
9442 break;
9443 case NEON_FCVTNU_H_scalar:
9444 fcvtu(fpf, rd, rn, FPTieEven);
9445 break;
9446 case NEON_FCVTPS_H_scalar:
9447 fcvts(fpf, rd, rn, FPPositiveInfinity);
9448 break;
9449 case NEON_FCVTPU_H_scalar:
9450 fcvtu(fpf, rd, rn, FPPositiveInfinity);
9451 break;
9452 case NEON_FCVTMS_H_scalar:
9453 fcvts(fpf, rd, rn, FPNegativeInfinity);
9454 break;
9455 case NEON_FCVTMU_H_scalar:
9456 fcvtu(fpf, rd, rn, FPNegativeInfinity);
9457 break;
9458 case NEON_FCVTZS_H_scalar:
9459 fcvts(fpf, rd, rn, FPZero);
9460 break;
9461 case NEON_FCVTZU_H_scalar:
9462 fcvtu(fpf, rd, rn, FPZero);
9463 break;
9464 case NEON_FCVTAS_H_scalar:
9465 fcvts(fpf, rd, rn, FPTieAway);
9466 break;
9467 case NEON_FCVTAU_H_scalar:
9468 fcvtu(fpf, rd, rn, FPTieAway);
9469 break;
9470 }
9471}
9472
9473
Alexandre Ramesd3832962016-07-04 15:03:43 +01009474void Simulator::VisitNEONScalar3Diff(const Instruction* instr) {
9475 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
9476 VectorFormat vf = nfd.GetVectorFormat();
9477
9478 SimVRegister& rd = ReadVRegister(instr->GetRd());
9479 SimVRegister& rn = ReadVRegister(instr->GetRn());
9480 SimVRegister& rm = ReadVRegister(instr->GetRm());
9481 switch (instr->Mask(NEONScalar3DiffMask)) {
9482 case NEON_SQDMLAL_scalar:
9483 sqdmlal(vf, rd, rn, rm);
9484 break;
9485 case NEON_SQDMLSL_scalar:
9486 sqdmlsl(vf, rd, rn, rm);
9487 break;
9488 case NEON_SQDMULL_scalar:
9489 sqdmull(vf, rd, rn, rm);
9490 break;
9491 default:
9492 VIXL_UNIMPLEMENTED();
9493 }
9494}
9495
9496
9497void Simulator::VisitNEONScalar3Same(const Instruction* instr) {
9498 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
9499 VectorFormat vf = nfd.GetVectorFormat();
9500
9501 SimVRegister& rd = ReadVRegister(instr->GetRd());
9502 SimVRegister& rn = ReadVRegister(instr->GetRn());
9503 SimVRegister& rm = ReadVRegister(instr->GetRm());
9504
9505 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
9506 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
9507 switch (instr->Mask(NEONScalar3SameFPMask)) {
9508 case NEON_FMULX_scalar:
9509 fmulx(vf, rd, rn, rm);
9510 break;
9511 case NEON_FACGE_scalar:
9512 fabscmp(vf, rd, rn, rm, ge);
9513 break;
9514 case NEON_FACGT_scalar:
9515 fabscmp(vf, rd, rn, rm, gt);
9516 break;
9517 case NEON_FCMEQ_scalar:
9518 fcmp(vf, rd, rn, rm, eq);
9519 break;
9520 case NEON_FCMGE_scalar:
9521 fcmp(vf, rd, rn, rm, ge);
9522 break;
9523 case NEON_FCMGT_scalar:
9524 fcmp(vf, rd, rn, rm, gt);
9525 break;
9526 case NEON_FRECPS_scalar:
9527 frecps(vf, rd, rn, rm);
9528 break;
9529 case NEON_FRSQRTS_scalar:
9530 frsqrts(vf, rd, rn, rm);
9531 break;
9532 case NEON_FABD_scalar:
9533 fabd(vf, rd, rn, rm);
9534 break;
9535 default:
9536 VIXL_UNIMPLEMENTED();
9537 }
9538 } else {
9539 switch (instr->Mask(NEONScalar3SameMask)) {
9540 case NEON_ADD_scalar:
9541 add(vf, rd, rn, rm);
9542 break;
9543 case NEON_SUB_scalar:
9544 sub(vf, rd, rn, rm);
9545 break;
9546 case NEON_CMEQ_scalar:
9547 cmp(vf, rd, rn, rm, eq);
9548 break;
9549 case NEON_CMGE_scalar:
9550 cmp(vf, rd, rn, rm, ge);
9551 break;
9552 case NEON_CMGT_scalar:
9553 cmp(vf, rd, rn, rm, gt);
9554 break;
9555 case NEON_CMHI_scalar:
9556 cmp(vf, rd, rn, rm, hi);
9557 break;
9558 case NEON_CMHS_scalar:
9559 cmp(vf, rd, rn, rm, hs);
9560 break;
9561 case NEON_CMTST_scalar:
9562 cmptst(vf, rd, rn, rm);
9563 break;
9564 case NEON_USHL_scalar:
9565 ushl(vf, rd, rn, rm);
9566 break;
9567 case NEON_SSHL_scalar:
9568 sshl(vf, rd, rn, rm);
9569 break;
9570 case NEON_SQDMULH_scalar:
9571 sqdmulh(vf, rd, rn, rm);
9572 break;
9573 case NEON_SQRDMULH_scalar:
9574 sqrdmulh(vf, rd, rn, rm);
9575 break;
9576 case NEON_UQADD_scalar:
9577 add(vf, rd, rn, rm).UnsignedSaturate(vf);
9578 break;
9579 case NEON_SQADD_scalar:
9580 add(vf, rd, rn, rm).SignedSaturate(vf);
9581 break;
9582 case NEON_UQSUB_scalar:
9583 sub(vf, rd, rn, rm).UnsignedSaturate(vf);
9584 break;
9585 case NEON_SQSUB_scalar:
9586 sub(vf, rd, rn, rm).SignedSaturate(vf);
9587 break;
9588 case NEON_UQSHL_scalar:
9589 ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
9590 break;
9591 case NEON_SQSHL_scalar:
9592 sshl(vf, rd, rn, rm).SignedSaturate(vf);
9593 break;
9594 case NEON_URSHL_scalar:
9595 ushl(vf, rd, rn, rm).Round(vf);
9596 break;
9597 case NEON_SRSHL_scalar:
9598 sshl(vf, rd, rn, rm).Round(vf);
9599 break;
9600 case NEON_UQRSHL_scalar:
9601 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
9602 break;
9603 case NEON_SQRSHL_scalar:
9604 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
9605 break;
9606 default:
9607 VIXL_UNIMPLEMENTED();
9608 }
9609 }
9610}
9611
Jacob Bramleyca789742018-09-13 14:25:46 +01009612void Simulator::VisitNEONScalar3SameFP16(const Instruction* instr) {
9613 SimVRegister& rd = ReadVRegister(instr->GetRd());
9614 SimVRegister& rn = ReadVRegister(instr->GetRn());
9615 SimVRegister& rm = ReadVRegister(instr->GetRm());
9616
9617 switch (instr->Mask(NEONScalar3SameFP16Mask)) {
9618 case NEON_FABD_H_scalar:
9619 fabd(kFormatH, rd, rn, rm);
9620 break;
9621 case NEON_FMULX_H_scalar:
9622 fmulx(kFormatH, rd, rn, rm);
9623 break;
9624 case NEON_FCMEQ_H_scalar:
9625 fcmp(kFormatH, rd, rn, rm, eq);
9626 break;
9627 case NEON_FCMGE_H_scalar:
9628 fcmp(kFormatH, rd, rn, rm, ge);
9629 break;
9630 case NEON_FCMGT_H_scalar:
9631 fcmp(kFormatH, rd, rn, rm, gt);
9632 break;
9633 case NEON_FACGE_H_scalar:
9634 fabscmp(kFormatH, rd, rn, rm, ge);
9635 break;
9636 case NEON_FACGT_H_scalar:
9637 fabscmp(kFormatH, rd, rn, rm, gt);
9638 break;
9639 case NEON_FRECPS_H_scalar:
9640 frecps(kFormatH, rd, rn, rm);
9641 break;
9642 case NEON_FRSQRTS_H_scalar:
9643 frsqrts(kFormatH, rd, rn, rm);
9644 break;
9645 default:
9646 VIXL_UNREACHABLE();
9647 }
9648}
9649
Alexandre Ramesd3832962016-07-04 15:03:43 +01009650
Alexander Gilday43785642018-04-04 13:42:33 +01009651void Simulator::VisitNEONScalar3SameExtra(const Instruction* instr) {
9652 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
9653 VectorFormat vf = nfd.GetVectorFormat();
9654
9655 SimVRegister& rd = ReadVRegister(instr->GetRd());
9656 SimVRegister& rn = ReadVRegister(instr->GetRn());
9657 SimVRegister& rm = ReadVRegister(instr->GetRm());
9658
9659 switch (instr->Mask(NEONScalar3SameExtraMask)) {
9660 case NEON_SQRDMLAH_scalar:
9661 sqrdmlah(vf, rd, rn, rm);
9662 break;
9663 case NEON_SQRDMLSH_scalar:
9664 sqrdmlsh(vf, rd, rn, rm);
9665 break;
9666 default:
9667 VIXL_UNIMPLEMENTED();
9668 }
9669}
9670
Alexandre Ramesd3832962016-07-04 15:03:43 +01009671void Simulator::VisitNEONScalarByIndexedElement(const Instruction* instr) {
9672 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
9673 VectorFormat vf = nfd.GetVectorFormat();
Alexandre Ramesd3832962016-07-04 15:03:43 +01009674 SimVRegister& rd = ReadVRegister(instr->GetRd());
9675 SimVRegister& rn = ReadVRegister(instr->GetRn());
9676 ByElementOp Op = NULL;
9677
mmc28ad17400f2025-01-17 10:47:22 +00009678 std::pair<int, int> rm_and_index = instr->GetNEONMulRmAndIndex();
9679 std::unordered_map<uint32_t, ByElementOp> handler = {
9680 {"sqdmull_asisdelem_l"_h, &Simulator::sqdmull},
9681 {"sqdmlal_asisdelem_l"_h, &Simulator::sqdmlal},
9682 {"sqdmlsl_asisdelem_l"_h, &Simulator::sqdmlsl},
9683 {"sqdmulh_asisdelem_r"_h, &Simulator::sqdmulh},
9684 {"sqrdmulh_asisdelem_r"_h, &Simulator::sqrdmulh},
9685 {"sqrdmlah_asisdelem_r"_h, &Simulator::sqrdmlah},
9686 {"sqrdmlsh_asisdelem_r"_h, &Simulator::sqrdmlsh},
9687 {"fmul_asisdelem_rh_h"_h, &Simulator::fmul},
9688 {"fmul_asisdelem_r_sd"_h, &Simulator::fmul},
9689 {"fmla_asisdelem_rh_h"_h, &Simulator::fmla},
9690 {"fmla_asisdelem_r_sd"_h, &Simulator::fmla},
9691 {"fmls_asisdelem_rh_h"_h, &Simulator::fmls},
9692 {"fmls_asisdelem_r_sd"_h, &Simulator::fmls},
9693 {"fmulx_asisdelem_rh_h"_h, &Simulator::fmulx},
9694 {"fmulx_asisdelem_r_sd"_h, &Simulator::fmulx},
9695 };
9696
9697 std::unordered_map<uint32_t, ByElementOp>::const_iterator it =
9698 handler.find(form_hash_);
9699
9700 if (it == handler.end()) {
9701 VIXL_UNIMPLEMENTED();
9702 } else {
9703 Op = it->second;
Alexandre Ramesd3832962016-07-04 15:03:43 +01009704 }
9705
mmc28ad17400f2025-01-17 10:47:22 +00009706 switch (form_hash_) {
9707 case "sqdmull_asisdelem_l"_h:
9708 case "sqdmlal_asisdelem_l"_h:
9709 case "sqdmlsl_asisdelem_l"_h:
9710 if ((vf == kFormatB) || (vf == kFormatH)) {
9711 VisitUnallocated(instr);
9712 return;
9713 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01009714 break;
mmc28ad17400f2025-01-17 10:47:22 +00009715 case "sqdmulh_asisdelem_r"_h:
9716 case "sqrdmulh_asisdelem_r"_h:
9717 case "sqrdmlah_asisdelem_r"_h:
9718 case "sqrdmlsh_asisdelem_r"_h:
9719 vf = nfd.GetVectorFormat(nfd.ScalarFormatMap());
9720 if ((vf == kFormatB) || (vf == kFormatD)) {
9721 VisitUnallocated(instr);
9722 return;
9723 }
Alexandre Ramesd3832962016-07-04 15:03:43 +01009724 break;
mmc28ad17400f2025-01-17 10:47:22 +00009725 case "fmul_asisdelem_r_sd"_h:
9726 case "fmla_asisdelem_r_sd"_h:
9727 case "fmls_asisdelem_r_sd"_h:
9728 case "fmulx_asisdelem_r_sd"_h:
Alexandre Ramesd3832962016-07-04 15:03:43 +01009729 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
mmc28ad17400f2025-01-17 10:47:22 +00009730 break;
9731 case "fmul_asisdelem_rh_h"_h:
9732 case "fmla_asisdelem_rh_h"_h:
9733 case "fmls_asisdelem_rh_h"_h:
9734 case "fmulx_asisdelem_rh_h"_h:
9735 vf = kFormatH;
9736 break;
Alexandre Ramesd3832962016-07-04 15:03:43 +01009737 }
9738
mmc28ad17400f2025-01-17 10:47:22 +00009739 (this->*Op)(vf,
9740 rd,
9741 rn,
9742 ReadVRegister(rm_and_index.first),
9743 rm_and_index.second);
Alexandre Ramesd3832962016-07-04 15:03:43 +01009744}
9745
9746
9747void Simulator::VisitNEONScalarCopy(const Instruction* instr) {
9748 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());
9749 VectorFormat vf = nfd.GetVectorFormat();
9750
9751 SimVRegister& rd = ReadVRegister(instr->GetRd());
9752 SimVRegister& rn = ReadVRegister(instr->GetRn());
9753
9754 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) {
9755 int imm5 = instr->GetImmNEON5();
9756 int tz = CountTrailingZeros(imm5, 32);
Martyn Capewelled5e03d2021-06-24 16:44:24 +01009757 int rn_index = ExtractSignedBitfield32(31, tz + 1, imm5);
Alexandre Ramesd3832962016-07-04 15:03:43 +01009758 dup_element(vf, rd, rn, rn_index);
9759 } else {
9760 VIXL_UNIMPLEMENTED();
9761 }
9762}
9763
9764
9765void Simulator::VisitNEONScalarPairwise(const Instruction* instr) {
Jacob Bramleyca789742018-09-13 14:25:46 +01009766 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarPairwiseFormatMap());
Alexandre Ramesd3832962016-07-04 15:03:43 +01009767 VectorFormat vf = nfd.GetVectorFormat();
9768
9769 SimVRegister& rd = ReadVRegister(instr->GetRd());
9770 SimVRegister& rn = ReadVRegister(instr->GetRn());
9771 switch (instr->Mask(NEONScalarPairwiseMask)) {
Jacob Bramleyca789742018-09-13 14:25:46 +01009772 case NEON_ADDP_scalar: {
9773 // All pairwise operations except ADDP use bit U to differentiate FP16
9774 // from FP32/FP64 variations.
9775 NEONFormatDecoder nfd_addp(instr, NEONFormatDecoder::FPScalarFormatMap());
9776 addp(nfd_addp.GetVectorFormat(), rd, rn);
Alexandre Ramesd3832962016-07-04 15:03:43 +01009777 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01009778 }
9779 case NEON_FADDP_h_scalar:
Alexandre Ramesd3832962016-07-04 15:03:43 +01009780 case NEON_FADDP_scalar:
9781 faddp(vf, rd, rn);
9782 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01009783 case NEON_FMAXP_h_scalar:
Alexandre Ramesd3832962016-07-04 15:03:43 +01009784 case NEON_FMAXP_scalar:
9785 fmaxp(vf, rd, rn);
9786 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01009787 case NEON_FMAXNMP_h_scalar:
Alexandre Ramesd3832962016-07-04 15:03:43 +01009788 case NEON_FMAXNMP_scalar:
9789 fmaxnmp(vf, rd, rn);
9790 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01009791 case NEON_FMINP_h_scalar:
Alexandre Ramesd3832962016-07-04 15:03:43 +01009792 case NEON_FMINP_scalar:
9793 fminp(vf, rd, rn);
9794 break;
Jacob Bramleyca789742018-09-13 14:25:46 +01009795 case NEON_FMINNMP_h_scalar:
Alexandre Ramesd3832962016-07-04 15:03:43 +01009796 case NEON_FMINNMP_scalar:
9797 fminnmp(vf, rd, rn);
9798 break;
9799 default:
9800 VIXL_UNIMPLEMENTED();
9801 }
9802}
9803
9804
9805void Simulator::VisitNEONScalarShiftImmediate(const Instruction* instr) {
9806 SimVRegister& rd = ReadVRegister(instr->GetRd());
9807 SimVRegister& rn = ReadVRegister(instr->GetRn());
9808 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
9809
9810 static const NEONFormatMap map = {{22, 21, 20, 19},
9811 {NF_UNDEF,
9812 NF_B,
9813 NF_H,
9814 NF_H,
9815 NF_S,
9816 NF_S,
9817 NF_S,
9818 NF_S,
9819 NF_D,
9820 NF_D,
9821 NF_D,
9822 NF_D,
9823 NF_D,
9824 NF_D,
9825 NF_D,
9826 NF_D}};
9827 NEONFormatDecoder nfd(instr, &map);
9828 VectorFormat vf = nfd.GetVectorFormat();
9829
Jacob Bramleyacd32aa2019-12-12 18:08:20 +00009830 int highest_set_bit = HighestSetBitPosition(instr->GetImmNEONImmh());
9831 int immh_immb = instr->GetImmNEONImmhImmb();
9832 int right_shift = (16 << highest_set_bit) - immh_immb;
9833 int left_shift = immh_immb - (8 << highest_set_bit);
Alexandre Ramesd3832962016-07-04 15:03:43 +01009834 switch (instr->Mask(NEONScalarShiftImmediateMask)) {
9835 case NEON_SHL_scalar:
9836 shl(vf, rd, rn, left_shift);
9837 break;
9838 case NEON_SLI_scalar:
9839 sli(vf, rd, rn, left_shift);
9840 break;
9841 case NEON_SQSHL_imm_scalar:
9842 sqshl(vf, rd, rn, left_shift);
9843 break;
9844 case NEON_UQSHL_imm_scalar:
9845 uqshl(vf, rd, rn, left_shift);
9846 break;
9847 case NEON_SQSHLU_scalar:
9848 sqshlu(vf, rd, rn, left_shift);
9849 break;
9850 case NEON_SRI_scalar:
9851 sri(vf, rd, rn, right_shift);
9852 break;
9853 case NEON_SSHR_scalar:
9854 sshr(vf, rd, rn, right_shift);
9855 break;
9856 case NEON_USHR_scalar:
9857 ushr(vf, rd, rn, right_shift);
9858 break;
9859 case NEON_SRSHR_scalar:
9860 sshr(vf, rd, rn, right_shift).Round(vf);
9861 break;
9862 case NEON_URSHR_scalar:
9863 ushr(vf, rd, rn, right_shift).Round(vf);
9864 break;
9865 case NEON_SSRA_scalar:
9866 ssra(vf, rd, rn, right_shift);
9867 break;
9868 case NEON_USRA_scalar:
9869 usra(vf, rd, rn, right_shift);
9870 break;
9871 case NEON_SRSRA_scalar:
9872 srsra(vf, rd, rn, right_shift);
9873 break;
9874 case NEON_URSRA_scalar:
9875 ursra(vf, rd, rn, right_shift);
9876 break;
9877 case NEON_UQSHRN_scalar:
9878 uqshrn(vf, rd, rn, right_shift);
9879 break;
9880 case NEON_UQRSHRN_scalar:
9881 uqrshrn(vf, rd, rn, right_shift);
9882 break;
9883 case NEON_SQSHRN_scalar:
9884 sqshrn(vf, rd, rn, right_shift);
9885 break;
9886 case NEON_SQRSHRN_scalar:
9887 sqrshrn(vf, rd, rn, right_shift);
9888 break;
9889 case NEON_SQSHRUN_scalar:
9890 sqshrun(vf, rd, rn, right_shift);
9891 break;
9892 case NEON_SQRSHRUN_scalar:
9893 sqrshrun(vf, rd, rn, right_shift);
9894 break;
9895 case NEON_FCVTZS_imm_scalar:
9896 fcvts(vf, rd, rn, FPZero, right_shift);
9897 break;
9898 case NEON_FCVTZU_imm_scalar:
9899 fcvtu(vf, rd, rn, FPZero, right_shift);
9900 break;
9901 case NEON_SCVTF_imm_scalar:
9902 scvtf(vf, rd, rn, right_shift, fpcr_rounding);
9903 break;
9904 case NEON_UCVTF_imm_scalar:
9905 ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
9906 break;
9907 default:
9908 VIXL_UNIMPLEMENTED();
9909 }
9910}
9911
9912
9913void Simulator::VisitNEONShiftImmediate(const Instruction* instr) {
9914 SimVRegister& rd = ReadVRegister(instr->GetRd());
9915 SimVRegister& rn = ReadVRegister(instr->GetRn());
9916 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
9917
9918 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
9919 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
9920 static const NEONFormatMap map = {{22, 21, 20, 19, 30},
Pierre Langlois1bce0072017-06-06 17:58:58 +01009921 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B,
9922 NF_4H, NF_8H, NF_4H, NF_8H,
9923 NF_2S, NF_4S, NF_2S, NF_4S,
9924 NF_2S, NF_4S, NF_2S, NF_4S,
9925 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
9926 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
9927 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
9928 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}};
Alexandre Ramesd3832962016-07-04 15:03:43 +01009929 NEONFormatDecoder nfd(instr, &map);
9930 VectorFormat vf = nfd.GetVectorFormat();
9931
9932 // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
9933 static const NEONFormatMap map_l =
9934 {{22, 21, 20, 19},
9935 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}};
9936 VectorFormat vf_l = nfd.GetVectorFormat(&map_l);
9937
Jacob Bramleyacd32aa2019-12-12 18:08:20 +00009938 int highest_set_bit = HighestSetBitPosition(instr->GetImmNEONImmh());
9939 int immh_immb = instr->GetImmNEONImmhImmb();
9940 int right_shift = (16 << highest_set_bit) - immh_immb;
9941 int left_shift = immh_immb - (8 << highest_set_bit);
Alexandre Ramesd3832962016-07-04 15:03:43 +01009942
9943 switch (instr->Mask(NEONShiftImmediateMask)) {
9944 case NEON_SHL:
9945 shl(vf, rd, rn, left_shift);
9946 break;
9947 case NEON_SLI:
9948 sli(vf, rd, rn, left_shift);
9949 break;
9950 case NEON_SQSHLU:
9951 sqshlu(vf, rd, rn, left_shift);
9952 break;
9953 case NEON_SRI:
9954 sri(vf, rd, rn, right_shift);
9955 break;
9956 case NEON_SSHR:
9957 sshr(vf, rd, rn, right_shift);
9958 break;
9959 case NEON_USHR:
9960 ushr(vf, rd, rn, right_shift);
9961 break;
9962 case NEON_SRSHR:
9963 sshr(vf, rd, rn, right_shift).Round(vf);
9964 break;
9965 case NEON_URSHR:
9966 ushr(vf, rd, rn, right_shift).Round(vf);
9967 break;
9968 case NEON_SSRA:
9969 ssra(vf, rd, rn, right_shift);
9970 break;
9971 case NEON_USRA:
9972 usra(vf, rd, rn, right_shift);
9973 break;
9974 case NEON_SRSRA:
9975 srsra(vf, rd, rn, right_shift);
9976 break;
9977 case NEON_URSRA:
9978 ursra(vf, rd, rn, right_shift);
9979 break;
9980 case NEON_SQSHL_imm:
9981 sqshl(vf, rd, rn, left_shift);
9982 break;
9983 case NEON_UQSHL_imm:
9984 uqshl(vf, rd, rn, left_shift);
9985 break;
9986 case NEON_SCVTF_imm:
9987 scvtf(vf, rd, rn, right_shift, fpcr_rounding);
9988 break;
9989 case NEON_UCVTF_imm:
9990 ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
9991 break;
9992 case NEON_FCVTZS_imm:
9993 fcvts(vf, rd, rn, FPZero, right_shift);
9994 break;
9995 case NEON_FCVTZU_imm:
9996 fcvtu(vf, rd, rn, FPZero, right_shift);
9997 break;
9998 case NEON_SSHLL:
9999 vf = vf_l;
10000 if (instr->Mask(NEON_Q)) {
10001 sshll2(vf, rd, rn, left_shift);
10002 } else {
10003 sshll(vf, rd, rn, left_shift);
10004 }
10005 break;
10006 case NEON_USHLL:
10007 vf = vf_l;
10008 if (instr->Mask(NEON_Q)) {
10009 ushll2(vf, rd, rn, left_shift);
10010 } else {
10011 ushll(vf, rd, rn, left_shift);
10012 }
10013 break;
10014 case NEON_SHRN:
10015 if (instr->Mask(NEON_Q)) {
10016 shrn2(vf, rd, rn, right_shift);
10017 } else {
10018 shrn(vf, rd, rn, right_shift);
10019 }
10020 break;
10021 case NEON_RSHRN:
10022 if (instr->Mask(NEON_Q)) {
10023 rshrn2(vf, rd, rn, right_shift);
10024 } else {
10025 rshrn(vf, rd, rn, right_shift);
10026 }
10027 break;
10028 case NEON_UQSHRN:
10029 if (instr->Mask(NEON_Q)) {
10030 uqshrn2(vf, rd, rn, right_shift);
10031 } else {
10032 uqshrn(vf, rd, rn, right_shift);
10033 }
10034 break;
10035 case NEON_UQRSHRN:
10036 if (instr->Mask(NEON_Q)) {
10037 uqrshrn2(vf, rd, rn, right_shift);
10038 } else {
10039 uqrshrn(vf, rd, rn, right_shift);
10040 }
10041 break;
10042 case NEON_SQSHRN:
10043 if (instr->Mask(NEON_Q)) {
10044 sqshrn2(vf, rd, rn, right_shift);
10045 } else {
10046 sqshrn(vf, rd, rn, right_shift);
10047 }
10048 break;
10049 case NEON_SQRSHRN:
10050 if (instr->Mask(NEON_Q)) {
10051 sqrshrn2(vf, rd, rn, right_shift);
10052 } else {
10053 sqrshrn(vf, rd, rn, right_shift);
10054 }
10055 break;
10056 case NEON_SQSHRUN:
10057 if (instr->Mask(NEON_Q)) {
10058 sqshrun2(vf, rd, rn, right_shift);
10059 } else {
10060 sqshrun(vf, rd, rn, right_shift);
10061 }
10062 break;
10063 case NEON_SQRSHRUN:
10064 if (instr->Mask(NEON_Q)) {
10065 sqrshrun2(vf, rd, rn, right_shift);
10066 } else {
10067 sqrshrun(vf, rd, rn, right_shift);
10068 }
10069 break;
10070 default:
10071 VIXL_UNIMPLEMENTED();
10072 }
10073}
10074
10075
10076void Simulator::VisitNEONTable(const Instruction* instr) {
10077 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
10078 VectorFormat vf = nfd.GetVectorFormat();
10079
10080 SimVRegister& rd = ReadVRegister(instr->GetRd());
10081 SimVRegister& rn = ReadVRegister(instr->GetRn());
10082 SimVRegister& rn2 = ReadVRegister((instr->GetRn() + 1) % kNumberOfVRegisters);
10083 SimVRegister& rn3 = ReadVRegister((instr->GetRn() + 2) % kNumberOfVRegisters);
10084 SimVRegister& rn4 = ReadVRegister((instr->GetRn() + 3) % kNumberOfVRegisters);
10085 SimVRegister& rm = ReadVRegister(instr->GetRm());
10086
10087 switch (instr->Mask(NEONTableMask)) {
10088 case NEON_TBL_1v:
10089 tbl(vf, rd, rn, rm);
10090 break;
10091 case NEON_TBL_2v:
10092 tbl(vf, rd, rn, rn2, rm);
10093 break;
10094 case NEON_TBL_3v:
10095 tbl(vf, rd, rn, rn2, rn3, rm);
10096 break;
10097 case NEON_TBL_4v:
10098 tbl(vf, rd, rn, rn2, rn3, rn4, rm);
10099 break;
10100 case NEON_TBX_1v:
10101 tbx(vf, rd, rn, rm);
10102 break;
10103 case NEON_TBX_2v:
10104 tbx(vf, rd, rn, rn2, rm);
10105 break;
10106 case NEON_TBX_3v:
10107 tbx(vf, rd, rn, rn2, rn3, rm);
10108 break;
10109 case NEON_TBX_4v:
10110 tbx(vf, rd, rn, rn2, rn3, rn4, rm);
10111 break;
10112 default:
10113 VIXL_UNIMPLEMENTED();
10114 }
10115}
10116
10117
10118void Simulator::VisitNEONPerm(const Instruction* instr) {
10119 NEONFormatDecoder nfd(instr);
10120 VectorFormat vf = nfd.GetVectorFormat();
10121
10122 SimVRegister& rd = ReadVRegister(instr->GetRd());
10123 SimVRegister& rn = ReadVRegister(instr->GetRn());
10124 SimVRegister& rm = ReadVRegister(instr->GetRm());
10125
10126 switch (instr->Mask(NEONPermMask)) {
10127 case NEON_TRN1:
10128 trn1(vf, rd, rn, rm);
10129 break;
10130 case NEON_TRN2:
10131 trn2(vf, rd, rn, rm);
10132 break;
10133 case NEON_UZP1:
10134 uzp1(vf, rd, rn, rm);
10135 break;
10136 case NEON_UZP2:
10137 uzp2(vf, rd, rn, rm);
10138 break;
10139 case NEON_ZIP1:
10140 zip1(vf, rd, rn, rm);
10141 break;
10142 case NEON_ZIP2:
10143 zip2(vf, rd, rn, rm);
10144 break;
10145 default:
10146 VIXL_UNIMPLEMENTED();
10147 }
10148}
10149
mmc28af307b4a2024-06-20 14:28:41 +010010150void Simulator::SimulateNEONSHA3(const Instruction* instr) {
10151 SimVRegister& rd = ReadVRegister(instr->GetRd());
10152 SimVRegister& rn = ReadVRegister(instr->GetRn());
10153 SimVRegister& rm = ReadVRegister(instr->GetRm());
10154 SimVRegister& ra = ReadVRegister(instr->GetRa());
10155 SimVRegister temp;
10156
10157 switch (form_hash_) {
10158 case "bcax_vvv16_crypto4"_h:
10159 bic(kFormat16B, temp, rm, ra);
10160 eor(kFormat16B, rd, rn, temp);
10161 break;
10162 case "eor3_vvv16_crypto4"_h:
10163 eor(kFormat16B, temp, rm, ra);
10164 eor(kFormat16B, rd, rn, temp);
10165 break;
10166 case "rax1_vvv2_cryptosha512_3"_h:
10167 ror(kFormat2D, temp, rm, 63); // rol(1) => ror(63)
10168 eor(kFormat2D, rd, rn, temp);
10169 break;
10170 case "xar_vvv2_crypto3_imm6"_h:
10171 int rot = instr->ExtractBits(15, 10);
10172 eor(kFormat2D, temp, rn, rm);
10173 ror(kFormat2D, rd, temp, rot);
10174 break;
10175 }
10176}
10177
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010178void Simulator::VisitSVEAddressGeneration(const Instruction* instr) {
Martyn Capewell48522f52020-03-16 15:31:19 +000010179 SimVRegister& zd = ReadVRegister(instr->GetRd());
10180 SimVRegister& zn = ReadVRegister(instr->GetRn());
10181 SimVRegister& zm = ReadVRegister(instr->GetRm());
10182 SimVRegister temp;
10183
10184 VectorFormat vform = kFormatVnD;
10185 mov(vform, temp, zm);
10186
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010187 switch (instr->Mask(SVEAddressGenerationMask)) {
10188 case ADR_z_az_d_s32_scaled:
Martyn Capewell48522f52020-03-16 15:31:19 +000010189 sxt(vform, temp, temp, kSRegSize);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010190 break;
10191 case ADR_z_az_d_u32_scaled:
Martyn Capewell48522f52020-03-16 15:31:19 +000010192 uxt(vform, temp, temp, kSRegSize);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010193 break;
Martyn Capewell48522f52020-03-16 15:31:19 +000010194 case ADR_z_az_s_same_scaled:
10195 vform = kFormatVnS;
10196 break;
10197 case ADR_z_az_d_same_scaled:
10198 // Nothing to do.
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010199 break;
10200 default:
10201 VIXL_UNIMPLEMENTED();
10202 break;
10203 }
Martyn Capewell48522f52020-03-16 15:31:19 +000010204
10205 int shift_amount = instr->ExtractBits(11, 10);
10206 shl(vform, temp, temp, shift_amount);
10207 add(vform, zd, zn, temp);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010208}
10209
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010210void Simulator::VisitSVEBitwiseLogicalWithImm_Unpredicated(
10211 const Instruction* instr) {
10212 Instr op = instr->Mask(SVEBitwiseLogicalWithImm_UnpredicatedMask);
TatWai Chonga1885a52019-04-15 17:19:14 -070010213 switch (op) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010214 case AND_z_zi:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010215 case EOR_z_zi:
TatWai Chonga1885a52019-04-15 17:19:14 -070010216 case ORR_z_zi: {
10217 int lane_size = instr->GetSVEBitwiseImmLaneSizeInBytesLog2();
10218 uint64_t imm = instr->GetSVEImmLogical();
10219 // Valid immediate is a non-zero bits
10220 VIXL_ASSERT(imm != 0);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010221 SVEBitwiseImmHelper(static_cast<SVEBitwiseLogicalWithImm_UnpredicatedOp>(
10222 op),
TatWai Chonga1885a52019-04-15 17:19:14 -070010223 SVEFormatFromLaneSizeInBytesLog2(lane_size),
10224 ReadVRegister(instr->GetRd()),
10225 imm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010226 break;
TatWai Chonga1885a52019-04-15 17:19:14 -070010227 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010228 default:
10229 VIXL_UNIMPLEMENTED();
10230 break;
10231 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010232}
10233
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010234void Simulator::VisitSVEBroadcastBitmaskImm(const Instruction* instr) {
10235 switch (instr->Mask(SVEBroadcastBitmaskImmMask)) {
10236 case DUPM_z_i: {
10237 /* DUPM uses the same lane size and immediate encoding as bitwise logical
10238 * immediate instructions. */
10239 int lane_size = instr->GetSVEBitwiseImmLaneSizeInBytesLog2();
10240 uint64_t imm = instr->GetSVEImmLogical();
10241 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(lane_size);
10242 dup_immediate(vform, ReadVRegister(instr->GetRd()), imm);
10243 break;
10244 }
10245 default:
10246 VIXL_UNIMPLEMENTED();
10247 break;
10248 }
10249}
10250
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010251void Simulator::VisitSVEBitwiseLogicalUnpredicated(const Instruction* instr) {
TatWai Chongcfb94212019-05-16 13:30:09 -070010252 SimVRegister& zd = ReadVRegister(instr->GetRd());
10253 SimVRegister& zn = ReadVRegister(instr->GetRn());
10254 SimVRegister& zm = ReadVRegister(instr->GetRm());
10255 Instr op = instr->Mask(SVEBitwiseLogicalUnpredicatedMask);
10256
Martyn Capewelled5e03d2021-06-24 16:44:24 +010010257 LogicalOp logical_op = LogicalOpMask;
TatWai Chongcfb94212019-05-16 13:30:09 -070010258 switch (op) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010259 case AND_z_zz:
TatWai Chong13634762019-07-16 16:20:45 -070010260 logical_op = AND;
10261 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010262 case BIC_z_zz:
TatWai Chong13634762019-07-16 16:20:45 -070010263 logical_op = BIC;
10264 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010265 case EOR_z_zz:
TatWai Chong13634762019-07-16 16:20:45 -070010266 logical_op = EOR;
10267 break;
TatWai Chongcfb94212019-05-16 13:30:09 -070010268 case ORR_z_zz:
TatWai Chong13634762019-07-16 16:20:45 -070010269 logical_op = ORR;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010270 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010271 default:
10272 VIXL_UNIMPLEMENTED();
10273 break;
10274 }
TatWai Chong13634762019-07-16 16:20:45 -070010275 // Lane size of registers is irrelevant to the bitwise operations, so perform
10276 // the operation on D-sized lanes.
10277 SVEBitwiseLogicalUnpredicatedHelper(logical_op, kFormatVnD, zd, zn, zm);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010278}
10279
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010280void Simulator::VisitSVEBitwiseShiftByImm_Predicated(const Instruction* instr) {
Martyn Capewell83e86612020-02-19 15:46:15 +000010281 SimVRegister& zdn = ReadVRegister(instr->GetRd());
10282 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
10283
10284 SimVRegister scratch;
10285 SimVRegister result;
10286
10287 bool for_division = false;
10288 Shift shift_op = NO_SHIFT;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010289 switch (instr->Mask(SVEBitwiseShiftByImm_PredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010290 case ASRD_z_p_zi:
Martyn Capewell83e86612020-02-19 15:46:15 +000010291 shift_op = ASR;
10292 for_division = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010293 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010294 case ASR_z_p_zi:
Martyn Capewell83e86612020-02-19 15:46:15 +000010295 shift_op = ASR;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010296 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010297 case LSL_z_p_zi:
Martyn Capewell83e86612020-02-19 15:46:15 +000010298 shift_op = LSL;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010299 break;
10300 case LSR_z_p_zi:
Martyn Capewell83e86612020-02-19 15:46:15 +000010301 shift_op = LSR;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010302 break;
10303 default:
10304 VIXL_UNIMPLEMENTED();
10305 break;
10306 }
Martyn Capewell83e86612020-02-19 15:46:15 +000010307
10308 std::pair<int, int> shift_and_lane_size =
10309 instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ true);
10310 unsigned lane_size = shift_and_lane_size.second;
10311 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(lane_size);
10312 int shift_dist = shift_and_lane_size.first;
10313
10314 if ((shift_op == ASR) && for_division) {
10315 asrd(vform, result, zdn, shift_dist);
10316 } else {
10317 if (shift_op == LSL) {
10318 // Shift distance is computed differently for LSL. Convert the result.
10319 shift_dist = (8 << lane_size) - shift_dist;
10320 }
10321 dup_immediate(vform, scratch, shift_dist);
10322 SVEBitwiseShiftHelper(shift_op, vform, result, zdn, scratch, false);
10323 }
10324 mov_merging(vform, zdn, pg, result);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010325}
10326
10327void Simulator::VisitSVEBitwiseShiftByVector_Predicated(
10328 const Instruction* instr) {
Martyn Capewell76c094a2020-02-13 17:26:49 +000010329 VectorFormat vform = instr->GetSVEVectorFormat();
10330 SimVRegister& zdn = ReadVRegister(instr->GetRd());
10331 SimVRegister& zm = ReadVRegister(instr->GetRn());
10332 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
Martyn Capewell76c094a2020-02-13 17:26:49 +000010333 SimVRegister result;
Martyn Capewell76c094a2020-02-13 17:26:49 +000010334
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010335 // SVE uses the whole (saturated) lane for the shift amount.
10336 bool shift_in_ls_byte = false;
Martyn Capewell76c094a2020-02-13 17:26:49 +000010337
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010338 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +010010339 case "asrr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010340 sshr(vform, result, zm, zdn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010341 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010342 case "asr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010343 sshr(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010344 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010345 case "lslr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010346 sshl(vform, result, zm, zdn, shift_in_ls_byte);
10347 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010348 case "lsl_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010349 sshl(vform, result, zdn, zm, shift_in_ls_byte);
10350 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010351 case "lsrr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010352 ushr(vform, result, zm, zdn);
10353 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010354 case "lsr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010355 ushr(vform, result, zdn, zm);
10356 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010357 case "sqrshl_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010358 sshl(vform, result, zdn, zm, shift_in_ls_byte)
10359 .Round(vform)
10360 .SignedSaturate(vform);
10361 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010362 case "sqrshlr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010363 sshl(vform, result, zm, zdn, shift_in_ls_byte)
10364 .Round(vform)
10365 .SignedSaturate(vform);
10366 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010367 case "sqshl_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010368 sshl(vform, result, zdn, zm, shift_in_ls_byte).SignedSaturate(vform);
10369 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010370 case "sqshlr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010371 sshl(vform, result, zm, zdn, shift_in_ls_byte).SignedSaturate(vform);
10372 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010373 case "srshl_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010374 sshl(vform, result, zdn, zm, shift_in_ls_byte).Round(vform);
10375 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010376 case "srshlr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010377 sshl(vform, result, zm, zdn, shift_in_ls_byte).Round(vform);
10378 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010379 case "uqrshl_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010380 ushl(vform, result, zdn, zm, shift_in_ls_byte)
10381 .Round(vform)
10382 .UnsignedSaturate(vform);
10383 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010384 case "uqrshlr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010385 ushl(vform, result, zm, zdn, shift_in_ls_byte)
10386 .Round(vform)
10387 .UnsignedSaturate(vform);
10388 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010389 case "uqshl_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010390 ushl(vform, result, zdn, zm, shift_in_ls_byte).UnsignedSaturate(vform);
10391 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010392 case "uqshlr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010393 ushl(vform, result, zm, zdn, shift_in_ls_byte).UnsignedSaturate(vform);
10394 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010395 case "urshl_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010396 ushl(vform, result, zdn, zm, shift_in_ls_byte).Round(vform);
10397 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010010398 case "urshlr_z_p_zz"_h:
Martyn Capewell42bd8e92020-09-09 18:34:44 +010010399 ushl(vform, result, zm, zdn, shift_in_ls_byte).Round(vform);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010400 break;
10401 default:
10402 VIXL_UNIMPLEMENTED();
10403 break;
10404 }
Martyn Capewell76c094a2020-02-13 17:26:49 +000010405 mov_merging(vform, zdn, pg, result);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010406}
10407
10408void Simulator::VisitSVEBitwiseShiftByWideElements_Predicated(
10409 const Instruction* instr) {
Martyn Capewell76c094a2020-02-13 17:26:49 +000010410 VectorFormat vform = instr->GetSVEVectorFormat();
10411 SimVRegister& zdn = ReadVRegister(instr->GetRd());
10412 SimVRegister& zm = ReadVRegister(instr->GetRn());
10413 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
10414
10415 SimVRegister result;
10416 Shift shift_op = ASR;
10417
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010418 switch (instr->Mask(SVEBitwiseShiftByWideElements_PredicatedMask)) {
10419 case ASR_z_p_zw:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010420 break;
10421 case LSL_z_p_zw:
Martyn Capewell76c094a2020-02-13 17:26:49 +000010422 shift_op = LSL;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010423 break;
10424 case LSR_z_p_zw:
Martyn Capewell76c094a2020-02-13 17:26:49 +000010425 shift_op = LSR;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010426 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010427 default:
10428 VIXL_UNIMPLEMENTED();
10429 break;
10430 }
Martyn Capewell76c094a2020-02-13 17:26:49 +000010431 SVEBitwiseShiftHelper(shift_op,
10432 vform,
10433 result,
10434 zdn,
10435 zm,
10436 /* is_wide_elements = */ true);
10437 mov_merging(vform, zdn, pg, result);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010438}
10439
10440void Simulator::VisitSVEBitwiseShiftUnpredicated(const Instruction* instr) {
TatWai Chong29a0c432019-11-06 22:20:44 -080010441 SimVRegister& zd = ReadVRegister(instr->GetRd());
10442 SimVRegister& zn = ReadVRegister(instr->GetRn());
10443
Martyn Capewelled5e03d2021-06-24 16:44:24 +010010444 Shift shift_op = NO_SHIFT;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010445 switch (instr->Mask(SVEBitwiseShiftUnpredicatedMask)) {
10446 case ASR_z_zi:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010447 case ASR_z_zw:
TatWai Chong29a0c432019-11-06 22:20:44 -080010448 shift_op = ASR;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010449 break;
10450 case LSL_z_zi:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010451 case LSL_z_zw:
TatWai Chong29a0c432019-11-06 22:20:44 -080010452 shift_op = LSL;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010453 break;
10454 case LSR_z_zi:
TatWai Chong29a0c432019-11-06 22:20:44 -080010455 case LSR_z_zw:
10456 shift_op = LSR;
10457 break;
10458 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010459 VIXL_UNIMPLEMENTED();
10460 break;
TatWai Chong29a0c432019-11-06 22:20:44 -080010461 }
10462
10463 switch (instr->Mask(SVEBitwiseShiftUnpredicatedMask)) {
10464 case ASR_z_zi:
10465 case LSL_z_zi:
10466 case LSR_z_zi: {
10467 SimVRegister scratch;
10468 std::pair<int, int> shift_and_lane_size =
Martyn Capewell83e86612020-02-19 15:46:15 +000010469 instr->GetSVEImmShiftAndLaneSizeLog2(/* is_predicated = */ false);
TatWai Chong29a0c432019-11-06 22:20:44 -080010470 unsigned lane_size = shift_and_lane_size.second;
10471 VIXL_ASSERT(lane_size <= kDRegSizeInBytesLog2);
10472 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(lane_size);
Martyn Capewell147b0ba2020-02-19 11:16:02 +000010473 int shift_dist = shift_and_lane_size.first;
10474 if (shift_op == LSL) {
10475 // Shift distance is computed differently for LSL. Convert the result.
10476 shift_dist = (8 << lane_size) - shift_dist;
10477 }
10478 dup_immediate(vform, scratch, shift_dist);
TatWai Chong29a0c432019-11-06 22:20:44 -080010479 SVEBitwiseShiftHelper(shift_op, vform, zd, zn, scratch, false);
10480 break;
10481 }
10482 case ASR_z_zw:
10483 case LSL_z_zw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010484 case LSR_z_zw:
TatWai Chong29a0c432019-11-06 22:20:44 -080010485 SVEBitwiseShiftHelper(shift_op,
10486 instr->GetSVEVectorFormat(),
10487 zd,
10488 zn,
10489 ReadVRegister(instr->GetRm()),
10490 true);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010491 break;
10492 default:
10493 VIXL_UNIMPLEMENTED();
10494 break;
10495 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010496}
10497
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010498void Simulator::VisitSVEIncDecRegisterByElementCount(const Instruction* instr) {
Martyn Capewell579c92d2019-10-30 17:48:52 +000010499 // Although the instructions have a separate encoding class, the lane size is
10500 // encoded in the same way as most other SVE instructions.
10501 VectorFormat vform = instr->GetSVEVectorFormat();
10502
10503 int pattern = instr->GetImmSVEPredicateConstraint();
10504 int count = GetPredicateConstraintLaneCount(vform, pattern);
10505 int multiplier = instr->ExtractBits(19, 16) + 1;
10506
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010507 switch (instr->Mask(SVEIncDecRegisterByElementCountMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010508 case DECB_r_rs:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010509 case DECD_r_rs:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010510 case DECH_r_rs:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010511 case DECW_r_rs:
Martyn Capewell579c92d2019-10-30 17:48:52 +000010512 count = -count;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010513 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010514 case INCB_r_rs:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010515 case INCD_r_rs:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010516 case INCH_r_rs:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010517 case INCW_r_rs:
Martyn Capewell579c92d2019-10-30 17:48:52 +000010518 // Nothing to do.
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010519 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010520 default:
10521 VIXL_UNIMPLEMENTED();
Martyn Capewell579c92d2019-10-30 17:48:52 +000010522 return;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010523 }
Martyn Capewell579c92d2019-10-30 17:48:52 +000010524
10525 WriteXRegister(instr->GetRd(),
10526 IncDecN(ReadXRegister(instr->GetRd()),
10527 count * multiplier,
10528 kXRegSize));
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010529}
10530
10531void Simulator::VisitSVEIncDecVectorByElementCount(const Instruction* instr) {
Martyn Capewell8188ddf2019-11-21 17:09:34 +000010532 VectorFormat vform = instr->GetSVEVectorFormat();
10533 if (LaneSizeInBitsFromFormat(vform) == kBRegSize) {
10534 VIXL_UNIMPLEMENTED();
10535 }
10536
10537 int pattern = instr->GetImmSVEPredicateConstraint();
10538 int count = GetPredicateConstraintLaneCount(vform, pattern);
10539 int multiplier = instr->ExtractBits(19, 16) + 1;
10540
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010541 switch (instr->Mask(SVEIncDecVectorByElementCountMask)) {
10542 case DECD_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010543 case DECH_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010544 case DECW_z_zs:
Martyn Capewell8188ddf2019-11-21 17:09:34 +000010545 count = -count;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010546 break;
10547 case INCD_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010548 case INCH_z_zs:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010549 case INCW_z_zs:
Martyn Capewell8188ddf2019-11-21 17:09:34 +000010550 // Nothing to do.
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010551 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010552 default:
10553 VIXL_UNIMPLEMENTED();
10554 break;
10555 }
Martyn Capewell8188ddf2019-11-21 17:09:34 +000010556
10557 SimVRegister& zd = ReadVRegister(instr->GetRd());
10558 SimVRegister scratch;
10559 dup_immediate(vform,
10560 scratch,
10561 IncDecN(0,
10562 count * multiplier,
10563 LaneSizeInBitsFromFormat(vform)));
10564 add(vform, zd, zd, scratch);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010565}
10566
10567void Simulator::VisitSVESaturatingIncDecRegisterByElementCount(
10568 const Instruction* instr) {
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010569 // Although the instructions have a separate encoding class, the lane size is
10570 // encoded in the same way as most other SVE instructions.
10571 VectorFormat vform = instr->GetSVEVectorFormat();
10572
10573 int pattern = instr->GetImmSVEPredicateConstraint();
10574 int count = GetPredicateConstraintLaneCount(vform, pattern);
10575 int multiplier = instr->ExtractBits(19, 16) + 1;
10576
10577 unsigned width = kXRegSize;
10578 bool is_signed = false;
10579
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010580 switch (instr->Mask(SVESaturatingIncDecRegisterByElementCountMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010581 case SQDECB_r_rs_sx:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010582 case SQDECD_r_rs_sx:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010583 case SQDECH_r_rs_sx:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010584 case SQDECW_r_rs_sx:
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010585 width = kWRegSize;
10586 VIXL_FALLTHROUGH();
10587 case SQDECB_r_rs_x:
10588 case SQDECD_r_rs_x:
10589 case SQDECH_r_rs_x:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010590 case SQDECW_r_rs_x:
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010591 is_signed = true;
10592 count = -count;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010593 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010594 case SQINCB_r_rs_sx:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010595 case SQINCD_r_rs_sx:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010596 case SQINCH_r_rs_sx:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010597 case SQINCW_r_rs_sx:
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010598 width = kWRegSize;
10599 VIXL_FALLTHROUGH();
10600 case SQINCB_r_rs_x:
10601 case SQINCD_r_rs_x:
10602 case SQINCH_r_rs_x:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010603 case SQINCW_r_rs_x:
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010604 is_signed = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010605 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010606 case UQDECB_r_rs_uw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010607 case UQDECD_r_rs_uw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010608 case UQDECH_r_rs_uw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010609 case UQDECW_r_rs_uw:
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010610 width = kWRegSize;
10611 VIXL_FALLTHROUGH();
10612 case UQDECB_r_rs_x:
10613 case UQDECD_r_rs_x:
10614 case UQDECH_r_rs_x:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010615 case UQDECW_r_rs_x:
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010616 count = -count;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010617 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010618 case UQINCB_r_rs_uw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010619 case UQINCD_r_rs_uw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010620 case UQINCH_r_rs_uw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010621 case UQINCW_r_rs_uw:
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010622 width = kWRegSize;
10623 VIXL_FALLTHROUGH();
10624 case UQINCB_r_rs_x:
10625 case UQINCD_r_rs_x:
10626 case UQINCH_r_rs_x:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010627 case UQINCW_r_rs_x:
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010628 // Nothing to do.
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010629 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010630 default:
10631 VIXL_UNIMPLEMENTED();
10632 break;
10633 }
Martyn Capewell91d5ba32019-11-01 18:11:23 +000010634
10635 WriteXRegister(instr->GetRd(),
10636 IncDecN(ReadXRegister(instr->GetRd()),
10637 count * multiplier,
10638 width,
10639 true,
10640 is_signed));
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010641}
10642
10643void Simulator::VisitSVESaturatingIncDecVectorByElementCount(
10644 const Instruction* instr) {
Martyn Capewell8188ddf2019-11-21 17:09:34 +000010645 VectorFormat vform = instr->GetSVEVectorFormat();
10646 if (LaneSizeInBitsFromFormat(vform) == kBRegSize) {
10647 VIXL_UNIMPLEMENTED();
10648 }
10649
10650 int pattern = instr->GetImmSVEPredicateConstraint();
10651 int count = GetPredicateConstraintLaneCount(vform, pattern);
10652 int multiplier = instr->ExtractBits(19, 16) + 1;
10653
10654 SimVRegister& zd = ReadVRegister(instr->GetRd());
10655 SimVRegister scratch;
10656 dup_immediate(vform,
10657 scratch,
10658 IncDecN(0,
10659 count * multiplier,
10660 LaneSizeInBitsFromFormat(vform)));
10661
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010662 switch (instr->Mask(SVESaturatingIncDecVectorByElementCountMask)) {
10663 case SQDECD_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010664 case SQDECH_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010665 case SQDECW_z_zs:
Martyn Capewell8188ddf2019-11-21 17:09:34 +000010666 sub(vform, zd, zd, scratch).SignedSaturate(vform);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010667 break;
10668 case SQINCD_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010669 case SQINCH_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010670 case SQINCW_z_zs:
Martyn Capewell8188ddf2019-11-21 17:09:34 +000010671 add(vform, zd, zd, scratch).SignedSaturate(vform);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010672 break;
10673 case UQDECD_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010674 case UQDECH_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010675 case UQDECW_z_zs:
Martyn Capewell8188ddf2019-11-21 17:09:34 +000010676 sub(vform, zd, zd, scratch).UnsignedSaturate(vform);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010677 break;
10678 case UQINCD_z_zs:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010679 case UQINCH_z_zs:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010680 case UQINCW_z_zs:
Martyn Capewell8188ddf2019-11-21 17:09:34 +000010681 add(vform, zd, zd, scratch).UnsignedSaturate(vform);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010682 break;
10683 default:
10684 VIXL_UNIMPLEMENTED();
10685 break;
10686 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010687}
10688
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010689void Simulator::VisitSVEElementCount(const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010690 switch (instr->Mask(SVEElementCountMask)) {
10691 case CNTB_r_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010692 case CNTD_r_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010693 case CNTH_r_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010694 case CNTW_r_s:
Martyn Capewell74f84f62019-10-30 15:30:44 +000010695 // All handled below.
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010696 break;
10697 default:
10698 VIXL_UNIMPLEMENTED();
10699 break;
10700 }
Martyn Capewell74f84f62019-10-30 15:30:44 +000010701
10702 // Although the instructions are separated, the lane size is encoded in the
10703 // same way as most other SVE instructions.
10704 VectorFormat vform = instr->GetSVEVectorFormat();
10705
10706 int pattern = instr->GetImmSVEPredicateConstraint();
10707 int count = GetPredicateConstraintLaneCount(vform, pattern);
10708 int multiplier = instr->ExtractBits(19, 16) + 1;
10709 WriteXRegister(instr->GetRd(), count * multiplier);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010710}
10711
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010712void Simulator::VisitSVEFPAccumulatingReduction(const Instruction* instr) {
Martyn Capewell4a9829f2020-01-30 17:41:01 +000010713 VectorFormat vform = instr->GetSVEVectorFormat();
10714 SimVRegister& vdn = ReadVRegister(instr->GetRd());
10715 SimVRegister& zm = ReadVRegister(instr->GetRn());
10716 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
10717
Martyn Capewell310a0822020-09-08 20:09:17 +010010718 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
10719
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010720 switch (instr->Mask(SVEFPAccumulatingReductionMask)) {
10721 case FADDA_v_p_z:
Martyn Capewell4a9829f2020-01-30 17:41:01 +000010722 fadda(vform, vdn, pg, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010723 break;
10724 default:
10725 VIXL_UNIMPLEMENTED();
10726 break;
10727 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010728}
10729
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010730void Simulator::VisitSVEFPArithmetic_Predicated(const Instruction* instr) {
TatWai Chongd316c5e2019-10-16 12:22:10 -070010731 VectorFormat vform = instr->GetSVEVectorFormat();
10732 SimVRegister& zdn = ReadVRegister(instr->GetRd());
10733 SimVRegister& zm = ReadVRegister(instr->GetRn());
10734 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
10735
Martyn Capewell310a0822020-09-08 20:09:17 +010010736 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
TatWai Chongd316c5e2019-10-16 12:22:10 -070010737
Martyn Capewell310a0822020-09-08 20:09:17 +010010738 SimVRegister result;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010739 switch (instr->Mask(SVEFPArithmetic_PredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010740 case FABD_z_p_zz:
Martyn Capewell37f28182020-01-14 10:15:10 +000010741 fabd(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010742 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010743 case FADD_z_p_zz:
Martyn Capewell37f28182020-01-14 10:15:10 +000010744 fadd(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010745 break;
10746 case FDIVR_z_p_zz:
TatWai Chongd316c5e2019-10-16 12:22:10 -070010747 fdiv(vform, result, zm, zdn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010748 break;
10749 case FDIV_z_p_zz:
TatWai Chongd316c5e2019-10-16 12:22:10 -070010750 fdiv(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010751 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010752 case FMAXNM_z_p_zz:
Martyn Capewell37f28182020-01-14 10:15:10 +000010753 fmaxnm(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010754 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010755 case FMAX_z_p_zz:
TatWai Chong7a0d3672019-10-23 17:35:18 -070010756 fmax(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010757 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010758 case FMINNM_z_p_zz:
Martyn Capewell37f28182020-01-14 10:15:10 +000010759 fminnm(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010760 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010761 case FMIN_z_p_zz:
TatWai Chong7a0d3672019-10-23 17:35:18 -070010762 fmin(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010763 break;
10764 case FMULX_z_p_zz:
Martyn Capewell37f28182020-01-14 10:15:10 +000010765 fmulx(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010766 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010767 case FMUL_z_p_zz:
Martyn Capewell37f28182020-01-14 10:15:10 +000010768 fmul(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010769 break;
10770 case FSCALE_z_p_zz:
Martyn Capewell37f28182020-01-14 10:15:10 +000010771 fscale(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010772 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010773 case FSUBR_z_p_zz:
Martyn Capewell37f28182020-01-14 10:15:10 +000010774 fsub(vform, result, zm, zdn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010775 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010776 case FSUB_z_p_zz:
Martyn Capewell37f28182020-01-14 10:15:10 +000010777 fsub(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010778 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010779 default:
10780 VIXL_UNIMPLEMENTED();
10781 break;
10782 }
TatWai Chongd316c5e2019-10-16 12:22:10 -070010783 mov_merging(vform, zdn, pg, result);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010784}
10785
10786void Simulator::VisitSVEFPArithmeticWithImm_Predicated(
10787 const Instruction* instr) {
Martyn Capewella2fadc22020-01-16 16:09:55 +000010788 VectorFormat vform = instr->GetSVEVectorFormat();
10789 if (LaneSizeInBitsFromFormat(vform) == kBRegSize) {
10790 VIXL_UNIMPLEMENTED();
10791 }
10792
10793 SimVRegister& zdn = ReadVRegister(instr->GetRd());
10794 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
10795 SimVRegister result;
10796
10797 int i1 = instr->ExtractBit(5);
10798 SimVRegister add_sub_imm, min_max_imm, mul_imm;
10799 uint64_t half = FPToRawbitsWithSize(LaneSizeInBitsFromFormat(vform), 0.5);
10800 uint64_t one = FPToRawbitsWithSize(LaneSizeInBitsFromFormat(vform), 1.0);
10801 uint64_t two = FPToRawbitsWithSize(LaneSizeInBitsFromFormat(vform), 2.0);
10802 dup_immediate(vform, add_sub_imm, i1 ? one : half);
10803 dup_immediate(vform, min_max_imm, i1 ? one : 0);
10804 dup_immediate(vform, mul_imm, i1 ? two : half);
10805
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010806 switch (instr->Mask(SVEFPArithmeticWithImm_PredicatedMask)) {
10807 case FADD_z_p_zs:
Martyn Capewella2fadc22020-01-16 16:09:55 +000010808 fadd(vform, result, zdn, add_sub_imm);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010809 break;
10810 case FMAXNM_z_p_zs:
Martyn Capewella2fadc22020-01-16 16:09:55 +000010811 fmaxnm(vform, result, zdn, min_max_imm);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010812 break;
10813 case FMAX_z_p_zs:
Martyn Capewella2fadc22020-01-16 16:09:55 +000010814 fmax(vform, result, zdn, min_max_imm);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010815 break;
10816 case FMINNM_z_p_zs:
Martyn Capewella2fadc22020-01-16 16:09:55 +000010817 fminnm(vform, result, zdn, min_max_imm);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010818 break;
10819 case FMIN_z_p_zs:
Martyn Capewella2fadc22020-01-16 16:09:55 +000010820 fmin(vform, result, zdn, min_max_imm);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010821 break;
10822 case FMUL_z_p_zs:
Martyn Capewella2fadc22020-01-16 16:09:55 +000010823 fmul(vform, result, zdn, mul_imm);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010824 break;
10825 case FSUBR_z_p_zs:
Martyn Capewella2fadc22020-01-16 16:09:55 +000010826 fsub(vform, result, add_sub_imm, zdn);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010827 break;
10828 case FSUB_z_p_zs:
Martyn Capewella2fadc22020-01-16 16:09:55 +000010829 fsub(vform, result, zdn, add_sub_imm);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010830 break;
10831 default:
10832 VIXL_UNIMPLEMENTED();
10833 break;
10834 }
Martyn Capewella2fadc22020-01-16 16:09:55 +000010835 mov_merging(vform, zdn, pg, result);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010836}
10837
10838void Simulator::VisitSVEFPTrigMulAddCoefficient(const Instruction* instr) {
Martyn Capewell5fb2ad62020-01-10 14:08:27 +000010839 VectorFormat vform = instr->GetSVEVectorFormat();
10840 SimVRegister& zd = ReadVRegister(instr->GetRd());
10841 SimVRegister& zm = ReadVRegister(instr->GetRn());
10842
Martyn Capewell310a0822020-09-08 20:09:17 +010010843 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
10844
Martyn Capewelld255bdb2019-08-13 16:27:30 +010010845 switch (instr->Mask(SVEFPTrigMulAddCoefficientMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010846 case FTMAD_z_zzi:
Martyn Capewell5fb2ad62020-01-10 14:08:27 +000010847 ftmad(vform, zd, zd, zm, instr->ExtractBits(18, 16));
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010848 break;
10849 default:
10850 VIXL_UNIMPLEMENTED();
10851 break;
10852 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010853}
10854
10855void Simulator::VisitSVEFPArithmeticUnpredicated(const Instruction* instr) {
TatWai Chongfe536042019-10-23 16:34:11 -070010856 VectorFormat vform = instr->GetSVEVectorFormat();
10857 SimVRegister& zd = ReadVRegister(instr->GetRd());
10858 SimVRegister& zn = ReadVRegister(instr->GetRn());
10859 SimVRegister& zm = ReadVRegister(instr->GetRm());
10860
Martyn Capewell310a0822020-09-08 20:09:17 +010010861 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
10862
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010863 switch (instr->Mask(SVEFPArithmeticUnpredicatedMask)) {
10864 case FADD_z_zz:
TatWai Chongfe536042019-10-23 16:34:11 -070010865 fadd(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010866 break;
10867 case FMUL_z_zz:
TatWai Chongfe536042019-10-23 16:34:11 -070010868 fmul(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010869 break;
10870 case FRECPS_z_zz:
Martyn Capewellefd9dc72020-02-13 10:46:29 +000010871 frecps(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010872 break;
10873 case FRSQRTS_z_zz:
Martyn Capewellefd9dc72020-02-13 10:46:29 +000010874 frsqrts(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010875 break;
10876 case FSUB_z_zz:
TatWai Chongfe536042019-10-23 16:34:11 -070010877 fsub(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010878 break;
10879 case FTSMUL_z_zz:
Martyn Capewellefd9dc72020-02-13 10:46:29 +000010880 ftsmul(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010881 break;
10882 default:
10883 VIXL_UNIMPLEMENTED();
10884 break;
10885 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010886}
10887
10888void Simulator::VisitSVEFPCompareVectors(const Instruction* instr) {
TatWai Chong47c26842020-02-10 01:51:32 -080010889 SimPRegister& pd = ReadPRegister(instr->GetPd());
10890 SimVRegister& zn = ReadVRegister(instr->GetRn());
10891 SimVRegister& zm = ReadVRegister(instr->GetRm());
10892 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
10893 VectorFormat vform = instr->GetSVEVectorFormat();
10894 SimVRegister result;
10895
Martyn Capewell310a0822020-09-08 20:09:17 +010010896 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
10897
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010898 switch (instr->Mask(SVEFPCompareVectorsMask)) {
10899 case FACGE_p_p_zz:
TatWai Chong47c26842020-02-10 01:51:32 -080010900 fabscmp(vform, result, zn, zm, ge);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010901 break;
10902 case FACGT_p_p_zz:
TatWai Chong47c26842020-02-10 01:51:32 -080010903 fabscmp(vform, result, zn, zm, gt);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010904 break;
10905 case FCMEQ_p_p_zz:
TatWai Chong47c26842020-02-10 01:51:32 -080010906 fcmp(vform, result, zn, zm, eq);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010907 break;
10908 case FCMGE_p_p_zz:
TatWai Chong47c26842020-02-10 01:51:32 -080010909 fcmp(vform, result, zn, zm, ge);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010910 break;
10911 case FCMGT_p_p_zz:
TatWai Chong47c26842020-02-10 01:51:32 -080010912 fcmp(vform, result, zn, zm, gt);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010913 break;
10914 case FCMNE_p_p_zz:
TatWai Chong47c26842020-02-10 01:51:32 -080010915 fcmp(vform, result, zn, zm, ne);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010916 break;
10917 case FCMUO_p_p_zz:
TatWai Chong47c26842020-02-10 01:51:32 -080010918 fcmp(vform, result, zn, zm, uo);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010919 break;
10920 default:
10921 VIXL_UNIMPLEMENTED();
10922 break;
10923 }
TatWai Chong47c26842020-02-10 01:51:32 -080010924
10925 ExtractFromSimVRegister(vform, pd, result);
10926 mov_zeroing(pd, pg, pd);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010927}
10928
10929void Simulator::VisitSVEFPCompareWithZero(const Instruction* instr) {
TatWai Chonge3775132020-02-16 22:13:17 -080010930 SimPRegister& pd = ReadPRegister(instr->GetPd());
10931 SimVRegister& zn = ReadVRegister(instr->GetRn());
10932 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
10933 VectorFormat vform = instr->GetSVEVectorFormat();
TatWai Chonge3775132020-02-16 22:13:17 -080010934
Martyn Capewell310a0822020-09-08 20:09:17 +010010935 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
10936
10937 SimVRegister result;
TatWai Chonge3775132020-02-16 22:13:17 -080010938 SimVRegister zeros;
10939 dup_immediate(kFormatVnD, zeros, 0);
10940
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010941 switch (instr->Mask(SVEFPCompareWithZeroMask)) {
10942 case FCMEQ_p_p_z0:
TatWai Chonge3775132020-02-16 22:13:17 -080010943 fcmp(vform, result, zn, zeros, eq);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010944 break;
10945 case FCMGE_p_p_z0:
TatWai Chonge3775132020-02-16 22:13:17 -080010946 fcmp(vform, result, zn, zeros, ge);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010947 break;
10948 case FCMGT_p_p_z0:
TatWai Chonge3775132020-02-16 22:13:17 -080010949 fcmp(vform, result, zn, zeros, gt);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010950 break;
10951 case FCMLE_p_p_z0:
TatWai Chonge3775132020-02-16 22:13:17 -080010952 fcmp(vform, result, zn, zeros, le);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010953 break;
10954 case FCMLT_p_p_z0:
TatWai Chonge3775132020-02-16 22:13:17 -080010955 fcmp(vform, result, zn, zeros, lt);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010956 break;
10957 case FCMNE_p_p_z0:
TatWai Chonge3775132020-02-16 22:13:17 -080010958 fcmp(vform, result, zn, zeros, ne);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010959 break;
10960 default:
10961 VIXL_UNIMPLEMENTED();
10962 break;
10963 }
TatWai Chonge3775132020-02-16 22:13:17 -080010964
10965 ExtractFromSimVRegister(vform, pd, result);
10966 mov_zeroing(pd, pg, pd);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010967}
10968
10969void Simulator::VisitSVEFPComplexAddition(const Instruction* instr) {
Martyn Capewell0b1afa82020-03-04 11:31:42 +000010970 VectorFormat vform = instr->GetSVEVectorFormat();
10971
10972 if (LaneSizeInBitsFromFormat(vform) == kBRegSize) {
10973 VIXL_UNIMPLEMENTED();
10974 }
10975
10976 SimVRegister& zdn = ReadVRegister(instr->GetRd());
10977 SimVRegister& zm = ReadVRegister(instr->GetRn());
10978 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
10979 int rot = instr->ExtractBit(16);
10980
10981 SimVRegister result;
10982
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010983 switch (instr->Mask(SVEFPComplexAdditionMask)) {
10984 case FCADD_z_p_zz:
Martyn Capewell0b1afa82020-03-04 11:31:42 +000010985 fcadd(vform, result, zdn, zm, rot);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000010986 break;
10987 default:
10988 VIXL_UNIMPLEMENTED();
10989 break;
10990 }
Martyn Capewell0b1afa82020-03-04 11:31:42 +000010991 mov_merging(vform, zdn, pg, result);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000010992}
10993
10994void Simulator::VisitSVEFPComplexMulAdd(const Instruction* instr) {
Martyn Capewell75f1c432020-03-30 09:23:27 +010010995 VectorFormat vform = instr->GetSVEVectorFormat();
10996
10997 if (LaneSizeInBitsFromFormat(vform) == kBRegSize) {
10998 VIXL_UNIMPLEMENTED();
10999 }
11000
11001 SimVRegister& zda = ReadVRegister(instr->GetRd());
11002 SimVRegister& zn = ReadVRegister(instr->GetRn());
11003 SimVRegister& zm = ReadVRegister(instr->GetRm());
11004 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11005 int rot = instr->ExtractBits(14, 13);
11006
11007 SimVRegister result;
11008
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011009 switch (instr->Mask(SVEFPComplexMulAddMask)) {
11010 case FCMLA_z_p_zzz:
Martyn Capewell75f1c432020-03-30 09:23:27 +010011011 fcmla(vform, result, zn, zm, zda, rot);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011012 break;
11013 default:
11014 VIXL_UNIMPLEMENTED();
11015 break;
11016 }
Martyn Capewell75f1c432020-03-30 09:23:27 +010011017 mov_merging(vform, zda, pg, result);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011018}
11019
11020void Simulator::VisitSVEFPComplexMulAddIndex(const Instruction* instr) {
Martyn Capewelle4886e52020-03-30 09:28:52 +010011021 SimVRegister& zda = ReadVRegister(instr->GetRd());
11022 SimVRegister& zn = ReadVRegister(instr->GetRn());
11023 int rot = instr->ExtractBits(11, 10);
11024 unsigned zm_code = instr->GetRm();
11025 int index = -1;
11026 VectorFormat vform, vform_dup;
11027
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011028 switch (instr->Mask(SVEFPComplexMulAddIndexMask)) {
11029 case FCMLA_z_zzzi_h:
Martyn Capewelle4886e52020-03-30 09:28:52 +010011030 vform = kFormatVnH;
11031 vform_dup = kFormatVnS;
11032 index = zm_code >> 3;
11033 zm_code &= 0x7;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011034 break;
11035 case FCMLA_z_zzzi_s:
Martyn Capewelle4886e52020-03-30 09:28:52 +010011036 vform = kFormatVnS;
11037 vform_dup = kFormatVnD;
11038 index = zm_code >> 4;
11039 zm_code &= 0xf;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011040 break;
11041 default:
11042 VIXL_UNIMPLEMENTED();
11043 break;
11044 }
Martyn Capewelle4886e52020-03-30 09:28:52 +010011045
11046 if (index >= 0) {
11047 SimVRegister temp;
11048 dup_elements_to_segments(vform_dup, temp, ReadVRegister(zm_code), index);
11049 fcmla(vform, zda, zn, temp, zda, rot);
11050 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011051}
11052
Martyn Capewell894962f2020-02-05 15:46:44 +000011053typedef LogicVRegister (Simulator::*FastReduceFn)(VectorFormat vform,
11054 LogicVRegister dst,
11055 const LogicVRegister& src);
11056
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011057void Simulator::VisitSVEFPFastReduction(const Instruction* instr) {
Martyn Capewell894962f2020-02-05 15:46:44 +000011058 VectorFormat vform = instr->GetSVEVectorFormat();
11059 SimVRegister& vd = ReadVRegister(instr->GetRd());
11060 SimVRegister& zn = ReadVRegister(instr->GetRn());
11061 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11062 int lane_size = LaneSizeInBitsFromFormat(vform);
11063
11064 uint64_t inactive_value = 0;
11065 FastReduceFn fn = nullptr;
11066
Martyn Capewell310a0822020-09-08 20:09:17 +010011067 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
11068
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011069 switch (instr->Mask(SVEFPFastReductionMask)) {
11070 case FADDV_v_p_z:
Martyn Capewell894962f2020-02-05 15:46:44 +000011071 fn = &Simulator::faddv;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011072 break;
11073 case FMAXNMV_v_p_z:
Martyn Capewell894962f2020-02-05 15:46:44 +000011074 inactive_value = FPToRawbitsWithSize(lane_size, kFP64DefaultNaN);
11075 fn = &Simulator::fmaxnmv;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011076 break;
11077 case FMAXV_v_p_z:
Martyn Capewell894962f2020-02-05 15:46:44 +000011078 inactive_value = FPToRawbitsWithSize(lane_size, kFP64NegativeInfinity);
11079 fn = &Simulator::fmaxv;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011080 break;
11081 case FMINNMV_v_p_z:
Martyn Capewell894962f2020-02-05 15:46:44 +000011082 inactive_value = FPToRawbitsWithSize(lane_size, kFP64DefaultNaN);
11083 fn = &Simulator::fminnmv;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011084 break;
11085 case FMINV_v_p_z:
Martyn Capewell894962f2020-02-05 15:46:44 +000011086 inactive_value = FPToRawbitsWithSize(lane_size, kFP64PositiveInfinity);
11087 fn = &Simulator::fminv;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011088 break;
11089 default:
11090 VIXL_UNIMPLEMENTED();
11091 break;
11092 }
Martyn Capewell894962f2020-02-05 15:46:44 +000011093
11094 SimVRegister scratch;
11095 dup_immediate(vform, scratch, inactive_value);
11096 mov_merging(vform, scratch, pg, zn);
11097 if (fn != nullptr) (this->*fn)(vform, vd, scratch);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011098}
11099
11100void Simulator::VisitSVEFPMulIndex(const Instruction* instr) {
Martyn Capewell50e9f552020-01-07 17:45:03 +000011101 VectorFormat vform = kFormatUndefined;
Martyn Capewell50e9f552020-01-07 17:45:03 +000011102
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011103 switch (instr->Mask(SVEFPMulIndexMask)) {
11104 case FMUL_z_zzi_d:
Martyn Capewell50e9f552020-01-07 17:45:03 +000011105 vform = kFormatVnD;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011106 break;
Martyn Capewell50e9f552020-01-07 17:45:03 +000011107 case FMUL_z_zzi_h_i3h:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011108 case FMUL_z_zzi_h:
Martyn Capewell50e9f552020-01-07 17:45:03 +000011109 vform = kFormatVnH;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011110 break;
11111 case FMUL_z_zzi_s:
Martyn Capewell50e9f552020-01-07 17:45:03 +000011112 vform = kFormatVnS;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011113 break;
11114 default:
11115 VIXL_UNIMPLEMENTED();
11116 break;
11117 }
Martyn Capewell50e9f552020-01-07 17:45:03 +000011118
11119 SimVRegister& zd = ReadVRegister(instr->GetRd());
11120 SimVRegister& zn = ReadVRegister(instr->GetRn());
11121 SimVRegister temp;
11122
Martyn Capewellf272b9c2020-11-05 18:30:16 +000011123 dup_elements_to_segments(vform, temp, instr->GetSVEMulZmAndIndex());
Martyn Capewell50e9f552020-01-07 17:45:03 +000011124 fmul(vform, zd, zn, temp);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011125}
11126
11127void Simulator::VisitSVEFPMulAdd(const Instruction* instr) {
TatWai Chongf8d29f12020-02-16 22:53:18 -080011128 VectorFormat vform = instr->GetSVEVectorFormat();
TatWai Chongf8d29f12020-02-16 22:53:18 -080011129 SimVRegister& zd = ReadVRegister(instr->GetRd());
11130 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11131 SimVRegister result;
11132
Martyn Capewell310a0822020-09-08 20:09:17 +010011133 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
11134
TatWai Chongf8d29f12020-02-16 22:53:18 -080011135 if (instr->ExtractBit(15) == 0) {
11136 // Floating-point multiply-accumulate writing addend.
11137 SimVRegister& zm = ReadVRegister(instr->GetRm());
11138 SimVRegister& zn = ReadVRegister(instr->GetRn());
11139
11140 switch (instr->Mask(SVEFPMulAddMask)) {
11141 // zda = zda + zn * zm
11142 case FMLA_z_p_zzz:
11143 fmla(vform, result, zd, zn, zm);
11144 break;
11145 // zda = -zda + -zn * zm
11146 case FNMLA_z_p_zzz:
11147 fneg(vform, result, zd);
11148 fmls(vform, result, result, zn, zm);
11149 break;
11150 // zda = zda + -zn * zm
11151 case FMLS_z_p_zzz:
11152 fmls(vform, result, zd, zn, zm);
11153 break;
11154 // zda = -zda + zn * zm
11155 case FNMLS_z_p_zzz:
11156 fneg(vform, result, zd);
11157 fmla(vform, result, result, zn, zm);
11158 break;
11159 default:
11160 VIXL_UNIMPLEMENTED();
11161 break;
11162 }
11163 } else {
11164 // Floating-point multiply-accumulate writing multiplicand.
11165 SimVRegister& za = ReadVRegister(instr->GetRm());
11166 SimVRegister& zm = ReadVRegister(instr->GetRn());
11167
11168 switch (instr->Mask(SVEFPMulAddMask)) {
11169 // zdn = za + zdn * zm
11170 case FMAD_z_p_zzz:
11171 fmla(vform, result, za, zd, zm);
11172 break;
11173 // zdn = -za + -zdn * zm
11174 case FNMAD_z_p_zzz:
11175 fneg(vform, result, za);
11176 fmls(vform, result, result, zd, zm);
11177 break;
11178 // zdn = za + -zdn * zm
11179 case FMSB_z_p_zzz:
11180 fmls(vform, result, za, zd, zm);
11181 break;
11182 // zdn = -za + zdn * zm
11183 case FNMSB_z_p_zzz:
11184 fneg(vform, result, za);
11185 fmla(vform, result, result, zd, zm);
11186 break;
11187 default:
11188 VIXL_UNIMPLEMENTED();
11189 break;
11190 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011191 }
TatWai Chongf8d29f12020-02-16 22:53:18 -080011192
11193 mov_merging(vform, zd, pg, result);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011194}
11195
11196void Simulator::VisitSVEFPMulAddIndex(const Instruction* instr) {
TatWai Chonga2c1bb72020-02-16 23:16:47 -080011197 VectorFormat vform = kFormatUndefined;
TatWai Chonga2c1bb72020-02-16 23:16:47 -080011198
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011199 switch (instr->Mask(SVEFPMulAddIndexMask)) {
11200 case FMLA_z_zzzi_d:
TatWai Chonga2c1bb72020-02-16 23:16:47 -080011201 case FMLS_z_zzzi_d:
11202 vform = kFormatVnD;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011203 break;
11204 case FMLA_z_zzzi_s:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011205 case FMLS_z_zzzi_s:
TatWai Chonga2c1bb72020-02-16 23:16:47 -080011206 vform = kFormatVnS;
TatWai Chonga2c1bb72020-02-16 23:16:47 -080011207 break;
11208 case FMLA_z_zzzi_h:
11209 case FMLS_z_zzzi_h:
11210 case FMLA_z_zzzi_h_i3h:
11211 case FMLS_z_zzzi_h_i3h:
11212 vform = kFormatVnH;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011213 break;
11214 default:
11215 VIXL_UNIMPLEMENTED();
11216 break;
11217 }
TatWai Chonga2c1bb72020-02-16 23:16:47 -080011218
11219 SimVRegister& zd = ReadVRegister(instr->GetRd());
11220 SimVRegister& zn = ReadVRegister(instr->GetRn());
11221 SimVRegister temp;
11222
Martyn Capewellf272b9c2020-11-05 18:30:16 +000011223 dup_elements_to_segments(vform, temp, instr->GetSVEMulZmAndIndex());
TatWai Chonga2c1bb72020-02-16 23:16:47 -080011224 if (instr->ExtractBit(10) == 1) {
11225 fmls(vform, zd, zd, zn, temp);
11226 } else {
11227 fmla(vform, zd, zd, zn, temp);
11228 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011229}
11230
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011231void Simulator::VisitSVEFPConvertToInt(const Instruction* instr) {
TatWai Chongdb7437c2020-01-09 17:44:10 -080011232 SimVRegister& zd = ReadVRegister(instr->GetRd());
11233 SimVRegister& zn = ReadVRegister(instr->GetRn());
11234 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11235 int dst_data_size;
11236 int src_data_size;
11237
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011238 switch (instr->Mask(SVEFPConvertToIntMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011239 case FCVTZS_z_p_z_d2w:
TatWai Chongdb7437c2020-01-09 17:44:10 -080011240 case FCVTZU_z_p_z_d2w:
11241 dst_data_size = kSRegSize;
11242 src_data_size = kDRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011243 break;
11244 case FCVTZS_z_p_z_d2x:
TatWai Chongdb7437c2020-01-09 17:44:10 -080011245 case FCVTZU_z_p_z_d2x:
11246 dst_data_size = kDRegSize;
11247 src_data_size = kDRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011248 break;
11249 case FCVTZS_z_p_z_fp162h:
TatWai Chongdb7437c2020-01-09 17:44:10 -080011250 case FCVTZU_z_p_z_fp162h:
11251 dst_data_size = kHRegSize;
11252 src_data_size = kHRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011253 break;
11254 case FCVTZS_z_p_z_fp162w:
TatWai Chongdb7437c2020-01-09 17:44:10 -080011255 case FCVTZU_z_p_z_fp162w:
11256 dst_data_size = kSRegSize;
11257 src_data_size = kHRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011258 break;
11259 case FCVTZS_z_p_z_fp162x:
TatWai Chongdb7437c2020-01-09 17:44:10 -080011260 case FCVTZU_z_p_z_fp162x:
11261 dst_data_size = kDRegSize;
11262 src_data_size = kHRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011263 break;
11264 case FCVTZS_z_p_z_s2w:
TatWai Chongdb7437c2020-01-09 17:44:10 -080011265 case FCVTZU_z_p_z_s2w:
11266 dst_data_size = kSRegSize;
11267 src_data_size = kSRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011268 break;
11269 case FCVTZS_z_p_z_s2x:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011270 case FCVTZU_z_p_z_s2x:
TatWai Chongdb7437c2020-01-09 17:44:10 -080011271 dst_data_size = kDRegSize;
11272 src_data_size = kSRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011273 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011274 default:
11275 VIXL_UNIMPLEMENTED();
TatWai Chongdb7437c2020-01-09 17:44:10 -080011276 dst_data_size = 0;
11277 src_data_size = 0;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011278 break;
11279 }
TatWai Chongdb7437c2020-01-09 17:44:10 -080011280
11281 VectorFormat vform =
11282 SVEFormatFromLaneSizeInBits(std::max(dst_data_size, src_data_size));
TatWai Chongdb7437c2020-01-09 17:44:10 -080011283
11284 if (instr->ExtractBit(16) == 0) {
11285 fcvts(vform, dst_data_size, src_data_size, zd, pg, zn, FPZero);
11286 } else {
11287 fcvtu(vform, dst_data_size, src_data_size, zd, pg, zn, FPZero);
11288 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011289}
11290
11291void Simulator::VisitSVEFPConvertPrecision(const Instruction* instr) {
TatWai Chong2cb1b612020-03-04 23:51:21 -080011292 SimVRegister& zd = ReadVRegister(instr->GetRd());
11293 SimVRegister& zn = ReadVRegister(instr->GetRn());
11294 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
TatWai Chong58fecbd2021-03-30 14:38:31 -070011295 VectorFormat dst_data_size = kFormatUndefined;
11296 VectorFormat src_data_size = kFormatUndefined;
TatWai Chong2cb1b612020-03-04 23:51:21 -080011297
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011298 switch (instr->Mask(SVEFPConvertPrecisionMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011299 case FCVT_z_p_z_d2h:
TatWai Chong58fecbd2021-03-30 14:38:31 -070011300 dst_data_size = kFormatVnH;
11301 src_data_size = kFormatVnD;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011302 break;
11303 case FCVT_z_p_z_d2s:
TatWai Chong58fecbd2021-03-30 14:38:31 -070011304 dst_data_size = kFormatVnS;
11305 src_data_size = kFormatVnD;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011306 break;
11307 case FCVT_z_p_z_h2d:
TatWai Chong58fecbd2021-03-30 14:38:31 -070011308 dst_data_size = kFormatVnD;
11309 src_data_size = kFormatVnH;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011310 break;
11311 case FCVT_z_p_z_h2s:
TatWai Chong58fecbd2021-03-30 14:38:31 -070011312 dst_data_size = kFormatVnS;
11313 src_data_size = kFormatVnH;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011314 break;
11315 case FCVT_z_p_z_s2d:
TatWai Chong58fecbd2021-03-30 14:38:31 -070011316 dst_data_size = kFormatVnD;
11317 src_data_size = kFormatVnS;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011318 break;
11319 case FCVT_z_p_z_s2h:
TatWai Chong58fecbd2021-03-30 14:38:31 -070011320 dst_data_size = kFormatVnH;
11321 src_data_size = kFormatVnS;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011322 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011323 default:
11324 VIXL_UNIMPLEMENTED();
11325 break;
11326 }
TatWai Chong2cb1b612020-03-04 23:51:21 -080011327
TatWai Chong58fecbd2021-03-30 14:38:31 -070011328 fcvt(dst_data_size, src_data_size, zd, pg, zn);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011329}
11330
11331void Simulator::VisitSVEFPUnaryOp(const Instruction* instr) {
TatWai Chongf60f6dc2020-02-21 10:48:11 -080011332 SimVRegister& zd = ReadVRegister(instr->GetRd());
11333 SimVRegister& zn = ReadVRegister(instr->GetRn());
11334 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11335 VectorFormat vform = instr->GetSVEVectorFormat();
11336 SimVRegister result;
11337
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011338 switch (instr->Mask(SVEFPUnaryOpMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011339 case FRECPX_z_p_z:
TatWai Chongf60f6dc2020-02-21 10:48:11 -080011340 frecpx(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011341 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011342 case FSQRT_z_p_z:
TatWai Chongb4a25f62020-02-27 00:53:57 -080011343 fsqrt(vform, result, zn);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011344 break;
11345 default:
11346 VIXL_UNIMPLEMENTED();
11347 break;
11348 }
TatWai Chongf60f6dc2020-02-21 10:48:11 -080011349 mov_merging(vform, zd, pg, result);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011350}
11351
11352void Simulator::VisitSVEFPRoundToIntegralValue(const Instruction* instr) {
TatWai Chongf07b8ce2020-02-17 00:05:54 -080011353 SimVRegister& zd = ReadVRegister(instr->GetRd());
11354 SimVRegister& zn = ReadVRegister(instr->GetRn());
11355 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11356 VectorFormat vform = instr->GetSVEVectorFormat();
11357 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
11358 bool exact_exception = false;
11359
Martyn Capewell310a0822020-09-08 20:09:17 +010011360 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
11361
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011362 switch (instr->Mask(SVEFPRoundToIntegralValueMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011363 case FRINTA_z_p_z:
TatWai Chongf07b8ce2020-02-17 00:05:54 -080011364 fpcr_rounding = FPTieAway;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011365 break;
11366 case FRINTI_z_p_z:
TatWai Chongf07b8ce2020-02-17 00:05:54 -080011367 break; // Use FPCR rounding mode.
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011368 case FRINTM_z_p_z:
TatWai Chongf07b8ce2020-02-17 00:05:54 -080011369 fpcr_rounding = FPNegativeInfinity;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011370 break;
11371 case FRINTN_z_p_z:
TatWai Chongf07b8ce2020-02-17 00:05:54 -080011372 fpcr_rounding = FPTieEven;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011373 break;
11374 case FRINTP_z_p_z:
TatWai Chongf07b8ce2020-02-17 00:05:54 -080011375 fpcr_rounding = FPPositiveInfinity;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011376 break;
11377 case FRINTX_z_p_z:
TatWai Chongf07b8ce2020-02-17 00:05:54 -080011378 exact_exception = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011379 break;
11380 case FRINTZ_z_p_z:
TatWai Chongf07b8ce2020-02-17 00:05:54 -080011381 fpcr_rounding = FPZero;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011382 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011383 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011384 VIXL_UNIMPLEMENTED();
11385 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011386 }
TatWai Chongf07b8ce2020-02-17 00:05:54 -080011387
11388 SimVRegister result;
11389 frint(vform, result, zn, fpcr_rounding, exact_exception, kFrintToInteger);
11390 mov_merging(vform, zd, pg, result);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011391}
11392
11393void Simulator::VisitSVEIntConvertToFP(const Instruction* instr) {
TatWai Chong31cd6a02020-01-10 13:03:26 -080011394 SimVRegister& zd = ReadVRegister(instr->GetRd());
11395 SimVRegister& zn = ReadVRegister(instr->GetRn());
11396 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11397 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
11398 int dst_data_size;
11399 int src_data_size;
11400
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011401 switch (instr->Mask(SVEIntConvertToFPMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011402 case SCVTF_z_p_z_h2fp16:
TatWai Chong31cd6a02020-01-10 13:03:26 -080011403 case UCVTF_z_p_z_h2fp16:
11404 dst_data_size = kHRegSize;
11405 src_data_size = kHRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011406 break;
11407 case SCVTF_z_p_z_w2d:
TatWai Chong31cd6a02020-01-10 13:03:26 -080011408 case UCVTF_z_p_z_w2d:
11409 dst_data_size = kDRegSize;
11410 src_data_size = kSRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011411 break;
11412 case SCVTF_z_p_z_w2fp16:
TatWai Chong31cd6a02020-01-10 13:03:26 -080011413 case UCVTF_z_p_z_w2fp16:
11414 dst_data_size = kHRegSize;
11415 src_data_size = kSRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011416 break;
11417 case SCVTF_z_p_z_w2s:
TatWai Chong31cd6a02020-01-10 13:03:26 -080011418 case UCVTF_z_p_z_w2s:
11419 dst_data_size = kSRegSize;
11420 src_data_size = kSRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011421 break;
11422 case SCVTF_z_p_z_x2d:
TatWai Chong31cd6a02020-01-10 13:03:26 -080011423 case UCVTF_z_p_z_x2d:
11424 dst_data_size = kDRegSize;
11425 src_data_size = kDRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011426 break;
11427 case SCVTF_z_p_z_x2fp16:
TatWai Chong31cd6a02020-01-10 13:03:26 -080011428 case UCVTF_z_p_z_x2fp16:
11429 dst_data_size = kHRegSize;
11430 src_data_size = kDRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011431 break;
11432 case SCVTF_z_p_z_x2s:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011433 case UCVTF_z_p_z_x2s:
TatWai Chong31cd6a02020-01-10 13:03:26 -080011434 dst_data_size = kSRegSize;
11435 src_data_size = kDRegSize;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011436 break;
11437 default:
11438 VIXL_UNIMPLEMENTED();
TatWai Chong31cd6a02020-01-10 13:03:26 -080011439 dst_data_size = 0;
11440 src_data_size = 0;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011441 break;
11442 }
TatWai Chong31cd6a02020-01-10 13:03:26 -080011443
11444 VectorFormat vform =
11445 SVEFormatFromLaneSizeInBits(std::max(dst_data_size, src_data_size));
11446
11447 if (instr->ExtractBit(16) == 0) {
11448 scvtf(vform, dst_data_size, src_data_size, zd, pg, zn, fpcr_rounding);
11449 } else {
11450 ucvtf(vform, dst_data_size, src_data_size, zd, pg, zn, fpcr_rounding);
11451 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011452}
11453
11454void Simulator::VisitSVEFPUnaryOpUnpredicated(const Instruction* instr) {
Martyn Capewell13050ca2020-02-11 16:43:40 +000011455 VectorFormat vform = instr->GetSVEVectorFormat();
11456 SimVRegister& zd = ReadVRegister(instr->GetRd());
11457 SimVRegister& zn = ReadVRegister(instr->GetRn());
11458 FPRounding fpcr_rounding = static_cast<FPRounding>(ReadFpcr().GetRMode());
11459
Martyn Capewell310a0822020-09-08 20:09:17 +010011460 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
11461
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011462 switch (instr->Mask(SVEFPUnaryOpUnpredicatedMask)) {
11463 case FRECPE_z_z:
Martyn Capewell13050ca2020-02-11 16:43:40 +000011464 frecpe(vform, zd, zn, fpcr_rounding);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011465 break;
11466 case FRSQRTE_z_z:
Martyn Capewell13050ca2020-02-11 16:43:40 +000011467 frsqrte(vform, zd, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011468 break;
11469 default:
11470 VIXL_UNIMPLEMENTED();
11471 break;
11472 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011473}
11474
11475void Simulator::VisitSVEIncDecByPredicateCount(const Instruction* instr) {
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011476 VectorFormat vform = instr->GetSVEVectorFormat();
11477 SimPRegister& pg = ReadPRegister(instr->ExtractBits(8, 5));
11478
11479 int count = CountActiveLanes(vform, pg);
11480
11481 if (instr->ExtractBit(11) == 0) {
11482 SimVRegister& zdn = ReadVRegister(instr->GetRd());
11483 switch (instr->Mask(SVEIncDecByPredicateCountMask)) {
11484 case DECP_z_p_z:
Jacob Bramleyb28f6172019-10-02 12:12:35 +010011485 sub_uint(vform, zdn, zdn, count);
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011486 break;
11487 case INCP_z_p_z:
Jacob Bramleyb28f6172019-10-02 12:12:35 +010011488 add_uint(vform, zdn, zdn, count);
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011489 break;
11490 case SQDECP_z_p_z:
Jacob Bramleyb28f6172019-10-02 12:12:35 +010011491 sub_uint(vform, zdn, zdn, count).SignedSaturate(vform);
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011492 break;
11493 case SQINCP_z_p_z:
Jacob Bramleyb28f6172019-10-02 12:12:35 +010011494 add_uint(vform, zdn, zdn, count).SignedSaturate(vform);
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011495 break;
11496 case UQDECP_z_p_z:
Jacob Bramleyb28f6172019-10-02 12:12:35 +010011497 sub_uint(vform, zdn, zdn, count).UnsignedSaturate(vform);
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011498 break;
11499 case UQINCP_z_p_z:
Jacob Bramleyb28f6172019-10-02 12:12:35 +010011500 add_uint(vform, zdn, zdn, count).UnsignedSaturate(vform);
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011501 break;
11502 default:
11503 VIXL_UNIMPLEMENTED();
11504 break;
11505 }
11506 } else {
11507 bool is_saturating = (instr->ExtractBit(18) == 0);
11508 bool decrement =
11509 is_saturating ? instr->ExtractBit(17) : instr->ExtractBit(16);
11510 bool is_signed = (instr->ExtractBit(16) == 0);
11511 bool sf = is_saturating ? (instr->ExtractBit(10) != 0) : true;
11512 unsigned width = sf ? kXRegSize : kWRegSize;
11513
11514 switch (instr->Mask(SVEIncDecByPredicateCountMask)) {
11515 case DECP_r_p_r:
11516 case INCP_r_p_r:
11517 case SQDECP_r_p_r_sx:
11518 case SQDECP_r_p_r_x:
11519 case SQINCP_r_p_r_sx:
11520 case SQINCP_r_p_r_x:
11521 case UQDECP_r_p_r_uw:
11522 case UQDECP_r_p_r_x:
11523 case UQINCP_r_p_r_uw:
11524 case UQINCP_r_p_r_x:
11525 WriteXRegister(instr->GetRd(),
11526 IncDecN(ReadXRegister(instr->GetRd()),
11527 decrement ? -count : count,
11528 width,
11529 is_saturating,
11530 is_signed));
11531 break;
11532 default:
11533 VIXL_UNIMPLEMENTED();
11534 break;
11535 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011536 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011537}
11538
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011539uint64_t Simulator::IncDecN(uint64_t acc,
11540 int64_t delta,
11541 unsigned n,
11542 bool is_saturating,
11543 bool is_signed) {
11544 VIXL_ASSERT(n <= 64);
11545 VIXL_ASSERT(IsIntN(n, delta));
11546
11547 uint64_t sign_mask = UINT64_C(1) << (n - 1);
11548 uint64_t mask = GetUintMask(n);
11549
11550 acc &= mask; // Ignore initial accumulator high bits.
11551 uint64_t result = (acc + delta) & mask;
11552
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011553 bool result_negative = ((result & sign_mask) != 0);
11554
11555 if (is_saturating) {
11556 if (is_signed) {
Martyn Capewell8188ddf2019-11-21 17:09:34 +000011557 bool acc_negative = ((acc & sign_mask) != 0);
11558 bool delta_negative = delta < 0;
11559
Jacob Bramleyd1686cb2019-05-28 17:39:05 +010011560 // If the signs of the operands are the same, but different from the
11561 // result, there was an overflow.
11562 if ((acc_negative == delta_negative) &&
11563 (acc_negative != result_negative)) {
11564 if (result_negative) {
11565 // Saturate to [..., INT<n>_MAX].
11566 result_negative = false;
11567 result = mask & ~sign_mask; // E.g. 0x000000007fffffff
11568 } else {
11569 // Saturate to [INT<n>_MIN, ...].
11570 result_negative = true;
11571 result = ~mask | sign_mask; // E.g. 0xffffffff80000000
11572 }
11573 }
11574 } else {
11575 if ((delta < 0) && (result > acc)) {
11576 // Saturate to [0, ...].
11577 result = 0;
11578 } else if ((delta > 0) && (result < acc)) {
11579 // Saturate to [..., UINT<n>_MAX].
11580 result = mask;
11581 }
11582 }
11583 }
11584
11585 // Sign-extend if necessary.
11586 if (result_negative && is_signed) result |= ~mask;
11587
11588 return result;
11589}
11590
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011591void Simulator::VisitSVEIndexGeneration(const Instruction* instr) {
Jacob Bramleycd8148c2019-07-11 18:43:20 +010011592 VectorFormat vform = instr->GetSVEVectorFormat();
11593 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011594 switch (instr->Mask(SVEIndexGenerationMask)) {
11595 case INDEX_z_ii:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011596 case INDEX_z_ir:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011597 case INDEX_z_ri:
Jacob Bramleycd8148c2019-07-11 18:43:20 +010011598 case INDEX_z_rr: {
11599 uint64_t start = instr->ExtractBit(10) ? ReadXRegister(instr->GetRn())
11600 : instr->ExtractSignedBits(9, 5);
11601 uint64_t step = instr->ExtractBit(11) ? ReadXRegister(instr->GetRm())
11602 : instr->ExtractSignedBits(20, 16);
11603 index(vform, zd, start, step);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011604 break;
Jacob Bramleycd8148c2019-07-11 18:43:20 +010011605 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011606 default:
11607 VIXL_UNIMPLEMENTED();
11608 break;
11609 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011610}
11611
11612void Simulator::VisitSVEIntArithmeticUnpredicated(const Instruction* instr) {
TatWai Chong845246b2019-08-08 00:01:58 -070011613 VectorFormat vform = instr->GetSVEVectorFormat();
11614 SimVRegister& zd = ReadVRegister(instr->GetRd());
11615 SimVRegister& zn = ReadVRegister(instr->GetRn());
11616 SimVRegister& zm = ReadVRegister(instr->GetRm());
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011617 switch (instr->Mask(SVEIntArithmeticUnpredicatedMask)) {
11618 case ADD_z_zz:
TatWai Chong845246b2019-08-08 00:01:58 -070011619 add(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011620 break;
11621 case SQADD_z_zz:
TatWai Chong845246b2019-08-08 00:01:58 -070011622 add(vform, zd, zn, zm).SignedSaturate(vform);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011623 break;
11624 case SQSUB_z_zz:
TatWai Chong845246b2019-08-08 00:01:58 -070011625 sub(vform, zd, zn, zm).SignedSaturate(vform);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011626 break;
11627 case SUB_z_zz:
TatWai Chong845246b2019-08-08 00:01:58 -070011628 sub(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011629 break;
11630 case UQADD_z_zz:
TatWai Chong845246b2019-08-08 00:01:58 -070011631 add(vform, zd, zn, zm).UnsignedSaturate(vform);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011632 break;
11633 case UQSUB_z_zz:
TatWai Chong845246b2019-08-08 00:01:58 -070011634 sub(vform, zd, zn, zm).UnsignedSaturate(vform);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011635 break;
11636 default:
11637 VIXL_UNIMPLEMENTED();
11638 break;
11639 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011640}
11641
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011642void Simulator::VisitSVEIntAddSubtractVectors_Predicated(
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011643 const Instruction* instr) {
TatWai Chong13634762019-07-16 16:20:45 -070011644 VectorFormat vform = instr->GetSVEVectorFormat();
11645 SimVRegister& zdn = ReadVRegister(instr->GetRd());
11646 SimVRegister& zm = ReadVRegister(instr->GetRn());
11647 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11648 SimVRegister result;
11649
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011650 switch (instr->Mask(SVEIntAddSubtractVectors_PredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011651 case ADD_z_p_zz:
TatWai Chong13634762019-07-16 16:20:45 -070011652 add(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011653 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011654 case SUBR_z_p_zz:
11655 sub(vform, result, zm, zdn);
11656 break;
11657 case SUB_z_p_zz:
11658 sub(vform, result, zdn, zm);
11659 break;
11660 default:
11661 VIXL_UNIMPLEMENTED();
11662 break;
11663 }
11664 mov_merging(vform, zdn, pg, result);
11665}
11666
11667void Simulator::VisitSVEBitwiseLogical_Predicated(const Instruction* instr) {
11668 VectorFormat vform = instr->GetSVEVectorFormat();
11669 SimVRegister& zdn = ReadVRegister(instr->GetRd());
11670 SimVRegister& zm = ReadVRegister(instr->GetRn());
11671 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11672 SimVRegister result;
11673
11674 switch (instr->Mask(SVEBitwiseLogical_PredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011675 case AND_z_p_zz:
TatWai Chong13634762019-07-16 16:20:45 -070011676 SVEBitwiseLogicalUnpredicatedHelper(AND, vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011677 break;
11678 case BIC_z_p_zz:
TatWai Chong13634762019-07-16 16:20:45 -070011679 SVEBitwiseLogicalUnpredicatedHelper(BIC, vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011680 break;
11681 case EOR_z_p_zz:
TatWai Chong13634762019-07-16 16:20:45 -070011682 SVEBitwiseLogicalUnpredicatedHelper(EOR, vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011683 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011684 case ORR_z_p_zz:
TatWai Chong13634762019-07-16 16:20:45 -070011685 SVEBitwiseLogicalUnpredicatedHelper(ORR, vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011686 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011687 default:
11688 VIXL_UNIMPLEMENTED();
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011689 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011690 }
11691 mov_merging(vform, zdn, pg, result);
11692}
11693
11694void Simulator::VisitSVEIntMulVectors_Predicated(const Instruction* instr) {
11695 VectorFormat vform = instr->GetSVEVectorFormat();
11696 SimVRegister& zdn = ReadVRegister(instr->GetRd());
11697 SimVRegister& zm = ReadVRegister(instr->GetRn());
11698 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11699 SimVRegister result;
11700
11701 switch (instr->Mask(SVEIntMulVectors_PredicatedMask)) {
11702 case MUL_z_p_zz:
11703 mul(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011704 break;
11705 case SMULH_z_p_zz:
TatWai Chong13634762019-07-16 16:20:45 -070011706 smulh(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011707 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011708 case UMULH_z_p_zz:
TatWai Chong13634762019-07-16 16:20:45 -070011709 umulh(vform, result, zdn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011710 break;
11711 default:
11712 VIXL_UNIMPLEMENTED();
11713 break;
11714 }
TatWai Chong13634762019-07-16 16:20:45 -070011715 mov_merging(vform, zdn, pg, result);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011716}
11717
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011718void Simulator::VisitSVEIntMinMaxDifference_Predicated(
11719 const Instruction* instr) {
11720 VectorFormat vform = instr->GetSVEVectorFormat();
11721 SimVRegister& zdn = ReadVRegister(instr->GetRd());
11722 SimVRegister& zm = ReadVRegister(instr->GetRn());
11723 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11724 SimVRegister result;
11725
11726 switch (instr->Mask(SVEIntMinMaxDifference_PredicatedMask)) {
11727 case SABD_z_p_zz:
11728 absdiff(vform, result, zdn, zm, true);
11729 break;
11730 case SMAX_z_p_zz:
11731 smax(vform, result, zdn, zm);
11732 break;
11733 case SMIN_z_p_zz:
11734 smin(vform, result, zdn, zm);
11735 break;
11736 case UABD_z_p_zz:
11737 absdiff(vform, result, zdn, zm, false);
11738 break;
11739 case UMAX_z_p_zz:
11740 umax(vform, result, zdn, zm);
11741 break;
11742 case UMIN_z_p_zz:
11743 umin(vform, result, zdn, zm);
11744 break;
11745 default:
11746 VIXL_UNIMPLEMENTED();
11747 break;
11748 }
11749 mov_merging(vform, zdn, pg, result);
11750}
11751
11752void Simulator::VisitSVEIntMulImm_Unpredicated(const Instruction* instr) {
11753 VectorFormat vform = instr->GetSVEVectorFormat();
11754 SimVRegister& zd = ReadVRegister(instr->GetRd());
11755 SimVRegister scratch;
11756
11757 switch (instr->Mask(SVEIntMulImm_UnpredicatedMask)) {
11758 case MUL_z_zi:
11759 dup_immediate(vform, scratch, instr->GetImmSVEIntWideSigned());
11760 mul(vform, zd, zd, scratch);
11761 break;
11762 default:
11763 VIXL_UNIMPLEMENTED();
11764 break;
11765 }
11766}
11767
11768void Simulator::VisitSVEIntDivideVectors_Predicated(const Instruction* instr) {
11769 VectorFormat vform = instr->GetSVEVectorFormat();
11770 SimVRegister& zdn = ReadVRegister(instr->GetRd());
11771 SimVRegister& zm = ReadVRegister(instr->GetRn());
11772 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
11773 SimVRegister result;
11774
11775 VIXL_ASSERT((vform == kFormatVnS) || (vform == kFormatVnD));
11776
11777 switch (instr->Mask(SVEIntDivideVectors_PredicatedMask)) {
11778 case SDIVR_z_p_zz:
11779 sdiv(vform, result, zm, zdn);
11780 break;
11781 case SDIV_z_p_zz:
11782 sdiv(vform, result, zdn, zm);
11783 break;
11784 case UDIVR_z_p_zz:
11785 udiv(vform, result, zm, zdn);
11786 break;
11787 case UDIV_z_p_zz:
11788 udiv(vform, result, zdn, zm);
11789 break;
11790 default:
11791 VIXL_UNIMPLEMENTED();
11792 break;
11793 }
11794 mov_merging(vform, zdn, pg, result);
11795}
11796
11797void Simulator::VisitSVEIntMinMaxImm_Unpredicated(const Instruction* instr) {
11798 VectorFormat vform = instr->GetSVEVectorFormat();
11799 SimVRegister& zd = ReadVRegister(instr->GetRd());
11800 SimVRegister scratch;
11801
11802 uint64_t unsigned_imm = instr->GetImmSVEIntWideUnsigned();
11803 int64_t signed_imm = instr->GetImmSVEIntWideSigned();
11804
11805 switch (instr->Mask(SVEIntMinMaxImm_UnpredicatedMask)) {
11806 case SMAX_z_zi:
11807 dup_immediate(vform, scratch, signed_imm);
11808 smax(vform, zd, zd, scratch);
11809 break;
11810 case SMIN_z_zi:
11811 dup_immediate(vform, scratch, signed_imm);
11812 smin(vform, zd, zd, scratch);
11813 break;
11814 case UMAX_z_zi:
11815 dup_immediate(vform, scratch, unsigned_imm);
11816 umax(vform, zd, zd, scratch);
11817 break;
11818 case UMIN_z_zi:
11819 dup_immediate(vform, scratch, unsigned_imm);
11820 umin(vform, zd, zd, scratch);
11821 break;
11822 default:
11823 VIXL_UNIMPLEMENTED();
11824 break;
11825 }
11826}
11827
11828void Simulator::VisitSVEIntCompareScalarCountAndLimit(
11829 const Instruction* instr) {
TatWai Chongc844bb22019-06-10 15:32:53 -070011830 unsigned rn_code = instr->GetRn();
11831 unsigned rm_code = instr->GetRm();
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011832 SimPRegister& pd = ReadPRegister(instr->GetPd());
11833 VectorFormat vform = instr->GetSVEVectorFormat();
TatWai Chongc844bb22019-06-10 15:32:53 -070011834
Martyn Capewellf0844012020-10-23 16:38:26 +010011835 bool is_64_bit = instr->ExtractBit(12) == 1;
11836 int rsize = is_64_bit ? kXRegSize : kWRegSize;
11837 uint64_t mask = is_64_bit ? kXRegMask : kWRegMask;
11838
11839 uint64_t usrc1 = ReadXRegister(rn_code);
11840 int64_t ssrc2 = is_64_bit ? ReadXRegister(rm_code) : ReadWRegister(rm_code);
11841 uint64_t usrc2 = ssrc2 & mask;
11842
Martyn Capewelld48909d2022-05-03 16:38:38 +010011843 bool reverse = (form_hash_ == "whilege_p_p_rr"_h) ||
11844 (form_hash_ == "whilegt_p_p_rr"_h) ||
11845 (form_hash_ == "whilehi_p_p_rr"_h) ||
11846 (form_hash_ == "whilehs_p_p_rr"_h);
Martyn Capewellf0844012020-10-23 16:38:26 +010011847
11848 int lane_count = LaneCountFromFormat(vform);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011849 bool last = true;
Martyn Capewellf0844012020-10-23 16:38:26 +010011850 for (int i = 0; i < lane_count; i++) {
11851 usrc1 &= mask;
11852 int64_t ssrc1 = ExtractSignedBitfield64(rsize - 1, 0, usrc1);
11853
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011854 bool cond = false;
Martyn Capewellf0844012020-10-23 16:38:26 +010011855 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +010011856 case "whilele_p_p_rr"_h:
Martyn Capewellf0844012020-10-23 16:38:26 +010011857 cond = ssrc1 <= ssrc2;
TatWai Chongc844bb22019-06-10 15:32:53 -070011858 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010011859 case "whilelo_p_p_rr"_h:
Martyn Capewellf0844012020-10-23 16:38:26 +010011860 cond = usrc1 < usrc2;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011861 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010011862 case "whilels_p_p_rr"_h:
Martyn Capewellf0844012020-10-23 16:38:26 +010011863 cond = usrc1 <= usrc2;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011864 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010011865 case "whilelt_p_p_rr"_h:
Martyn Capewellf0844012020-10-23 16:38:26 +010011866 cond = ssrc1 < ssrc2;
11867 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010011868 case "whilege_p_p_rr"_h:
Martyn Capewellf0844012020-10-23 16:38:26 +010011869 cond = ssrc1 >= ssrc2;
11870 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010011871 case "whilegt_p_p_rr"_h:
Martyn Capewellf0844012020-10-23 16:38:26 +010011872 cond = ssrc1 > ssrc2;
11873 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010011874 case "whilehi_p_p_rr"_h:
Martyn Capewellf0844012020-10-23 16:38:26 +010011875 cond = usrc1 > usrc2;
11876 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010011877 case "whilehs_p_p_rr"_h:
Martyn Capewellf0844012020-10-23 16:38:26 +010011878 cond = usrc1 >= usrc2;
TatWai Chongc844bb22019-06-10 15:32:53 -070011879 break;
11880 default:
TatWai Chongc844bb22019-06-10 15:32:53 -070011881 VIXL_UNIMPLEMENTED();
11882 break;
11883 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011884 last = last && cond;
11885 LogicPRegister dst(pd);
Martyn Capewellf0844012020-10-23 16:38:26 +010011886 int lane = reverse ? ((lane_count - 1) - i) : i;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011887 dst.SetActive(vform, lane, last);
Martyn Capewellf0844012020-10-23 16:38:26 +010011888 usrc1 += reverse ? -1 : 1;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011889 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011890
11891 PredTest(vform, GetPTrue(), pd);
11892 LogSystemRegister(NZCV);
11893}
11894
11895void Simulator::VisitSVEConditionallyTerminateScalars(
11896 const Instruction* instr) {
11897 unsigned rn_code = instr->GetRn();
11898 unsigned rm_code = instr->GetRm();
11899 bool is_64_bit = instr->ExtractBit(22) == 1;
11900 uint64_t src1 = is_64_bit ? ReadXRegister(rn_code) : ReadWRegister(rn_code);
11901 uint64_t src2 = is_64_bit ? ReadXRegister(rm_code) : ReadWRegister(rm_code);
Martyn Capewelled5e03d2021-06-24 16:44:24 +010011902 bool term = false;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011903 switch (instr->Mask(SVEConditionallyTerminateScalarsMask)) {
11904 case CTERMEQ_rr:
11905 term = src1 == src2;
11906 break;
11907 case CTERMNE_rr:
11908 term = src1 != src2;
11909 break;
11910 default:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010011911 VIXL_UNIMPLEMENTED();
11912 break;
11913 }
11914 ReadNzcv().SetN(term ? 1 : 0);
11915 ReadNzcv().SetV(term ? 0 : !ReadC());
TatWai Chongc844bb22019-06-10 15:32:53 -070011916 LogSystemRegister(NZCV);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011917}
11918
11919void Simulator::VisitSVEIntCompareSignedImm(const Instruction* instr) {
TatWai Chong302729c2019-06-14 16:18:51 -070011920 bool commute_inputs = false;
Martyn Capewelled5e03d2021-06-24 16:44:24 +010011921 Condition cond = al;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011922 switch (instr->Mask(SVEIntCompareSignedImmMask)) {
11923 case CMPEQ_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011924 cond = eq;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011925 break;
11926 case CMPGE_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011927 cond = ge;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011928 break;
11929 case CMPGT_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011930 cond = gt;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011931 break;
11932 case CMPLE_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011933 cond = ge;
11934 commute_inputs = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011935 break;
11936 case CMPLT_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011937 cond = gt;
11938 commute_inputs = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011939 break;
11940 case CMPNE_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011941 cond = ne;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011942 break;
11943 default:
11944 VIXL_UNIMPLEMENTED();
11945 break;
11946 }
TatWai Chong302729c2019-06-14 16:18:51 -070011947
11948 VectorFormat vform = instr->GetSVEVectorFormat();
11949 SimVRegister src2;
11950 dup_immediate(vform,
11951 src2,
11952 ExtractSignedBitfield64(4, 0, instr->ExtractBits(20, 16)));
11953 SVEIntCompareVectorsHelper(cond,
11954 vform,
11955 ReadPRegister(instr->GetPd()),
11956 ReadPRegister(instr->GetPgLow8()),
11957 commute_inputs ? src2
11958 : ReadVRegister(instr->GetRn()),
11959 commute_inputs ? ReadVRegister(instr->GetRn())
11960 : src2);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011961}
11962
11963void Simulator::VisitSVEIntCompareUnsignedImm(const Instruction* instr) {
TatWai Chong302729c2019-06-14 16:18:51 -070011964 bool commute_inputs = false;
Martyn Capewelled5e03d2021-06-24 16:44:24 +010011965 Condition cond = al;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011966 switch (instr->Mask(SVEIntCompareUnsignedImmMask)) {
11967 case CMPHI_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011968 cond = hi;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011969 break;
11970 case CMPHS_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011971 cond = hs;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011972 break;
11973 case CMPLO_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011974 cond = hi;
11975 commute_inputs = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011976 break;
11977 case CMPLS_p_p_zi:
TatWai Chong302729c2019-06-14 16:18:51 -070011978 cond = hs;
11979 commute_inputs = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000011980 break;
11981 default:
11982 VIXL_UNIMPLEMENTED();
11983 break;
11984 }
TatWai Chong302729c2019-06-14 16:18:51 -070011985
11986 VectorFormat vform = instr->GetSVEVectorFormat();
11987 SimVRegister src2;
11988 dup_immediate(vform, src2, instr->ExtractBits(20, 14));
11989 SVEIntCompareVectorsHelper(cond,
11990 vform,
11991 ReadPRegister(instr->GetPd()),
11992 ReadPRegister(instr->GetPgLow8()),
11993 commute_inputs ? src2
11994 : ReadVRegister(instr->GetRn()),
11995 commute_inputs ? ReadVRegister(instr->GetRn())
11996 : src2);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000011997}
11998
11999void Simulator::VisitSVEIntCompareVectors(const Instruction* instr) {
TatWai Chong96713fe2019-06-04 16:39:37 -070012000 Instr op = instr->Mask(SVEIntCompareVectorsMask);
12001 bool is_wide_elements = false;
12002 switch (op) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012003 case CMPEQ_p_p_zw:
TatWai Chong96713fe2019-06-04 16:39:37 -070012004 case CMPGE_p_p_zw:
12005 case CMPGT_p_p_zw:
12006 case CMPHI_p_p_zw:
12007 case CMPHS_p_p_zw:
12008 case CMPLE_p_p_zw:
12009 case CMPLO_p_p_zw:
12010 case CMPLS_p_p_zw:
12011 case CMPLT_p_p_zw:
12012 case CMPNE_p_p_zw:
12013 is_wide_elements = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012014 break;
TatWai Chong96713fe2019-06-04 16:39:37 -070012015 }
12016
TatWai Chong302729c2019-06-14 16:18:51 -070012017 Condition cond;
TatWai Chong96713fe2019-06-04 16:39:37 -070012018 switch (op) {
12019 case CMPEQ_p_p_zw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012020 case CMPEQ_p_p_zz:
TatWai Chong302729c2019-06-14 16:18:51 -070012021 cond = eq;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012022 break;
12023 case CMPGE_p_p_zw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012024 case CMPGE_p_p_zz:
TatWai Chong302729c2019-06-14 16:18:51 -070012025 cond = ge;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012026 break;
12027 case CMPGT_p_p_zw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012028 case CMPGT_p_p_zz:
TatWai Chong302729c2019-06-14 16:18:51 -070012029 cond = gt;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012030 break;
12031 case CMPHI_p_p_zw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012032 case CMPHI_p_p_zz:
TatWai Chong302729c2019-06-14 16:18:51 -070012033 cond = hi;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012034 break;
12035 case CMPHS_p_p_zw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012036 case CMPHS_p_p_zz:
TatWai Chong302729c2019-06-14 16:18:51 -070012037 cond = hs;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012038 break;
12039 case CMPNE_p_p_zw:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012040 case CMPNE_p_p_zz:
TatWai Chong302729c2019-06-14 16:18:51 -070012041 cond = ne;
TatWai Chong96713fe2019-06-04 16:39:37 -070012042 break;
12043 case CMPLE_p_p_zw:
TatWai Chong302729c2019-06-14 16:18:51 -070012044 cond = le;
TatWai Chong96713fe2019-06-04 16:39:37 -070012045 break;
12046 case CMPLO_p_p_zw:
TatWai Chong302729c2019-06-14 16:18:51 -070012047 cond = lo;
TatWai Chong96713fe2019-06-04 16:39:37 -070012048 break;
12049 case CMPLS_p_p_zw:
TatWai Chong302729c2019-06-14 16:18:51 -070012050 cond = ls;
TatWai Chong96713fe2019-06-04 16:39:37 -070012051 break;
12052 case CMPLT_p_p_zw:
TatWai Chong302729c2019-06-14 16:18:51 -070012053 cond = lt;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012054 break;
12055 default:
12056 VIXL_UNIMPLEMENTED();
TatWai Chong302729c2019-06-14 16:18:51 -070012057 cond = al;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012058 break;
12059 }
TatWai Chong96713fe2019-06-04 16:39:37 -070012060
TatWai Chong302729c2019-06-14 16:18:51 -070012061 SVEIntCompareVectorsHelper(cond,
TatWai Chong96713fe2019-06-04 16:39:37 -070012062 instr->GetSVEVectorFormat(),
12063 ReadPRegister(instr->GetPd()),
12064 ReadPRegister(instr->GetPgLow8()),
12065 ReadVRegister(instr->GetRn()),
12066 ReadVRegister(instr->GetRm()),
12067 is_wide_elements);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012068}
12069
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012070void Simulator::VisitSVEFPExponentialAccelerator(const Instruction* instr) {
Martyn Capewell43782632019-12-12 13:22:10 +000012071 VectorFormat vform = instr->GetSVEVectorFormat();
12072 SimVRegister& zd = ReadVRegister(instr->GetRd());
12073 SimVRegister& zn = ReadVRegister(instr->GetRn());
12074
12075 VIXL_ASSERT((vform == kFormatVnH) || (vform == kFormatVnS) ||
12076 (vform == kFormatVnD));
12077
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012078 switch (instr->Mask(SVEFPExponentialAcceleratorMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012079 case FEXPA_z_z:
Martyn Capewell43782632019-12-12 13:22:10 +000012080 fexpa(vform, zd, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012081 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012082 default:
12083 VIXL_UNIMPLEMENTED();
12084 break;
12085 }
12086}
12087
12088void Simulator::VisitSVEFPTrigSelectCoefficient(const Instruction* instr) {
Martyn Capewell43782632019-12-12 13:22:10 +000012089 VectorFormat vform = instr->GetSVEVectorFormat();
12090 SimVRegister& zd = ReadVRegister(instr->GetRd());
12091 SimVRegister& zn = ReadVRegister(instr->GetRn());
12092 SimVRegister& zm = ReadVRegister(instr->GetRm());
12093
12094 VIXL_ASSERT((vform == kFormatVnH) || (vform == kFormatVnS) ||
12095 (vform == kFormatVnD));
12096
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012097 switch (instr->Mask(SVEFPTrigSelectCoefficientMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012098 case FTSSEL_z_zz:
Martyn Capewell43782632019-12-12 13:22:10 +000012099 ftssel(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012100 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012101 default:
12102 VIXL_UNIMPLEMENTED();
12103 break;
12104 }
12105}
12106
12107void Simulator::VisitSVEConstructivePrefix_Unpredicated(
12108 const Instruction* instr) {
12109 SimVRegister& zd = ReadVRegister(instr->GetRd());
12110 SimVRegister& zn = ReadVRegister(instr->GetRn());
12111
12112 switch (instr->Mask(SVEConstructivePrefix_UnpredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012113 case MOVPRFX_z_z:
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012114 mov(kFormatVnD, zd, zn); // The lane size is arbitrary.
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012115 break;
12116 default:
12117 VIXL_UNIMPLEMENTED();
12118 break;
12119 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012120}
12121
12122void Simulator::VisitSVEIntMulAddPredicated(const Instruction* instr) {
Jacob Bramley22023df2019-05-14 17:55:43 +010012123 VectorFormat vform = instr->GetSVEVectorFormat();
12124
12125 SimVRegister& zd = ReadVRegister(instr->GetRd());
12126 SimVRegister& zm = ReadVRegister(instr->GetRm());
12127
12128 SimVRegister result;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012129 switch (instr->Mask(SVEIntMulAddPredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012130 case MLA_z_p_zzz:
Jacob Bramley22023df2019-05-14 17:55:43 +010012131 mla(vform, result, zd, ReadVRegister(instr->GetRn()), zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012132 break;
12133 case MLS_z_p_zzz:
Jacob Bramley22023df2019-05-14 17:55:43 +010012134 mls(vform, result, zd, ReadVRegister(instr->GetRn()), zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012135 break;
Jacob Bramley22023df2019-05-14 17:55:43 +010012136 case MAD_z_p_zzz:
12137 // 'za' is encoded in 'Rn'.
12138 mla(vform, result, ReadVRegister(instr->GetRn()), zd, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012139 break;
Jacob Bramley22023df2019-05-14 17:55:43 +010012140 case MSB_z_p_zzz: {
12141 // 'za' is encoded in 'Rn'.
12142 mls(vform, result, ReadVRegister(instr->GetRn()), zd, zm);
12143 break;
12144 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012145 default:
12146 VIXL_UNIMPLEMENTED();
12147 break;
12148 }
Jacob Bramley22023df2019-05-14 17:55:43 +010012149 mov_merging(vform, zd, ReadPRegister(instr->GetPgLow8()), result);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012150}
12151
12152void Simulator::VisitSVEIntMulAddUnpredicated(const Instruction* instr) {
TatWai Chong4d2a4e92019-10-23 16:19:32 -070012153 VectorFormat vform = instr->GetSVEVectorFormat();
12154 SimVRegister& zda = ReadVRegister(instr->GetRd());
12155 SimVRegister& zn = ReadVRegister(instr->GetRn());
12156 SimVRegister& zm = ReadVRegister(instr->GetRm());
12157
Martyn Capewell286dce72021-08-20 13:42:06 +010012158 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +010012159 case "sdot_z_zzz"_h:
TatWai Chong4d2a4e92019-10-23 16:19:32 -070012160 sdot(vform, zda, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012161 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010012162 case "udot_z_zzz"_h:
TatWai Chong4d2a4e92019-10-23 16:19:32 -070012163 udot(vform, zda, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012164 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010012165 case "usdot_z_zzz_s"_h:
Martyn Capewell286dce72021-08-20 13:42:06 +010012166 usdot(vform, zda, zn, zm);
12167 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012168 default:
12169 VIXL_UNIMPLEMENTED();
12170 break;
12171 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012172}
12173
TatWai Chongb2d8d1f2019-10-21 15:19:31 -070012174void Simulator::VisitSVEMovprfx(const Instruction* instr) {
TatWai Chongb2d8d1f2019-10-21 15:19:31 -070012175 VectorFormat vform = instr->GetSVEVectorFormat();
12176 SimVRegister& zn = ReadVRegister(instr->GetRn());
12177 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
12178 SimVRegister& zd = ReadVRegister(instr->GetRd());
12179
12180 switch (instr->Mask(SVEMovprfxMask)) {
12181 case MOVPRFX_z_p_z:
12182 if (instr->ExtractBit(16)) {
12183 mov_merging(vform, zd, pg, zn);
12184 } else {
12185 mov_zeroing(vform, zd, pg, zn);
12186 }
TatWai Chongb2d8d1f2019-10-21 15:19:31 -070012187 break;
12188 default:
12189 VIXL_UNIMPLEMENTED();
12190 break;
12191 }
12192}
12193
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012194void Simulator::VisitSVEIntReduction(const Instruction* instr) {
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012195 VectorFormat vform = instr->GetSVEVectorFormat();
TatWai Chong6f111bc2019-10-07 09:20:37 +010012196 SimVRegister& vd = ReadVRegister(instr->GetRd());
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012197 SimVRegister& zn = ReadVRegister(instr->GetRn());
12198 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
12199
12200 if (instr->Mask(SVEIntReductionLogicalFMask) == SVEIntReductionLogicalFixed) {
12201 switch (instr->Mask(SVEIntReductionLogicalMask)) {
12202 case ANDV_r_p_z:
TatWai Chong6f111bc2019-10-07 09:20:37 +010012203 andv(vform, vd, pg, zn);
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012204 break;
12205 case EORV_r_p_z:
TatWai Chong6f111bc2019-10-07 09:20:37 +010012206 eorv(vform, vd, pg, zn);
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012207 break;
12208 case ORV_r_p_z:
TatWai Chong6f111bc2019-10-07 09:20:37 +010012209 orv(vform, vd, pg, zn);
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012210 break;
12211 default:
12212 VIXL_UNIMPLEMENTED();
12213 break;
12214 }
12215 } else {
12216 switch (instr->Mask(SVEIntReductionMask)) {
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012217 case SADDV_r_p_z:
TatWai Chongb2d8d1f2019-10-21 15:19:31 -070012218 saddv(vform, vd, pg, zn);
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012219 break;
12220 case SMAXV_r_p_z:
TatWai Chongb2d8d1f2019-10-21 15:19:31 -070012221 smaxv(vform, vd, pg, zn);
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012222 break;
12223 case SMINV_r_p_z:
TatWai Chongb2d8d1f2019-10-21 15:19:31 -070012224 sminv(vform, vd, pg, zn);
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012225 break;
12226 case UADDV_r_p_z:
TatWai Chongb2d8d1f2019-10-21 15:19:31 -070012227 uaddv(vform, vd, pg, zn);
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012228 break;
12229 case UMAXV_r_p_z:
TatWai Chongb2d8d1f2019-10-21 15:19:31 -070012230 umaxv(vform, vd, pg, zn);
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012231 break;
12232 case UMINV_r_p_z:
TatWai Chongb2d8d1f2019-10-21 15:19:31 -070012233 uminv(vform, vd, pg, zn);
Jacob Bramleyae2fc3b2019-05-21 19:24:36 +010012234 break;
12235 default:
12236 VIXL_UNIMPLEMENTED();
12237 break;
12238 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012239 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012240}
12241
12242void Simulator::VisitSVEIntUnaryArithmeticPredicated(const Instruction* instr) {
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012243 VectorFormat vform = instr->GetSVEVectorFormat();
12244 SimVRegister& zn = ReadVRegister(instr->GetRn());
12245
12246 SimVRegister result;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012247 switch (instr->Mask(SVEIntUnaryArithmeticPredicatedMask)) {
12248 case ABS_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012249 abs(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012250 break;
12251 case CLS_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012252 cls(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012253 break;
12254 case CLZ_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012255 clz(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012256 break;
12257 case CNOT_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012258 cnot(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012259 break;
12260 case CNT_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012261 cnt(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012262 break;
12263 case FABS_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012264 fabs_(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012265 break;
12266 case FNEG_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012267 fneg(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012268 break;
12269 case NEG_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012270 neg(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012271 break;
12272 case NOT_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012273 not_(vform, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012274 break;
12275 case SXTB_z_p_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012276 case SXTH_z_p_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012277 case SXTW_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012278 sxt(vform, result, zn, (kBitsPerByte << instr->ExtractBits(18, 17)));
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012279 break;
12280 case UXTB_z_p_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012281 case UXTH_z_p_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012282 case UXTW_z_p_z:
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012283 uxt(vform, result, zn, (kBitsPerByte << instr->ExtractBits(18, 17)));
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012284 break;
12285 default:
12286 VIXL_UNIMPLEMENTED();
12287 break;
12288 }
Jacob Bramleybc21a0d2019-09-20 18:49:15 +010012289
12290 SimVRegister& zd = ReadVRegister(instr->GetRd());
12291 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
12292 mov_merging(vform, zd, pg, result);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012293}
12294
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012295void Simulator::VisitSVECopyFPImm_Predicated(const Instruction* instr) {
Jacob Bramley0f62eab2019-10-23 17:07:47 +010012296 // There is only one instruction in this group.
12297 VIXL_ASSERT(instr->Mask(SVECopyFPImm_PredicatedMask) == FCPY_z_p_i);
12298
12299 VectorFormat vform = instr->GetSVEVectorFormat();
12300 SimPRegister& pg = ReadPRegister(instr->ExtractBits(19, 16));
12301 SimVRegister& zd = ReadVRegister(instr->GetRd());
12302
Martyn Capewell310a0822020-09-08 20:09:17 +010012303 if (vform == kFormatVnB) VIXL_UNIMPLEMENTED();
12304
Jacob Bramley0f62eab2019-10-23 17:07:47 +010012305 SimVRegister result;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012306 switch (instr->Mask(SVECopyFPImm_PredicatedMask)) {
Jacob Bramley0f62eab2019-10-23 17:07:47 +010012307 case FCPY_z_p_i: {
12308 int imm8 = instr->ExtractBits(12, 5);
12309 uint64_t value = FPToRawbitsWithSize(LaneSizeInBitsFromFormat(vform),
12310 Instruction::Imm8ToFP64(imm8));
12311 dup_immediate(vform, result, value);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012312 break;
Jacob Bramley0f62eab2019-10-23 17:07:47 +010012313 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012314 default:
12315 VIXL_UNIMPLEMENTED();
12316 break;
12317 }
Jacob Bramley0f62eab2019-10-23 17:07:47 +010012318 mov_merging(vform, zd, pg, result);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012319}
12320
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012321void Simulator::VisitSVEIntAddSubtractImm_Unpredicated(
12322 const Instruction* instr) {
TatWai Chong6995bfd2019-09-26 10:48:05 +010012323 VectorFormat vform = instr->GetSVEVectorFormat();
Jacob Bramley9d06c4d2019-05-13 18:15:06 +010012324 SimVRegister& zd = ReadVRegister(instr->GetRd());
TatWai Chong6995bfd2019-09-26 10:48:05 +010012325 SimVRegister scratch;
12326
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012327 uint64_t imm = instr->GetImmSVEIntWideUnsigned();
12328 imm <<= instr->ExtractBit(13) * 8;
TatWai Chong6995bfd2019-09-26 10:48:05 +010012329
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012330 switch (instr->Mask(SVEIntAddSubtractImm_UnpredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012331 case ADD_z_zi:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012332 add_uint(vform, zd, zd, imm);
12333 break;
TatWai Chong6995bfd2019-09-26 10:48:05 +010012334 case SQADD_z_zi:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012335 add_uint(vform, zd, zd, imm).SignedSaturate(vform);
12336 break;
TatWai Chong6995bfd2019-09-26 10:48:05 +010012337 case SQSUB_z_zi:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012338 sub_uint(vform, zd, zd, imm).SignedSaturate(vform);
12339 break;
TatWai Chong6995bfd2019-09-26 10:48:05 +010012340 case SUBR_z_zi:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012341 dup_immediate(vform, scratch, imm);
TatWai Chong6995bfd2019-09-26 10:48:05 +010012342 sub(vform, zd, scratch, zd);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012343 break;
TatWai Chong6995bfd2019-09-26 10:48:05 +010012344 case SUB_z_zi:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012345 sub_uint(vform, zd, zd, imm);
12346 break;
TatWai Chong6995bfd2019-09-26 10:48:05 +010012347 case UQADD_z_zi:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012348 add_uint(vform, zd, zd, imm).UnsignedSaturate(vform);
12349 break;
TatWai Chong6995bfd2019-09-26 10:48:05 +010012350 case UQSUB_z_zi:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012351 sub_uint(vform, zd, zd, imm).UnsignedSaturate(vform);
12352 break;
TatWai Chong6995bfd2019-09-26 10:48:05 +010012353 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012354 break;
TatWai Chong6995bfd2019-09-26 10:48:05 +010012355 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012356}
TatWai Chong6995bfd2019-09-26 10:48:05 +010012357
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012358void Simulator::VisitSVEBroadcastIntImm_Unpredicated(const Instruction* instr) {
12359 SimVRegister& zd = ReadVRegister(instr->GetRd());
12360
Martyn Capewell8ed83522020-08-11 16:19:43 +010012361 VectorFormat format = instr->GetSVEVectorFormat();
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012362 int64_t imm = instr->GetImmSVEIntWideSigned();
Martyn Capewell8ed83522020-08-11 16:19:43 +010012363 int shift = instr->ExtractBit(13) * 8;
TheLastRar49d6efa2024-10-15 16:37:27 +010012364 imm *= uint64_t{1} << shift;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012365
12366 switch (instr->Mask(SVEBroadcastIntImm_UnpredicatedMask)) {
12367 case DUP_z_i:
Martyn Capewell8ed83522020-08-11 16:19:43 +010012368 // The encoding of byte-sized lanes with lsl #8 is undefined.
12369 if ((format == kFormatVnB) && (shift == 8)) {
12370 VIXL_UNIMPLEMENTED();
12371 } else {
12372 dup_immediate(format, zd, imm);
12373 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012374 break;
12375 default:
12376 VIXL_UNIMPLEMENTED();
12377 break;
12378 }
12379}
12380
12381void Simulator::VisitSVEBroadcastFPImm_Unpredicated(const Instruction* instr) {
12382 VectorFormat vform = instr->GetSVEVectorFormat();
12383 SimVRegister& zd = ReadVRegister(instr->GetRd());
12384
12385 switch (instr->Mask(SVEBroadcastFPImm_UnpredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012386 case FDUP_z_i:
TatWai Chong6995bfd2019-09-26 10:48:05 +010012387 switch (vform) {
12388 case kFormatVnH:
12389 dup_immediate(vform, zd, Float16ToRawbits(instr->GetSVEImmFP16()));
12390 break;
12391 case kFormatVnS:
12392 dup_immediate(vform, zd, FloatToRawbits(instr->GetSVEImmFP32()));
12393 break;
12394 case kFormatVnD:
12395 dup_immediate(vform, zd, DoubleToRawbits(instr->GetSVEImmFP64()));
12396 break;
12397 default:
12398 VIXL_UNIMPLEMENTED();
12399 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012400 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012401 default:
12402 VIXL_UNIMPLEMENTED();
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012403 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012404 }
12405}
12406
12407void Simulator::VisitSVE32BitGatherLoadHalfwords_ScalarPlus32BitScaledOffsets(
12408 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012409 switch (instr->Mask(
12410 SVE32BitGatherLoadHalfwords_ScalarPlus32BitScaledOffsetsMask)) {
12411 case LD1H_z_p_bz_s_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012412 case LD1SH_z_p_bz_s_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012413 case LDFF1H_z_p_bz_s_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012414 case LDFF1SH_z_p_bz_s_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012415 break;
12416 default:
12417 VIXL_UNIMPLEMENTED();
12418 break;
12419 }
TatWai Chong113d9192020-05-19 01:02:36 -070012420
TatWai Chongcd3f6c52020-06-14 00:42:39 -070012421 SVEOffsetModifier mod = (instr->ExtractBit(22) == 1) ? SVE_SXTW : SVE_UXTW;
12422 SVEGatherLoadScalarPlusVectorHelper(instr, kFormatVnS, mod);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012423}
12424
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012425void Simulator::VisitSVE32BitGatherLoad_ScalarPlus32BitUnscaledOffsets(
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012426 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012427 switch (instr->Mask(SVE32BitGatherLoad_ScalarPlus32BitUnscaledOffsetsMask)) {
12428 case LD1B_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012429 case LD1H_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012430 case LD1SB_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012431 case LD1SH_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012432 case LD1W_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012433 case LDFF1B_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012434 case LDFF1H_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012435 case LDFF1SB_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012436 case LDFF1SH_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012437 case LDFF1W_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012438 break;
12439 default:
12440 VIXL_UNIMPLEMENTED();
12441 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012442 }
TatWai Chong113d9192020-05-19 01:02:36 -070012443
TatWai Chongcd3f6c52020-06-14 00:42:39 -070012444 SVEOffsetModifier mod = (instr->ExtractBit(22) == 1) ? SVE_SXTW : SVE_UXTW;
12445 SVEGatherLoadScalarPlusVectorHelper(instr, kFormatVnS, mod);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012446}
12447
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012448void Simulator::VisitSVE32BitGatherLoad_VectorPlusImm(
12449 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012450 switch (instr->Mask(SVE32BitGatherLoad_VectorPlusImmMask)) {
12451 case LD1B_z_p_ai_s:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012452 VIXL_UNIMPLEMENTED();
12453 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012454 case LD1H_z_p_ai_s:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012455 VIXL_UNIMPLEMENTED();
12456 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012457 case LD1SB_z_p_ai_s:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012458 VIXL_UNIMPLEMENTED();
12459 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012460 case LD1SH_z_p_ai_s:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012461 VIXL_UNIMPLEMENTED();
12462 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012463 case LD1W_z_p_ai_s:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012464 VIXL_UNIMPLEMENTED();
12465 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012466 case LDFF1B_z_p_ai_s:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012467 VIXL_UNIMPLEMENTED();
12468 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012469 case LDFF1H_z_p_ai_s:
12470 VIXL_UNIMPLEMENTED();
12471 break;
12472 case LDFF1SB_z_p_ai_s:
12473 VIXL_UNIMPLEMENTED();
12474 break;
12475 case LDFF1SH_z_p_ai_s:
12476 VIXL_UNIMPLEMENTED();
12477 break;
12478 case LDFF1W_z_p_ai_s:
12479 VIXL_UNIMPLEMENTED();
12480 break;
12481 default:
12482 VIXL_UNIMPLEMENTED();
12483 break;
12484 }
12485}
12486
12487void Simulator::VisitSVE32BitGatherLoadWords_ScalarPlus32BitScaledOffsets(
12488 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012489 switch (
12490 instr->Mask(SVE32BitGatherLoadWords_ScalarPlus32BitScaledOffsetsMask)) {
12491 case LD1W_z_p_bz_s_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012492 case LDFF1W_z_p_bz_s_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012493 break;
12494 default:
12495 VIXL_UNIMPLEMENTED();
12496 break;
12497 }
TatWai Chong113d9192020-05-19 01:02:36 -070012498
TatWai Chongcd3f6c52020-06-14 00:42:39 -070012499 SVEOffsetModifier mod = (instr->ExtractBit(22) == 1) ? SVE_SXTW : SVE_UXTW;
12500 SVEGatherLoadScalarPlusVectorHelper(instr, kFormatVnS, mod);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012501}
12502
12503void Simulator::VisitSVE32BitGatherPrefetch_ScalarPlus32BitScaledOffsets(
12504 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012505 switch (
12506 instr->Mask(SVE32BitGatherPrefetch_ScalarPlus32BitScaledOffsetsMask)) {
TatWai Chong3db2c492020-03-29 22:20:41 -070012507 // Ignore prefetch hint instructions.
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012508 case PRFB_i_p_bz_s_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012509 case PRFD_i_p_bz_s_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012510 case PRFH_i_p_bz_s_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012511 case PRFW_i_p_bz_s_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012512 break;
12513 default:
12514 VIXL_UNIMPLEMENTED();
12515 break;
12516 }
12517}
12518
12519void Simulator::VisitSVE32BitGatherPrefetch_VectorPlusImm(
12520 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012521 switch (instr->Mask(SVE32BitGatherPrefetch_VectorPlusImmMask)) {
TatWai Chong3db2c492020-03-29 22:20:41 -070012522 // Ignore prefetch hint instructions.
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012523 case PRFB_i_p_ai_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012524 case PRFD_i_p_ai_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012525 case PRFH_i_p_ai_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012526 case PRFW_i_p_ai_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012527 break;
12528 default:
12529 VIXL_UNIMPLEMENTED();
12530 break;
12531 }
12532}
12533
12534void Simulator::VisitSVEContiguousPrefetch_ScalarPlusImm(
12535 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012536 switch (instr->Mask(SVEContiguousPrefetch_ScalarPlusImmMask)) {
TatWai Chong3db2c492020-03-29 22:20:41 -070012537 // Ignore prefetch hint instructions.
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012538 case PRFB_i_p_bi_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012539 case PRFD_i_p_bi_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012540 case PRFH_i_p_bi_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012541 case PRFW_i_p_bi_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012542 break;
12543 default:
12544 VIXL_UNIMPLEMENTED();
12545 break;
12546 }
12547}
12548
12549void Simulator::VisitSVEContiguousPrefetch_ScalarPlusScalar(
12550 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012551 switch (instr->Mask(SVEContiguousPrefetch_ScalarPlusScalarMask)) {
TatWai Chong3db2c492020-03-29 22:20:41 -070012552 // Ignore prefetch hint instructions.
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012553 case PRFB_i_p_br_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012554 case PRFD_i_p_br_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012555 case PRFH_i_p_br_s:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012556 case PRFW_i_p_br_s:
Martyn Capewellecca4b12020-07-02 14:30:50 +010012557 if (instr->GetRm() == kZeroRegCode) {
12558 VIXL_UNIMPLEMENTED();
12559 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012560 break;
12561 default:
12562 VIXL_UNIMPLEMENTED();
12563 break;
12564 }
12565}
12566
12567void Simulator::VisitSVELoadAndBroadcastElement(const Instruction* instr) {
TatWai Chong85e15102020-05-04 21:00:40 -070012568 bool is_signed;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012569 switch (instr->Mask(SVELoadAndBroadcastElementMask)) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012570 case LD1RB_z_p_bi_u8:
TatWai Chong85e15102020-05-04 21:00:40 -070012571 case LD1RB_z_p_bi_u16:
12572 case LD1RB_z_p_bi_u32:
12573 case LD1RB_z_p_bi_u64:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012574 case LD1RH_z_p_bi_u16:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012575 case LD1RH_z_p_bi_u32:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012576 case LD1RH_z_p_bi_u64:
TatWai Chong85e15102020-05-04 21:00:40 -070012577 case LD1RW_z_p_bi_u32:
12578 case LD1RW_z_p_bi_u64:
12579 case LD1RD_z_p_bi_u64:
12580 is_signed = false;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012581 break;
12582 case LD1RSB_z_p_bi_s16:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012583 case LD1RSB_z_p_bi_s32:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012584 case LD1RSB_z_p_bi_s64:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012585 case LD1RSH_z_p_bi_s32:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012586 case LD1RSH_z_p_bi_s64:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012587 case LD1RSW_z_p_bi_s64:
TatWai Chong85e15102020-05-04 21:00:40 -070012588 is_signed = true;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012589 break;
12590 default:
TatWai Chong85e15102020-05-04 21:00:40 -070012591 // This encoding group is complete, so no other values should be possible.
12592 VIXL_UNREACHABLE();
12593 is_signed = false;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012594 break;
12595 }
TatWai Chong85e15102020-05-04 21:00:40 -070012596
12597 int msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(is_signed);
12598 int esize_in_bytes_log2 = instr->GetSVEEsizeFromDtype(is_signed, 13);
12599 VIXL_ASSERT(msize_in_bytes_log2 <= esize_in_bytes_log2);
12600 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(esize_in_bytes_log2);
12601 uint64_t offset = instr->ExtractBits(21, 16) << msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000012602 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer) + offset;
TatWai Chong85e15102020-05-04 21:00:40 -070012603 VectorFormat unpack_vform =
12604 SVEFormatFromLaneSizeInBytesLog2(msize_in_bytes_log2);
12605 SimVRegister temp;
Chris Jones89dfbc02024-04-16 16:21:03 +010012606 if (!ld1r(vform, unpack_vform, temp, base, is_signed)) return;
TatWai Chong85e15102020-05-04 21:00:40 -070012607 mov_zeroing(vform,
12608 ReadVRegister(instr->GetRt()),
12609 ReadPRegister(instr->GetPgLow8()),
12610 temp);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012611}
12612
12613void Simulator::VisitSVELoadPredicateRegister(const Instruction* instr) {
12614 switch (instr->Mask(SVELoadPredicateRegisterMask)) {
12615 case LDR_p_bi: {
12616 SimPRegister& pt = ReadPRegister(instr->GetPt());
12617 int pl = GetPredicateLengthInBytes();
12618 int imm9 = (instr->ExtractBits(21, 16) << 3) | instr->ExtractBits(12, 10);
12619 uint64_t multiplier = ExtractSignedBitfield64(8, 0, imm9);
Maid3f755c2022-11-18 10:49:35 +000012620 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
12621 uint64_t address = base + multiplier * pl;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012622 for (int i = 0; i < pl; i++) {
Chris Jones30e7bbd2024-02-15 15:05:25 +000012623 VIXL_DEFINE_OR_RETURN(value, MemRead<uint8_t>(address + i));
12624 pt.Insert(i, value);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012625 }
Jacob Bramley7eb3e212019-11-22 17:28:05 +000012626 LogPRead(instr->GetPt(), address);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012627 break;
12628 }
12629 default:
12630 VIXL_UNIMPLEMENTED();
12631 break;
12632 }
12633}
12634
12635void Simulator::VisitSVELoadVectorRegister(const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012636 switch (instr->Mask(SVELoadVectorRegisterMask)) {
12637 case LDR_z_bi: {
12638 SimVRegister& zt = ReadVRegister(instr->GetRt());
12639 int vl = GetVectorLengthInBytes();
12640 int imm9 = (instr->ExtractBits(21, 16) << 3) | instr->ExtractBits(12, 10);
12641 uint64_t multiplier = ExtractSignedBitfield64(8, 0, imm9);
Maid3f755c2022-11-18 10:49:35 +000012642 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
12643 uint64_t address = base + multiplier * vl;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012644 for (int i = 0; i < vl; i++) {
Chris Jones30e7bbd2024-02-15 15:05:25 +000012645 VIXL_DEFINE_OR_RETURN(value, MemRead<uint8_t>(address + i));
12646 zt.Insert(i, value);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012647 }
Jacob Bramley7eb3e212019-11-22 17:28:05 +000012648 LogZRead(instr->GetRt(), address);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012649 break;
12650 }
12651 default:
12652 VIXL_UNIMPLEMENTED();
12653 break;
12654 }
12655}
12656
12657void Simulator::VisitSVE64BitGatherLoad_ScalarPlus32BitUnpackedScaledOffsets(
12658 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012659 switch (instr->Mask(
12660 SVE64BitGatherLoad_ScalarPlus32BitUnpackedScaledOffsetsMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012661 case LD1D_z_p_bz_d_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012662 case LD1H_z_p_bz_d_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012663 case LD1SH_z_p_bz_d_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012664 case LD1SW_z_p_bz_d_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012665 case LD1W_z_p_bz_d_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012666 case LDFF1H_z_p_bz_d_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012667 case LDFF1W_z_p_bz_d_x32_scaled:
TatWai Chong1af34f12020-06-01 20:54:06 -070012668 case LDFF1D_z_p_bz_d_x32_scaled:
12669 case LDFF1SH_z_p_bz_d_x32_scaled:
12670 case LDFF1SW_z_p_bz_d_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012671 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012672 default:
12673 VIXL_UNIMPLEMENTED();
12674 break;
12675 }
TatWai Chong1af34f12020-06-01 20:54:06 -070012676
TatWai Chongcd3f6c52020-06-14 00:42:39 -070012677 SVEOffsetModifier mod = (instr->ExtractBit(22) == 1) ? SVE_SXTW : SVE_UXTW;
12678 SVEGatherLoadScalarPlusVectorHelper(instr, kFormatVnD, mod);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012679}
12680
12681void Simulator::VisitSVE64BitGatherLoad_ScalarPlus64BitScaledOffsets(
12682 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012683 switch (instr->Mask(SVE64BitGatherLoad_ScalarPlus64BitScaledOffsetsMask)) {
12684 case LD1D_z_p_bz_d_64_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012685 case LD1H_z_p_bz_d_64_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012686 case LD1SH_z_p_bz_d_64_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012687 case LD1SW_z_p_bz_d_64_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012688 case LD1W_z_p_bz_d_64_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012689 case LDFF1H_z_p_bz_d_64_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012690 case LDFF1W_z_p_bz_d_64_scaled:
TatWai Chong1af34f12020-06-01 20:54:06 -070012691 case LDFF1D_z_p_bz_d_64_scaled:
12692 case LDFF1SH_z_p_bz_d_64_scaled:
12693 case LDFF1SW_z_p_bz_d_64_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012694 break;
12695 default:
12696 VIXL_UNIMPLEMENTED();
12697 break;
12698 }
TatWai Chong1af34f12020-06-01 20:54:06 -070012699
TatWai Chongcd3f6c52020-06-14 00:42:39 -070012700 SVEGatherLoadScalarPlusVectorHelper(instr, kFormatVnD, SVE_LSL);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012701}
12702
12703void Simulator::VisitSVE64BitGatherLoad_ScalarPlus64BitUnscaledOffsets(
12704 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012705 switch (instr->Mask(SVE64BitGatherLoad_ScalarPlus64BitUnscaledOffsetsMask)) {
12706 case LD1B_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012707 case LD1D_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012708 case LD1H_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012709 case LD1SB_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012710 case LD1SH_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012711 case LD1SW_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012712 case LD1W_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012713 case LDFF1B_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012714 case LDFF1D_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012715 case LDFF1H_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012716 case LDFF1SB_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012717 case LDFF1SH_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012718 case LDFF1SW_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012719 case LDFF1W_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012720 break;
12721 default:
12722 VIXL_UNIMPLEMENTED();
12723 break;
12724 }
TatWai Chong113d9192020-05-19 01:02:36 -070012725
TatWai Chongcd3f6c52020-06-14 00:42:39 -070012726 SVEGatherLoadScalarPlusVectorHelper(instr,
12727 kFormatVnD,
12728 NO_SVE_OFFSET_MODIFIER);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012729}
12730
12731void Simulator::VisitSVE64BitGatherLoad_ScalarPlusUnpacked32BitUnscaledOffsets(
12732 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012733 switch (instr->Mask(
12734 SVE64BitGatherLoad_ScalarPlusUnpacked32BitUnscaledOffsetsMask)) {
12735 case LD1B_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012736 case LD1D_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012737 case LD1H_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012738 case LD1SB_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012739 case LD1SH_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012740 case LD1SW_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012741 case LD1W_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012742 case LDFF1B_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012743 case LDFF1H_z_p_bz_d_x32_unscaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012744 case LDFF1W_z_p_bz_d_x32_unscaled:
TatWai Chong1af34f12020-06-01 20:54:06 -070012745 case LDFF1D_z_p_bz_d_x32_unscaled:
12746 case LDFF1SB_z_p_bz_d_x32_unscaled:
12747 case LDFF1SH_z_p_bz_d_x32_unscaled:
12748 case LDFF1SW_z_p_bz_d_x32_unscaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012749 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012750 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012751 VIXL_UNIMPLEMENTED();
12752 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012753 }
TatWai Chong1af34f12020-06-01 20:54:06 -070012754
TatWai Chongcd3f6c52020-06-14 00:42:39 -070012755 SVEOffsetModifier mod = (instr->ExtractBit(22) == 1) ? SVE_SXTW : SVE_UXTW;
12756 SVEGatherLoadScalarPlusVectorHelper(instr, kFormatVnD, mod);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012757}
12758
12759void Simulator::VisitSVE64BitGatherLoad_VectorPlusImm(
12760 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012761 switch (instr->Mask(SVE64BitGatherLoad_VectorPlusImmMask)) {
12762 case LD1B_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012763 case LD1D_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012764 case LD1H_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012765 case LD1SB_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012766 case LD1SH_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012767 case LD1SW_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012768 case LD1W_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012769 case LDFF1B_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012770 case LDFF1D_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012771 case LDFF1H_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012772 case LDFF1SB_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012773 case LDFF1SH_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012774 case LDFF1SW_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012775 case LDFF1W_z_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012776 break;
12777 default:
12778 VIXL_UNIMPLEMENTED();
12779 break;
12780 }
Jacob Bramleydcdbd752020-01-20 11:47:36 +000012781 bool is_signed = instr->ExtractBit(14) == 0;
12782 bool is_ff = instr->ExtractBit(13) == 1;
12783 // Note that these instructions don't use the Dtype encoding.
12784 int msize_in_bytes_log2 = instr->ExtractBits(24, 23);
12785 uint64_t imm = instr->ExtractBits(20, 16) << msize_in_bytes_log2;
12786 LogicSVEAddressVector addr(imm, &ReadVRegister(instr->GetRn()), kFormatVnD);
12787 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
12788 if (is_ff) {
12789 VIXL_UNIMPLEMENTED();
12790 } else {
12791 SVEStructuredLoadHelper(kFormatVnD,
12792 ReadPRegister(instr->GetPgLow8()),
12793 instr->GetRt(),
12794 addr,
12795 is_signed);
12796 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012797}
12798
12799void Simulator::VisitSVE64BitGatherPrefetch_ScalarPlus64BitScaledOffsets(
12800 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012801 switch (
12802 instr->Mask(SVE64BitGatherPrefetch_ScalarPlus64BitScaledOffsetsMask)) {
TatWai Chong3db2c492020-03-29 22:20:41 -070012803 // Ignore prefetch hint instructions.
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012804 case PRFB_i_p_bz_d_64_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012805 case PRFD_i_p_bz_d_64_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012806 case PRFH_i_p_bz_d_64_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012807 case PRFW_i_p_bz_d_64_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012808 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012809 default:
12810 VIXL_UNIMPLEMENTED();
12811 break;
12812 }
12813}
12814
12815void Simulator::
12816 VisitSVE64BitGatherPrefetch_ScalarPlusUnpacked32BitScaledOffsets(
12817 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012818 switch (instr->Mask(
12819 SVE64BitGatherPrefetch_ScalarPlusUnpacked32BitScaledOffsetsMask)) {
TatWai Chong3db2c492020-03-29 22:20:41 -070012820 // Ignore prefetch hint instructions.
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012821 case PRFB_i_p_bz_d_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012822 case PRFD_i_p_bz_d_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012823 case PRFH_i_p_bz_d_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012824 case PRFW_i_p_bz_d_x32_scaled:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012825 break;
12826 default:
12827 VIXL_UNIMPLEMENTED();
12828 break;
12829 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000012830}
12831
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012832void Simulator::VisitSVE64BitGatherPrefetch_VectorPlusImm(
12833 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012834 switch (instr->Mask(SVE64BitGatherPrefetch_VectorPlusImmMask)) {
TatWai Chong3db2c492020-03-29 22:20:41 -070012835 // Ignore prefetch hint instructions.
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012836 case PRFB_i_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012837 case PRFD_i_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012838 case PRFH_i_p_ai_d:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012839 case PRFW_i_p_ai_d:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012840 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012841 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012842 VIXL_UNIMPLEMENTED();
12843 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012844 }
12845}
12846
12847void Simulator::VisitSVEContiguousFirstFaultLoad_ScalarPlusScalar(
12848 const Instruction* instr) {
Jacob Bramley85a9c102019-12-09 17:48:29 +000012849 bool is_signed;
Jacob Bramley85a9c102019-12-09 17:48:29 +000012850 switch (instr->Mask(SVEContiguousLoad_ScalarPlusScalarMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012851 case LDFF1B_z_p_br_u8:
Jacob Bramley85a9c102019-12-09 17:48:29 +000012852 case LDFF1B_z_p_br_u16:
12853 case LDFF1B_z_p_br_u32:
12854 case LDFF1B_z_p_br_u64:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012855 case LDFF1H_z_p_br_u16:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012856 case LDFF1H_z_p_br_u32:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012857 case LDFF1H_z_p_br_u64:
Jacob Bramley85a9c102019-12-09 17:48:29 +000012858 case LDFF1W_z_p_br_u32:
12859 case LDFF1W_z_p_br_u64:
12860 case LDFF1D_z_p_br_u64:
12861 is_signed = false;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012862 break;
12863 case LDFF1SB_z_p_br_s16:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012864 case LDFF1SB_z_p_br_s32:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012865 case LDFF1SB_z_p_br_s64:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012866 case LDFF1SH_z_p_br_s32:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012867 case LDFF1SH_z_p_br_s64:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012868 case LDFF1SW_z_p_br_s64:
Jacob Bramley85a9c102019-12-09 17:48:29 +000012869 is_signed = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012870 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012871 default:
Jacob Bramley85a9c102019-12-09 17:48:29 +000012872 // This encoding group is complete, so no other values should be possible.
12873 VIXL_UNREACHABLE();
12874 is_signed = false;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012875 break;
12876 }
Jacob Bramley85a9c102019-12-09 17:48:29 +000012877
12878 int msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(is_signed);
12879 int esize_in_bytes_log2 = instr->GetSVEEsizeFromDtype(is_signed);
12880 VIXL_ASSERT(msize_in_bytes_log2 <= esize_in_bytes_log2);
12881 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(esize_in_bytes_log2);
Maid3f755c2022-11-18 10:49:35 +000012882 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Jacob Bramley85a9c102019-12-09 17:48:29 +000012883 uint64_t offset = ReadXRegister(instr->GetRm());
12884 offset <<= msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000012885 LogicSVEAddressVector addr(base + offset);
Jacob Bramley85a9c102019-12-09 17:48:29 +000012886 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
12887 SVEFaultTolerantLoadHelper(vform,
12888 ReadPRegister(instr->GetPgLow8()),
12889 instr->GetRt(),
12890 addr,
12891 kSVEFirstFaultLoad,
12892 is_signed);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012893}
12894
12895void Simulator::VisitSVEContiguousNonFaultLoad_ScalarPlusImm(
12896 const Instruction* instr) {
Martyn Capewell5f9b3802020-03-24 16:16:36 +000012897 bool is_signed = false;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012898 switch (instr->Mask(SVEContiguousNonFaultLoad_ScalarPlusImmMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012899 case LDNF1B_z_p_bi_u16:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012900 case LDNF1B_z_p_bi_u32:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012901 case LDNF1B_z_p_bi_u64:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012902 case LDNF1B_z_p_bi_u8:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012903 case LDNF1D_z_p_bi_u64:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012904 case LDNF1H_z_p_bi_u16:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012905 case LDNF1H_z_p_bi_u32:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012906 case LDNF1H_z_p_bi_u64:
Martyn Capewell5f9b3802020-03-24 16:16:36 +000012907 case LDNF1W_z_p_bi_u32:
12908 case LDNF1W_z_p_bi_u64:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012909 break;
12910 case LDNF1SB_z_p_bi_s16:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012911 case LDNF1SB_z_p_bi_s32:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012912 case LDNF1SB_z_p_bi_s64:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012913 case LDNF1SH_z_p_bi_s32:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012914 case LDNF1SH_z_p_bi_s64:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012915 case LDNF1SW_z_p_bi_s64:
Martyn Capewell5f9b3802020-03-24 16:16:36 +000012916 is_signed = true;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012917 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012918 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012919 VIXL_UNIMPLEMENTED();
12920 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012921 }
Martyn Capewell5f9b3802020-03-24 16:16:36 +000012922 int msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(is_signed);
12923 int esize_in_bytes_log2 = instr->GetSVEEsizeFromDtype(is_signed);
12924 VIXL_ASSERT(msize_in_bytes_log2 <= esize_in_bytes_log2);
12925 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(esize_in_bytes_log2);
12926 int vl = GetVectorLengthInBytes();
12927 int vl_divisor_log2 = esize_in_bytes_log2 - msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000012928 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewell5f9b3802020-03-24 16:16:36 +000012929 uint64_t offset =
12930 (instr->ExtractSignedBits(19, 16) * vl) / (1 << vl_divisor_log2);
Maid3f755c2022-11-18 10:49:35 +000012931 LogicSVEAddressVector addr(base + offset);
Martyn Capewell5f9b3802020-03-24 16:16:36 +000012932 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
12933 SVEFaultTolerantLoadHelper(vform,
12934 ReadPRegister(instr->GetPgLow8()),
12935 instr->GetRt(),
12936 addr,
12937 kSVENonFaultLoad,
12938 is_signed);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012939}
12940
12941void Simulator::VisitSVEContiguousNonTemporalLoad_ScalarPlusImm(
12942 const Instruction* instr) {
Martyn Capewell72765d12020-03-23 14:25:53 +000012943 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
12944 VectorFormat vform = kFormatUndefined;
12945
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012946 switch (instr->Mask(SVEContiguousNonTemporalLoad_ScalarPlusImmMask)) {
12947 case LDNT1B_z_p_bi_contiguous:
Martyn Capewell72765d12020-03-23 14:25:53 +000012948 vform = kFormatVnB;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012949 break;
12950 case LDNT1D_z_p_bi_contiguous:
Martyn Capewell72765d12020-03-23 14:25:53 +000012951 vform = kFormatVnD;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012952 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012953 case LDNT1H_z_p_bi_contiguous:
Martyn Capewell72765d12020-03-23 14:25:53 +000012954 vform = kFormatVnH;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012955 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012956 case LDNT1W_z_p_bi_contiguous:
Martyn Capewell72765d12020-03-23 14:25:53 +000012957 vform = kFormatVnS;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012958 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012959 default:
12960 VIXL_UNIMPLEMENTED();
12961 break;
12962 }
Martyn Capewell72765d12020-03-23 14:25:53 +000012963 int msize_in_bytes_log2 = LaneSizeInBytesLog2FromFormat(vform);
12964 int vl = GetVectorLengthInBytes();
Maid3f755c2022-11-18 10:49:35 +000012965 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewell72765d12020-03-23 14:25:53 +000012966 uint64_t offset = instr->ExtractSignedBits(19, 16) * vl;
Maid3f755c2022-11-18 10:49:35 +000012967 LogicSVEAddressVector addr(base + offset);
Martyn Capewell72765d12020-03-23 14:25:53 +000012968 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
12969 SVEStructuredLoadHelper(vform,
12970 pg,
12971 instr->GetRt(),
12972 addr,
12973 /* is_signed = */ false);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012974}
12975
12976void Simulator::VisitSVEContiguousNonTemporalLoad_ScalarPlusScalar(
12977 const Instruction* instr) {
Martyn Capewell72765d12020-03-23 14:25:53 +000012978 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
12979 VectorFormat vform = kFormatUndefined;
12980
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012981 switch (instr->Mask(SVEContiguousNonTemporalLoad_ScalarPlusScalarMask)) {
12982 case LDNT1B_z_p_br_contiguous:
Martyn Capewell72765d12020-03-23 14:25:53 +000012983 vform = kFormatVnB;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012984 break;
12985 case LDNT1D_z_p_br_contiguous:
Martyn Capewell72765d12020-03-23 14:25:53 +000012986 vform = kFormatVnD;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010012987 break;
12988 case LDNT1H_z_p_br_contiguous:
Martyn Capewell72765d12020-03-23 14:25:53 +000012989 vform = kFormatVnH;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012990 break;
12991 case LDNT1W_z_p_br_contiguous:
Martyn Capewell72765d12020-03-23 14:25:53 +000012992 vform = kFormatVnS;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000012993 break;
12994 default:
12995 VIXL_UNIMPLEMENTED();
12996 break;
12997 }
Martyn Capewell72765d12020-03-23 14:25:53 +000012998 int msize_in_bytes_log2 = LaneSizeInBytesLog2FromFormat(vform);
Maid3f755c2022-11-18 10:49:35 +000012999 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewell72765d12020-03-23 14:25:53 +000013000 uint64_t offset = ReadXRegister(instr->GetRm()) << msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000013001 LogicSVEAddressVector addr(base + offset);
Martyn Capewell72765d12020-03-23 14:25:53 +000013002 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13003 SVEStructuredLoadHelper(vform,
13004 pg,
13005 instr->GetRt(),
13006 addr,
13007 /* is_signed = */ false);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000013008}
13009
Martyn Capewelleecb6072021-07-30 14:08:43 +010013010void Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusImm(
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013011 const Instruction* instr) {
Martyn Capewell452ad8b2020-03-19 15:49:57 +000013012 SimVRegister& zt = ReadVRegister(instr->GetRt());
13013 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13014
Martyn Capewelleecb6072021-07-30 14:08:43 +010013015 uint64_t dwords = 2;
13016 VectorFormat vform_dst = kFormatVnQ;
Martyn Capewelld48909d2022-05-03 16:38:38 +010013017 if ((form_hash_ == "ld1rob_z_p_bi_u8"_h) ||
13018 (form_hash_ == "ld1roh_z_p_bi_u16"_h) ||
13019 (form_hash_ == "ld1row_z_p_bi_u32"_h) ||
13020 (form_hash_ == "ld1rod_z_p_bi_u64"_h)) {
Martyn Capewelleecb6072021-07-30 14:08:43 +010013021 dwords = 4;
13022 vform_dst = kFormatVnO;
13023 }
13024
Martyn Capewell452ad8b2020-03-19 15:49:57 +000013025 uint64_t addr = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewelleecb6072021-07-30 14:08:43 +010013026 uint64_t offset =
13027 instr->ExtractSignedBits(19, 16) * dwords * kDRegSizeInBytes;
13028 int msz = instr->ExtractBits(24, 23);
13029 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(msz);
Martyn Capewell452ad8b2020-03-19 15:49:57 +000013030
Martyn Capewelleecb6072021-07-30 14:08:43 +010013031 for (unsigned i = 0; i < dwords; i++) {
Chris Jones89dfbc02024-04-16 16:21:03 +010013032 if (!ld1(kFormatVnD, zt, i, addr + offset + (i * kDRegSizeInBytes))) return;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013033 }
Martyn Capewell452ad8b2020-03-19 15:49:57 +000013034 mov_zeroing(vform, zt, pg, zt);
Martyn Capewelleecb6072021-07-30 14:08:43 +010013035 dup_element(vform_dst, zt, zt, 0);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013036}
13037
Martyn Capewelleecb6072021-07-30 14:08:43 +010013038void Simulator::VisitSVELoadAndBroadcastQOWord_ScalarPlusScalar(
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013039 const Instruction* instr) {
Martyn Capewell452ad8b2020-03-19 15:49:57 +000013040 SimVRegister& zt = ReadVRegister(instr->GetRt());
13041 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13042
Martyn Capewelleecb6072021-07-30 14:08:43 +010013043 uint64_t bytes = 16;
13044 VectorFormat vform_dst = kFormatVnQ;
Martyn Capewelld48909d2022-05-03 16:38:38 +010013045 if ((form_hash_ == "ld1rob_z_p_br_contiguous"_h) ||
13046 (form_hash_ == "ld1roh_z_p_br_contiguous"_h) ||
13047 (form_hash_ == "ld1row_z_p_br_contiguous"_h) ||
13048 (form_hash_ == "ld1rod_z_p_br_contiguous"_h)) {
Martyn Capewelleecb6072021-07-30 14:08:43 +010013049 bytes = 32;
13050 vform_dst = kFormatVnO;
13051 }
13052
Martyn Capewell452ad8b2020-03-19 15:49:57 +000013053 uint64_t addr = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
13054 uint64_t offset = ReadXRegister(instr->GetRm());
Martyn Capewelleecb6072021-07-30 14:08:43 +010013055 int msz = instr->ExtractBits(24, 23);
13056 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(msz);
13057 offset <<= msz;
13058 for (unsigned i = 0; i < bytes; i++) {
Chris Jones89dfbc02024-04-16 16:21:03 +010013059 if (!ld1(kFormatVnB, zt, i, addr + offset + i)) return;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013060 }
Martyn Capewell452ad8b2020-03-19 15:49:57 +000013061 mov_zeroing(vform, zt, pg, zt);
Martyn Capewelleecb6072021-07-30 14:08:43 +010013062 dup_element(vform_dst, zt, zt, 0);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013063}
13064
13065void Simulator::VisitSVELoadMultipleStructures_ScalarPlusImm(
13066 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013067 switch (instr->Mask(SVELoadMultipleStructures_ScalarPlusImmMask)) {
13068 case LD2B_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013069 case LD2D_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013070 case LD2H_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013071 case LD2W_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013072 case LD3B_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013073 case LD3D_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013074 case LD3H_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013075 case LD3W_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013076 case LD4B_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013077 case LD4D_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013078 case LD4H_z_p_bi_contiguous:
Jacob Bramleye5ab0fe2019-11-05 16:52:29 +000013079 case LD4W_z_p_bi_contiguous: {
13080 int vl = GetVectorLengthInBytes();
13081 int msz = instr->ExtractBits(24, 23);
13082 int reg_count = instr->ExtractBits(22, 21) + 1;
13083 uint64_t offset = instr->ExtractSignedBits(19, 16) * vl * reg_count;
13084 LogicSVEAddressVector addr(
13085 ReadXRegister(instr->GetRn(), Reg31IsStackPointer) + offset);
13086 addr.SetMsizeInBytesLog2(msz);
13087 addr.SetRegCount(reg_count);
13088 SVEStructuredLoadHelper(SVEFormatFromLaneSizeInBytesLog2(msz),
13089 ReadPRegister(instr->GetPgLow8()),
13090 instr->GetRt(),
13091 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013092 break;
Jacob Bramleye5ab0fe2019-11-05 16:52:29 +000013093 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013094 default:
13095 VIXL_UNIMPLEMENTED();
13096 break;
13097 }
13098}
13099
13100void Simulator::VisitSVELoadMultipleStructures_ScalarPlusScalar(
13101 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013102 switch (instr->Mask(SVELoadMultipleStructures_ScalarPlusScalarMask)) {
13103 case LD2B_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013104 case LD2D_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013105 case LD2H_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013106 case LD2W_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013107 case LD3B_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013108 case LD3D_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013109 case LD3H_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013110 case LD3W_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013111 case LD4B_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013112 case LD4D_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013113 case LD4H_z_p_br_contiguous:
Jacob Bramleye483ce52019-11-05 16:52:29 +000013114 case LD4W_z_p_br_contiguous: {
13115 int msz = instr->ExtractBits(24, 23);
TheLastRar49d6efa2024-10-15 16:37:27 +010013116 uint64_t offset = ReadXRegister(instr->GetRm()) * (uint64_t{1} << msz);
Jacob Bramleye483ce52019-11-05 16:52:29 +000013117 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(msz);
13118 LogicSVEAddressVector addr(
13119 ReadXRegister(instr->GetRn(), Reg31IsStackPointer) + offset);
13120 addr.SetMsizeInBytesLog2(msz);
13121 addr.SetRegCount(instr->ExtractBits(22, 21) + 1);
13122 SVEStructuredLoadHelper(vform,
13123 ReadPRegister(instr->GetPgLow8()),
13124 instr->GetRt(),
13125 addr,
13126 false);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013127 break;
Jacob Bramleye483ce52019-11-05 16:52:29 +000013128 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013129 default:
13130 VIXL_UNIMPLEMENTED();
13131 break;
13132 }
13133}
13134
13135void Simulator::VisitSVE32BitScatterStore_ScalarPlus32BitScaledOffsets(
13136 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013137 switch (instr->Mask(SVE32BitScatterStore_ScalarPlus32BitScaledOffsetsMask)) {
13138 case ST1H_z_p_bz_s_x32_scaled:
TatWai Chong5f3928c2020-06-11 00:09:20 -070013139 case ST1W_z_p_bz_s_x32_scaled: {
13140 unsigned msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(false);
13141 VIXL_ASSERT(kDRegSizeInBytesLog2 >= msize_in_bytes_log2);
13142 int scale = instr->ExtractBit(21) * msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000013143 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
TatWai Chong5f3928c2020-06-11 00:09:20 -070013144 SVEOffsetModifier mod =
13145 (instr->ExtractBit(14) == 1) ? SVE_SXTW : SVE_UXTW;
13146 LogicSVEAddressVector addr(base,
13147 &ReadVRegister(instr->GetRm()),
13148 kFormatVnS,
13149 mod,
13150 scale);
13151 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13152 SVEStructuredStoreHelper(kFormatVnS,
13153 ReadPRegister(instr->GetPgLow8()),
13154 instr->GetRt(),
13155 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013156 break;
TatWai Chong5f3928c2020-06-11 00:09:20 -070013157 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013158 default:
13159 VIXL_UNIMPLEMENTED();
13160 break;
13161 }
13162}
13163
13164void Simulator::VisitSVE32BitScatterStore_ScalarPlus32BitUnscaledOffsets(
13165 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013166 switch (
13167 instr->Mask(SVE32BitScatterStore_ScalarPlus32BitUnscaledOffsetsMask)) {
13168 case ST1B_z_p_bz_s_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013169 case ST1H_z_p_bz_s_x32_unscaled:
TatWai Chong5f3928c2020-06-11 00:09:20 -070013170 case ST1W_z_p_bz_s_x32_unscaled: {
13171 unsigned msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(false);
13172 VIXL_ASSERT(kDRegSizeInBytesLog2 >= msize_in_bytes_log2);
Maid3f755c2022-11-18 10:49:35 +000013173 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
TatWai Chong5f3928c2020-06-11 00:09:20 -070013174 SVEOffsetModifier mod =
13175 (instr->ExtractBit(14) == 1) ? SVE_SXTW : SVE_UXTW;
13176 LogicSVEAddressVector addr(base,
13177 &ReadVRegister(instr->GetRm()),
13178 kFormatVnS,
13179 mod);
13180 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13181 SVEStructuredStoreHelper(kFormatVnS,
13182 ReadPRegister(instr->GetPgLow8()),
13183 instr->GetRt(),
13184 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013185 break;
TatWai Chong5f3928c2020-06-11 00:09:20 -070013186 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013187 default:
13188 VIXL_UNIMPLEMENTED();
13189 break;
13190 }
13191}
13192
13193void Simulator::VisitSVE32BitScatterStore_VectorPlusImm(
13194 const Instruction* instr) {
Martyn Capewellb56cf222020-05-05 17:38:28 +010013195 int msz = 0;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013196 switch (instr->Mask(SVE32BitScatterStore_VectorPlusImmMask)) {
13197 case ST1B_z_p_ai_s:
Martyn Capewellb56cf222020-05-05 17:38:28 +010013198 msz = 0;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013199 break;
13200 case ST1H_z_p_ai_s:
Martyn Capewellb56cf222020-05-05 17:38:28 +010013201 msz = 1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013202 break;
13203 case ST1W_z_p_ai_s:
Martyn Capewellb56cf222020-05-05 17:38:28 +010013204 msz = 2;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013205 break;
13206 default:
13207 VIXL_UNIMPLEMENTED();
13208 break;
13209 }
Martyn Capewellb56cf222020-05-05 17:38:28 +010013210 uint64_t imm = instr->ExtractBits(20, 16) << msz;
13211 LogicSVEAddressVector addr(imm, &ReadVRegister(instr->GetRn()), kFormatVnS);
13212 addr.SetMsizeInBytesLog2(msz);
13213 SVEStructuredStoreHelper(kFormatVnS,
13214 ReadPRegister(instr->GetPgLow8()),
13215 instr->GetRt(),
13216 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013217}
13218
13219void Simulator::VisitSVE64BitScatterStore_ScalarPlus64BitScaledOffsets(
13220 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013221 switch (instr->Mask(SVE64BitScatterStore_ScalarPlus64BitScaledOffsetsMask)) {
13222 case ST1D_z_p_bz_d_64_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013223 case ST1H_z_p_bz_d_64_scaled:
Martyn Capewellfa098bc2020-05-12 10:21:56 +010013224 case ST1W_z_p_bz_d_64_scaled: {
13225 unsigned msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(false);
13226 VIXL_ASSERT(kDRegSizeInBytesLog2 >= msize_in_bytes_log2);
13227 int scale = instr->ExtractBit(21) * msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000013228 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewellfa098bc2020-05-12 10:21:56 +010013229 LogicSVEAddressVector addr(base,
13230 &ReadVRegister(instr->GetRm()),
13231 kFormatVnD,
13232 SVE_LSL,
13233 scale);
13234 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13235 SVEStructuredStoreHelper(kFormatVnD,
13236 ReadPRegister(instr->GetPgLow8()),
13237 instr->GetRt(),
13238 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013239 break;
Martyn Capewellfa098bc2020-05-12 10:21:56 +010013240 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013241 default:
13242 VIXL_UNIMPLEMENTED();
13243 break;
13244 }
13245}
13246
13247void Simulator::VisitSVE64BitScatterStore_ScalarPlus64BitUnscaledOffsets(
13248 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013249 switch (
13250 instr->Mask(SVE64BitScatterStore_ScalarPlus64BitUnscaledOffsetsMask)) {
13251 case ST1B_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013252 case ST1D_z_p_bz_d_64_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013253 case ST1H_z_p_bz_d_64_unscaled:
Martyn Capewellfa098bc2020-05-12 10:21:56 +010013254 case ST1W_z_p_bz_d_64_unscaled: {
13255 unsigned msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(false);
13256 VIXL_ASSERT(kDRegSizeInBytesLog2 >= msize_in_bytes_log2);
Maid3f755c2022-11-18 10:49:35 +000013257 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewellfa098bc2020-05-12 10:21:56 +010013258 LogicSVEAddressVector addr(base,
13259 &ReadVRegister(instr->GetRm()),
13260 kFormatVnD,
TatWai Chong5f3928c2020-06-11 00:09:20 -070013261 NO_SVE_OFFSET_MODIFIER);
Martyn Capewellfa098bc2020-05-12 10:21:56 +010013262 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13263 SVEStructuredStoreHelper(kFormatVnD,
13264 ReadPRegister(instr->GetPgLow8()),
13265 instr->GetRt(),
13266 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013267 break;
Martyn Capewellfa098bc2020-05-12 10:21:56 +010013268 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013269 default:
13270 VIXL_UNIMPLEMENTED();
13271 break;
13272 }
13273}
13274
13275void Simulator::VisitSVE64BitScatterStore_ScalarPlusUnpacked32BitScaledOffsets(
13276 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013277 switch (instr->Mask(
13278 SVE64BitScatterStore_ScalarPlusUnpacked32BitScaledOffsetsMask)) {
13279 case ST1D_z_p_bz_d_x32_scaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013280 case ST1H_z_p_bz_d_x32_scaled:
TatWai Chong5f3928c2020-06-11 00:09:20 -070013281 case ST1W_z_p_bz_d_x32_scaled: {
13282 unsigned msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(false);
13283 VIXL_ASSERT(kDRegSizeInBytesLog2 >= msize_in_bytes_log2);
13284 int scale = instr->ExtractBit(21) * msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000013285 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
TatWai Chong5f3928c2020-06-11 00:09:20 -070013286 SVEOffsetModifier mod =
13287 (instr->ExtractBit(14) == 1) ? SVE_SXTW : SVE_UXTW;
13288 LogicSVEAddressVector addr(base,
13289 &ReadVRegister(instr->GetRm()),
13290 kFormatVnD,
13291 mod,
13292 scale);
13293 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13294 SVEStructuredStoreHelper(kFormatVnD,
13295 ReadPRegister(instr->GetPgLow8()),
13296 instr->GetRt(),
13297 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013298 break;
TatWai Chong5f3928c2020-06-11 00:09:20 -070013299 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013300 default:
13301 VIXL_UNIMPLEMENTED();
13302 break;
13303 }
13304}
13305
13306void Simulator::
13307 VisitSVE64BitScatterStore_ScalarPlusUnpacked32BitUnscaledOffsets(
13308 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013309 switch (instr->Mask(
13310 SVE64BitScatterStore_ScalarPlusUnpacked32BitUnscaledOffsetsMask)) {
13311 case ST1B_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013312 case ST1D_z_p_bz_d_x32_unscaled:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013313 case ST1H_z_p_bz_d_x32_unscaled:
TatWai Chong5f3928c2020-06-11 00:09:20 -070013314 case ST1W_z_p_bz_d_x32_unscaled: {
13315 unsigned msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(false);
13316 VIXL_ASSERT(kDRegSizeInBytesLog2 >= msize_in_bytes_log2);
Maid3f755c2022-11-18 10:49:35 +000013317 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
TatWai Chong5f3928c2020-06-11 00:09:20 -070013318 SVEOffsetModifier mod =
13319 (instr->ExtractBit(14) == 1) ? SVE_SXTW : SVE_UXTW;
13320 LogicSVEAddressVector addr(base,
13321 &ReadVRegister(instr->GetRm()),
13322 kFormatVnD,
13323 mod);
13324 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13325 SVEStructuredStoreHelper(kFormatVnD,
13326 ReadPRegister(instr->GetPgLow8()),
13327 instr->GetRt(),
13328 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013329 break;
TatWai Chong5f3928c2020-06-11 00:09:20 -070013330 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013331 default:
13332 VIXL_UNIMPLEMENTED();
13333 break;
13334 }
13335}
13336
13337void Simulator::VisitSVE64BitScatterStore_VectorPlusImm(
13338 const Instruction* instr) {
Martyn Capewellb56cf222020-05-05 17:38:28 +010013339 int msz = 0;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013340 switch (instr->Mask(SVE64BitScatterStore_VectorPlusImmMask)) {
13341 case ST1B_z_p_ai_d:
Martyn Capewellb56cf222020-05-05 17:38:28 +010013342 msz = 0;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013343 break;
13344 case ST1D_z_p_ai_d:
Martyn Capewellb56cf222020-05-05 17:38:28 +010013345 msz = 3;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013346 break;
13347 case ST1H_z_p_ai_d:
Martyn Capewellb56cf222020-05-05 17:38:28 +010013348 msz = 1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013349 break;
13350 case ST1W_z_p_ai_d:
Martyn Capewellb56cf222020-05-05 17:38:28 +010013351 msz = 2;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013352 break;
13353 default:
13354 VIXL_UNIMPLEMENTED();
13355 break;
13356 }
Martyn Capewellb56cf222020-05-05 17:38:28 +010013357 uint64_t imm = instr->ExtractBits(20, 16) << msz;
13358 LogicSVEAddressVector addr(imm, &ReadVRegister(instr->GetRn()), kFormatVnD);
13359 addr.SetMsizeInBytesLog2(msz);
13360 SVEStructuredStoreHelper(kFormatVnD,
13361 ReadPRegister(instr->GetPgLow8()),
13362 instr->GetRt(),
13363 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013364}
13365
13366void Simulator::VisitSVEContiguousNonTemporalStore_ScalarPlusImm(
13367 const Instruction* instr) {
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013368 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13369 VectorFormat vform = kFormatUndefined;
13370
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013371 switch (instr->Mask(SVEContiguousNonTemporalStore_ScalarPlusImmMask)) {
13372 case STNT1B_z_p_bi_contiguous:
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013373 vform = kFormatVnB;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013374 break;
13375 case STNT1D_z_p_bi_contiguous:
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013376 vform = kFormatVnD;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013377 break;
13378 case STNT1H_z_p_bi_contiguous:
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013379 vform = kFormatVnH;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013380 break;
13381 case STNT1W_z_p_bi_contiguous:
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013382 vform = kFormatVnS;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013383 break;
13384 default:
13385 VIXL_UNIMPLEMENTED();
13386 break;
13387 }
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013388 int msize_in_bytes_log2 = LaneSizeInBytesLog2FromFormat(vform);
13389 int vl = GetVectorLengthInBytes();
Maid3f755c2022-11-18 10:49:35 +000013390 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013391 uint64_t offset = instr->ExtractSignedBits(19, 16) * vl;
Maid3f755c2022-11-18 10:49:35 +000013392 LogicSVEAddressVector addr(base + offset);
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013393 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13394 SVEStructuredStoreHelper(vform, pg, instr->GetRt(), addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013395}
13396
13397void Simulator::VisitSVEContiguousNonTemporalStore_ScalarPlusScalar(
13398 const Instruction* instr) {
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013399 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13400 VectorFormat vform = kFormatUndefined;
13401
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013402 switch (instr->Mask(SVEContiguousNonTemporalStore_ScalarPlusScalarMask)) {
13403 case STNT1B_z_p_br_contiguous:
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013404 vform = kFormatVnB;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013405 break;
13406 case STNT1D_z_p_br_contiguous:
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013407 vform = kFormatVnD;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013408 break;
13409 case STNT1H_z_p_br_contiguous:
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013410 vform = kFormatVnH;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013411 break;
13412 case STNT1W_z_p_br_contiguous:
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013413 vform = kFormatVnS;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013414 break;
13415 default:
13416 VIXL_UNIMPLEMENTED();
13417 break;
13418 }
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013419 int msize_in_bytes_log2 = LaneSizeInBytesLog2FromFormat(vform);
Maid3f755c2022-11-18 10:49:35 +000013420 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013421 uint64_t offset = ReadXRegister(instr->GetRm()) << msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000013422 LogicSVEAddressVector addr(base + offset);
Martyn Capewell3e2fb502020-03-24 12:04:07 +000013423 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13424 SVEStructuredStoreHelper(vform, pg, instr->GetRt(), addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013425}
13426
13427void Simulator::VisitSVEContiguousStore_ScalarPlusImm(
13428 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013429 switch (instr->Mask(SVEContiguousStore_ScalarPlusImmMask)) {
13430 case ST1B_z_p_bi:
13431 case ST1D_z_p_bi:
13432 case ST1H_z_p_bi:
13433 case ST1W_z_p_bi: {
13434 int vl = GetVectorLengthInBytes();
Jacob Bramley6ebbba62019-10-09 15:02:10 +010013435 int msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(false);
13436 int esize_in_bytes_log2 = instr->GetSVEEsizeFromDtype(false);
13437 VIXL_ASSERT(esize_in_bytes_log2 >= msize_in_bytes_log2);
13438 int vl_divisor_log2 = esize_in_bytes_log2 - msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000013439 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Jacob Bramley6ebbba62019-10-09 15:02:10 +010013440 uint64_t offset =
13441 (instr->ExtractSignedBits(19, 16) * vl) / (1 << vl_divisor_log2);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013442 VectorFormat vform =
Jacob Bramley6ebbba62019-10-09 15:02:10 +010013443 SVEFormatFromLaneSizeInBytesLog2(esize_in_bytes_log2);
Maid3f755c2022-11-18 10:49:35 +000013444 LogicSVEAddressVector addr(base + offset);
Jacob Bramleybc4a54f2019-11-04 16:44:01 +000013445 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
13446 SVEStructuredStoreHelper(vform,
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013447 ReadPRegister(instr->GetPgLow8()),
13448 instr->GetRt(),
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013449 addr);
13450 break;
13451 }
13452 default:
13453 VIXL_UNIMPLEMENTED();
13454 break;
13455 }
13456}
13457
13458void Simulator::VisitSVEContiguousStore_ScalarPlusScalar(
13459 const Instruction* instr) {
13460 switch (instr->Mask(SVEContiguousStore_ScalarPlusScalarMask)) {
13461 case ST1B_z_p_br:
13462 case ST1D_z_p_br:
13463 case ST1H_z_p_br:
13464 case ST1W_z_p_br: {
Maid3f755c2022-11-18 10:49:35 +000013465 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013466 uint64_t offset = ReadXRegister(instr->GetRm());
13467 offset <<= instr->ExtractBits(24, 23);
13468 VectorFormat vform =
13469 SVEFormatFromLaneSizeInBytesLog2(instr->ExtractBits(22, 21));
Maid3f755c2022-11-18 10:49:35 +000013470 LogicSVEAddressVector addr(base + offset);
Jacob Bramleybc4a54f2019-11-04 16:44:01 +000013471 addr.SetMsizeInBytesLog2(instr->ExtractBits(24, 23));
13472 SVEStructuredStoreHelper(vform,
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013473 ReadPRegister(instr->GetPgLow8()),
13474 instr->GetRt(),
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013475 addr);
13476 break;
13477 }
13478 default:
13479 VIXL_UNIMPLEMENTED();
13480 break;
13481 }
13482}
13483
13484void Simulator::VisitSVECopySIMDFPScalarRegisterToVector_Predicated(
13485 const Instruction* instr) {
13486 VectorFormat vform = instr->GetSVEVectorFormat();
13487 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13488 SimVRegister z_result;
13489
13490 switch (instr->Mask(SVECopySIMDFPScalarRegisterToVector_PredicatedMask)) {
13491 case CPY_z_p_v:
13492 dup_element(vform, z_result, ReadVRegister(instr->GetRn()), 0);
13493 mov_merging(vform, ReadVRegister(instr->GetRd()), pg, z_result);
13494 break;
13495 default:
13496 VIXL_UNIMPLEMENTED();
13497 break;
13498 }
13499}
13500
13501void Simulator::VisitSVEStoreMultipleStructures_ScalarPlusImm(
13502 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013503 switch (instr->Mask(SVEStoreMultipleStructures_ScalarPlusImmMask)) {
13504 case ST2B_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013505 case ST2D_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013506 case ST2H_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013507 case ST2W_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013508 case ST3B_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013509 case ST3D_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013510 case ST3H_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013511 case ST3W_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013512 case ST4B_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013513 case ST4D_z_p_bi_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013514 case ST4H_z_p_bi_contiguous:
Jacob Bramleyd4dd9c22019-11-04 16:44:01 +000013515 case ST4W_z_p_bi_contiguous: {
13516 int vl = GetVectorLengthInBytes();
13517 int msz = instr->ExtractBits(24, 23);
13518 int reg_count = instr->ExtractBits(22, 21) + 1;
13519 uint64_t offset = instr->ExtractSignedBits(19, 16) * vl * reg_count;
13520 LogicSVEAddressVector addr(
13521 ReadXRegister(instr->GetRn(), Reg31IsStackPointer) + offset);
13522 addr.SetMsizeInBytesLog2(msz);
13523 addr.SetRegCount(reg_count);
13524 SVEStructuredStoreHelper(SVEFormatFromLaneSizeInBytesLog2(msz),
13525 ReadPRegister(instr->GetPgLow8()),
13526 instr->GetRt(),
13527 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013528 break;
Jacob Bramleyd4dd9c22019-11-04 16:44:01 +000013529 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013530 default:
13531 VIXL_UNIMPLEMENTED();
13532 break;
13533 }
13534}
13535
13536void Simulator::VisitSVEStoreMultipleStructures_ScalarPlusScalar(
13537 const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013538 switch (instr->Mask(SVEStoreMultipleStructures_ScalarPlusScalarMask)) {
13539 case ST2B_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013540 case ST2D_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013541 case ST2H_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013542 case ST2W_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013543 case ST3B_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013544 case ST3D_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013545 case ST3H_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013546 case ST3W_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013547 case ST4B_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013548 case ST4D_z_p_br_contiguous:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013549 case ST4H_z_p_br_contiguous:
Jacob Bramleybc4a54f2019-11-04 16:44:01 +000013550 case ST4W_z_p_br_contiguous: {
13551 int msz = instr->ExtractBits(24, 23);
TheLastRar49d6efa2024-10-15 16:37:27 +010013552 uint64_t offset = ReadXRegister(instr->GetRm()) * (uint64_t{1} << msz);
Jacob Bramleybc4a54f2019-11-04 16:44:01 +000013553 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(msz);
13554 LogicSVEAddressVector addr(
13555 ReadXRegister(instr->GetRn(), Reg31IsStackPointer) + offset);
13556 addr.SetMsizeInBytesLog2(msz);
13557 addr.SetRegCount(instr->ExtractBits(22, 21) + 1);
13558 SVEStructuredStoreHelper(vform,
13559 ReadPRegister(instr->GetPgLow8()),
13560 instr->GetRt(),
13561 addr);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013562 break;
Jacob Bramleybc4a54f2019-11-04 16:44:01 +000013563 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013564 default:
13565 VIXL_UNIMPLEMENTED();
13566 break;
13567 }
13568}
13569
13570void Simulator::VisitSVEStorePredicateRegister(const Instruction* instr) {
13571 switch (instr->Mask(SVEStorePredicateRegisterMask)) {
13572 case STR_p_bi: {
13573 SimPRegister& pt = ReadPRegister(instr->GetPt());
13574 int pl = GetPredicateLengthInBytes();
13575 int imm9 = (instr->ExtractBits(21, 16) << 3) | instr->ExtractBits(12, 10);
13576 uint64_t multiplier = ExtractSignedBitfield64(8, 0, imm9);
Maid3f755c2022-11-18 10:49:35 +000013577 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
13578 uint64_t address = base + multiplier * pl;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013579 for (int i = 0; i < pl; i++) {
Chris Jones3134e252024-02-29 13:44:20 +000013580 if (!MemWrite(address + i, pt.GetLane<uint8_t>(i))) return;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013581 }
Jacob Bramley7eb3e212019-11-22 17:28:05 +000013582 LogPWrite(instr->GetPt(), address);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013583 break;
13584 }
13585 default:
13586 VIXL_UNIMPLEMENTED();
13587 break;
13588 }
13589}
13590
13591void Simulator::VisitSVEStoreVectorRegister(const Instruction* instr) {
13592 switch (instr->Mask(SVEStoreVectorRegisterMask)) {
13593 case STR_z_bi: {
13594 SimVRegister& zt = ReadVRegister(instr->GetRt());
13595 int vl = GetVectorLengthInBytes();
13596 int imm9 = (instr->ExtractBits(21, 16) << 3) | instr->ExtractBits(12, 10);
13597 uint64_t multiplier = ExtractSignedBitfield64(8, 0, imm9);
Maid3f755c2022-11-18 10:49:35 +000013598 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
13599 uint64_t address = base + multiplier * vl;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013600 for (int i = 0; i < vl; i++) {
Chris Jones3134e252024-02-29 13:44:20 +000013601 if (!MemWrite(address + i, zt.GetLane<uint8_t>(i))) return;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013602 }
Jacob Bramley7eb3e212019-11-22 17:28:05 +000013603 LogZWrite(instr->GetRt(), address);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013604 break;
13605 }
13606 default:
13607 VIXL_UNIMPLEMENTED();
13608 break;
13609 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000013610}
13611
13612void Simulator::VisitSVEMulIndex(const Instruction* instr) {
TatWai Chongfa3f6bf2020-03-13 00:22:03 -070013613 VectorFormat vform = instr->GetSVEVectorFormat();
13614 SimVRegister& zda = ReadVRegister(instr->GetRd());
13615 SimVRegister& zn = ReadVRegister(instr->GetRn());
Martyn Capewell286dce72021-08-20 13:42:06 +010013616 std::pair<int, int> zm_and_index = instr->GetSVEMulZmAndIndex();
13617 SimVRegister zm = ReadVRegister(zm_and_index.first);
13618 int index = zm_and_index.second;
TatWai Chongfa3f6bf2020-03-13 00:22:03 -070013619
Martyn Capewell286dce72021-08-20 13:42:06 +010013620 SimVRegister temp;
13621 dup_elements_to_segments(vform, temp, zm, index);
13622
13623 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +010013624 case "sdot_z_zzzi_d"_h:
13625 case "sdot_z_zzzi_s"_h:
Martyn Capewell286dce72021-08-20 13:42:06 +010013626 sdot(vform, zda, zn, temp);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013627 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010013628 case "udot_z_zzzi_d"_h:
13629 case "udot_z_zzzi_s"_h:
Martyn Capewell286dce72021-08-20 13:42:06 +010013630 udot(vform, zda, zn, temp);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013631 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010013632 case "sudot_z_zzzi_s"_h:
Martyn Capewell286dce72021-08-20 13:42:06 +010013633 usdot(vform, zda, temp, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013634 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010013635 case "usdot_z_zzzi_s"_h:
Martyn Capewell286dce72021-08-20 13:42:06 +010013636 usdot(vform, zda, zn, temp);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013637 break;
13638 default:
13639 VIXL_UNIMPLEMENTED();
13640 break;
13641 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000013642}
13643
Martyn Capewell8b1e7392021-06-08 17:32:49 +010013644void Simulator::SimulateMatrixMul(const Instruction* instr) {
13645 VectorFormat vform = kFormatVnS;
13646 SimVRegister& dn = ReadVRegister(instr->GetRd());
13647 SimVRegister& n = ReadVRegister(instr->GetRn());
13648 SimVRegister& m = ReadVRegister(instr->GetRm());
Martyn Capewelle642a962021-05-20 17:20:50 +010013649
Martyn Capewell8b1e7392021-06-08 17:32:49 +010013650 bool n_signed = false;
13651 bool m_signed = false;
Martyn Capewelle642a962021-05-20 17:20:50 +010013652 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +010013653 case "smmla_asimdsame2_g"_h:
Martyn Capewell8b1e7392021-06-08 17:32:49 +010013654 vform = kFormat4S;
13655 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +010013656 case "smmla_z_zzz"_h:
Martyn Capewell8b1e7392021-06-08 17:32:49 +010013657 n_signed = m_signed = true;
Martyn Capewelle642a962021-05-20 17:20:50 +010013658 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010013659 case "ummla_asimdsame2_g"_h:
Martyn Capewell8b1e7392021-06-08 17:32:49 +010013660 vform = kFormat4S;
13661 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +010013662 case "ummla_z_zzz"_h:
Martyn Capewelle642a962021-05-20 17:20:50 +010013663 // Nothing to do.
13664 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010013665 case "usmmla_asimdsame2_g"_h:
Martyn Capewell8b1e7392021-06-08 17:32:49 +010013666 vform = kFormat4S;
13667 VIXL_FALLTHROUGH();
Martyn Capewelld48909d2022-05-03 16:38:38 +010013668 case "usmmla_z_zzz"_h:
Martyn Capewell8b1e7392021-06-08 17:32:49 +010013669 m_signed = true;
Martyn Capewelle642a962021-05-20 17:20:50 +010013670 break;
13671 default:
13672 VIXL_UNIMPLEMENTED();
13673 break;
13674 }
Martyn Capewell8b1e7392021-06-08 17:32:49 +010013675 matmul(vform, dn, n, m, n_signed, m_signed);
Martyn Capewelle642a962021-05-20 17:20:50 +010013676}
13677
13678void Simulator::SimulateSVEFPMatrixMul(const Instruction* instr) {
13679 VectorFormat vform = instr->GetSVEVectorFormat();
13680 SimVRegister& zdn = ReadVRegister(instr->GetRd());
13681 SimVRegister& zn = ReadVRegister(instr->GetRn());
13682 SimVRegister& zm = ReadVRegister(instr->GetRm());
13683
13684 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +010013685 case "fmmla_z_zzz_d"_h:
Martyn Capewellc40e2882024-03-22 13:47:46 +000013686 if (GetVectorLengthInBits() < 256) VisitUnimplemented(instr);
13687 VIXL_FALLTHROUGH();
13688 case "fmmla_z_zzz_s"_h:
Martyn Capewelle642a962021-05-20 17:20:50 +010013689 fmatmul(vform, zdn, zn, zm);
13690 break;
13691 default:
13692 VIXL_UNIMPLEMENTED();
13693 break;
13694 }
13695}
13696
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013697void Simulator::VisitSVEPartitionBreakCondition(const Instruction* instr) {
TatWai Chong5d872292020-01-02 15:39:51 -080013698 SimPRegister& pd = ReadPRegister(instr->GetPd());
13699 SimPRegister& pg = ReadPRegister(instr->ExtractBits(13, 10));
13700 SimPRegister& pn = ReadPRegister(instr->GetPn());
13701 SimPRegister result;
13702
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013703 switch (instr->Mask(SVEPartitionBreakConditionMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013704 case BRKAS_p_p_p_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013705 case BRKA_p_p_p:
TatWai Chong5d872292020-01-02 15:39:51 -080013706 brka(result, pg, pn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013707 break;
13708 case BRKBS_p_p_p_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013709 case BRKB_p_p_p:
TatWai Chong5d872292020-01-02 15:39:51 -080013710 brkb(result, pg, pn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013711 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013712 default:
13713 VIXL_UNIMPLEMENTED();
13714 break;
13715 }
TatWai Chong5d872292020-01-02 15:39:51 -080013716
13717 if (instr->ExtractBit(4) == 1) {
13718 mov_merging(pd, pg, result);
13719 } else {
13720 mov_zeroing(pd, pg, result);
13721 }
13722
13723 // Set flag if needed.
13724 if (instr->ExtractBit(22) == 1) {
13725 PredTest(kFormatVnB, pg, pd);
13726 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013727}
13728
13729void Simulator::VisitSVEPropagateBreakToNextPartition(
13730 const Instruction* instr) {
TatWai Chong5d872292020-01-02 15:39:51 -080013731 SimPRegister& pdm = ReadPRegister(instr->GetPd());
13732 SimPRegister& pg = ReadPRegister(instr->ExtractBits(13, 10));
13733 SimPRegister& pn = ReadPRegister(instr->GetPn());
13734
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013735 switch (instr->Mask(SVEPropagateBreakToNextPartitionMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013736 case BRKNS_p_p_pp:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013737 case BRKN_p_p_pp:
TatWai Chong5d872292020-01-02 15:39:51 -080013738 brkn(pdm, pg, pn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013739 break;
13740 default:
13741 VIXL_UNIMPLEMENTED();
13742 break;
13743 }
TatWai Chong5d872292020-01-02 15:39:51 -080013744
13745 // Set flag if needed.
13746 if (instr->ExtractBit(22) == 1) {
Jacob Bramleya3d61102020-07-01 16:49:47 +010013747 // Note that this ignores `pg`.
13748 PredTest(kFormatVnB, GetPTrue(), pdm);
TatWai Chong5d872292020-01-02 15:39:51 -080013749 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000013750}
13751
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013752void Simulator::VisitSVEUnpackPredicateElements(const Instruction* instr) {
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013753 SimPRegister& pd = ReadPRegister(instr->GetPd());
13754 SimPRegister& pn = ReadPRegister(instr->GetPn());
13755
13756 SimVRegister temp = Simulator::ExpandToSimVRegister(pn);
13757 SimVRegister zero;
13758 dup_immediate(kFormatVnB, zero, 0);
13759
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013760 switch (instr->Mask(SVEUnpackPredicateElementsMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013761 case PUNPKHI_p_p:
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013762 zip2(kFormatVnB, temp, temp, zero);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013763 break;
13764 case PUNPKLO_p_p:
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013765 zip1(kFormatVnB, temp, temp, zero);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013766 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013767 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013768 VIXL_UNIMPLEMENTED();
13769 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013770 }
TatWai Chong47c26842020-02-10 01:51:32 -080013771 Simulator::ExtractFromSimVRegister(kFormatVnB, pd, temp);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013772}
13773
13774void Simulator::VisitSVEPermutePredicateElements(const Instruction* instr) {
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013775 VectorFormat vform = instr->GetSVEVectorFormat();
13776 SimPRegister& pd = ReadPRegister(instr->GetPd());
13777 SimPRegister& pn = ReadPRegister(instr->GetPn());
13778 SimPRegister& pm = ReadPRegister(instr->GetPm());
13779
13780 SimVRegister temp0 = Simulator::ExpandToSimVRegister(pn);
13781 SimVRegister temp1 = Simulator::ExpandToSimVRegister(pm);
13782
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013783 switch (instr->Mask(SVEPermutePredicateElementsMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013784 case TRN1_p_pp:
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013785 trn1(vform, temp0, temp0, temp1);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013786 break;
13787 case TRN2_p_pp:
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013788 trn2(vform, temp0, temp0, temp1);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013789 break;
13790 case UZP1_p_pp:
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013791 uzp1(vform, temp0, temp0, temp1);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013792 break;
13793 case UZP2_p_pp:
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013794 uzp2(vform, temp0, temp0, temp1);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013795 break;
13796 case ZIP1_p_pp:
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013797 zip1(vform, temp0, temp0, temp1);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013798 break;
13799 case ZIP2_p_pp:
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013800 zip2(vform, temp0, temp0, temp1);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013801 break;
13802 default:
13803 VIXL_UNIMPLEMENTED();
13804 break;
13805 }
TatWai Chong47c26842020-02-10 01:51:32 -080013806 Simulator::ExtractFromSimVRegister(kFormatVnB, pd, temp0);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000013807}
13808
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013809void Simulator::VisitSVEReversePredicateElements(const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013810 switch (instr->Mask(SVEReversePredicateElementsMask)) {
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013811 case REV_p_p: {
13812 VectorFormat vform = instr->GetSVEVectorFormat();
13813 SimPRegister& pn = ReadPRegister(instr->GetPn());
13814 SimPRegister& pd = ReadPRegister(instr->GetPd());
13815 SimVRegister temp = Simulator::ExpandToSimVRegister(pn);
13816 rev(vform, temp, temp);
TatWai Chong47c26842020-02-10 01:51:32 -080013817 Simulator::ExtractFromSimVRegister(kFormatVnB, pd, temp);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013818 break;
Martyn Capewell7fd6fd52019-12-06 14:50:15 +000013819 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013820 default:
13821 VIXL_UNIMPLEMENTED();
13822 break;
13823 }
13824}
13825
Martyn Capewellb545d6c2018-11-08 18:14:23 +000013826void Simulator::VisitSVEPermuteVectorExtract(const Instruction* instr) {
Martyn Capewellac07af12019-12-02 14:55:05 +000013827 SimVRegister& zdn = ReadVRegister(instr->GetRd());
13828 // Second source register "Zm" is encoded where "Zn" would usually be.
13829 SimVRegister& zm = ReadVRegister(instr->GetRn());
13830
Martyn Capewellbf424382021-03-19 15:56:26 +000013831 int index = instr->GetSVEExtractImmediate();
Martyn Capewellac07af12019-12-02 14:55:05 +000013832 int vl = GetVectorLengthInBytes();
13833 index = (index >= vl) ? 0 : index;
13834
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013835 switch (instr->Mask(SVEPermuteVectorExtractMask)) {
13836 case EXT_z_zi_des:
Martyn Capewellac07af12019-12-02 14:55:05 +000013837 ext(kFormatVnB, zdn, zdn, zm, index);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013838 break;
13839 default:
13840 VIXL_UNIMPLEMENTED();
13841 break;
13842 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000013843}
13844
13845void Simulator::VisitSVEPermuteVectorInterleaving(const Instruction* instr) {
Martyn Capewell15f89012020-01-09 11:18:30 +000013846 VectorFormat vform = instr->GetSVEVectorFormat();
13847 SimVRegister& zd = ReadVRegister(instr->GetRd());
13848 SimVRegister& zn = ReadVRegister(instr->GetRn());
13849 SimVRegister& zm = ReadVRegister(instr->GetRm());
13850
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013851 switch (instr->Mask(SVEPermuteVectorInterleavingMask)) {
13852 case TRN1_z_zz:
Martyn Capewell15f89012020-01-09 11:18:30 +000013853 trn1(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013854 break;
13855 case TRN2_z_zz:
Martyn Capewell15f89012020-01-09 11:18:30 +000013856 trn2(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013857 break;
13858 case UZP1_z_zz:
Martyn Capewell15f89012020-01-09 11:18:30 +000013859 uzp1(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013860 break;
13861 case UZP2_z_zz:
Martyn Capewell15f89012020-01-09 11:18:30 +000013862 uzp2(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013863 break;
13864 case ZIP1_z_zz:
Martyn Capewell15f89012020-01-09 11:18:30 +000013865 zip1(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013866 break;
13867 case ZIP2_z_zz:
Martyn Capewell15f89012020-01-09 11:18:30 +000013868 zip2(vform, zd, zn, zm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013869 break;
13870 default:
13871 VIXL_UNIMPLEMENTED();
13872 break;
13873 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000013874}
13875
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013876void Simulator::VisitSVEConditionallyBroadcastElementToVector(
13877 const Instruction* instr) {
Martyn Capewellf804b602020-02-24 18:57:18 +000013878 VectorFormat vform = instr->GetSVEVectorFormat();
13879 SimVRegister& zdn = ReadVRegister(instr->GetRd());
13880 SimVRegister& zm = ReadVRegister(instr->GetRn());
13881 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13882
13883 int active_offset = -1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013884 switch (instr->Mask(SVEConditionallyBroadcastElementToVectorMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013885 case CLASTA_z_p_zz:
Martyn Capewellf804b602020-02-24 18:57:18 +000013886 active_offset = 1;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013887 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013888 case CLASTB_z_p_zz:
Martyn Capewellf804b602020-02-24 18:57:18 +000013889 active_offset = 0;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000013890 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013891 default:
13892 VIXL_UNIMPLEMENTED();
13893 break;
13894 }
Martyn Capewellf804b602020-02-24 18:57:18 +000013895
13896 if (active_offset >= 0) {
13897 std::pair<bool, uint64_t> value = clast(vform, pg, zm, active_offset);
13898 if (value.first) {
13899 dup_immediate(vform, zdn, value.second);
13900 } else {
13901 // Trigger a line of trace for the operation, even though it doesn't
13902 // change the register value.
13903 mov(vform, zdn, zdn);
13904 }
13905 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013906}
13907
13908void Simulator::VisitSVEConditionallyExtractElementToSIMDFPScalar(
13909 const Instruction* instr) {
Martyn Capewellf804b602020-02-24 18:57:18 +000013910 VectorFormat vform = instr->GetSVEVectorFormat();
13911 SimVRegister& vdn = ReadVRegister(instr->GetRd());
13912 SimVRegister& zm = ReadVRegister(instr->GetRn());
13913 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13914
13915 int active_offset = -1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013916 switch (instr->Mask(SVEConditionallyExtractElementToSIMDFPScalarMask)) {
13917 case CLASTA_v_p_z:
Martyn Capewellf804b602020-02-24 18:57:18 +000013918 active_offset = 1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013919 break;
13920 case CLASTB_v_p_z:
Martyn Capewellf804b602020-02-24 18:57:18 +000013921 active_offset = 0;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013922 break;
13923 default:
13924 VIXL_UNIMPLEMENTED();
13925 break;
13926 }
Martyn Capewellf804b602020-02-24 18:57:18 +000013927
13928 if (active_offset >= 0) {
13929 LogicVRegister dst(vdn);
13930 uint64_t src1_value = dst.Uint(vform, 0);
13931 std::pair<bool, uint64_t> src2_value = clast(vform, pg, zm, active_offset);
13932 dup_immediate(vform, vdn, 0);
13933 dst.SetUint(vform, 0, src2_value.first ? src2_value.second : src1_value);
13934 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013935}
13936
13937void Simulator::VisitSVEConditionallyExtractElementToGeneralRegister(
13938 const Instruction* instr) {
Martyn Capewellf804b602020-02-24 18:57:18 +000013939 VectorFormat vform = instr->GetSVEVectorFormat();
13940 SimVRegister& zm = ReadVRegister(instr->GetRn());
13941 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13942
13943 int active_offset = -1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013944 switch (instr->Mask(SVEConditionallyExtractElementToGeneralRegisterMask)) {
13945 case CLASTA_r_p_z:
Martyn Capewellf804b602020-02-24 18:57:18 +000013946 active_offset = 1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013947 break;
13948 case CLASTB_r_p_z:
Martyn Capewellf804b602020-02-24 18:57:18 +000013949 active_offset = 0;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013950 break;
13951 default:
13952 VIXL_UNIMPLEMENTED();
13953 break;
13954 }
Martyn Capewellf804b602020-02-24 18:57:18 +000013955
13956 if (active_offset >= 0) {
13957 std::pair<bool, uint64_t> value = clast(vform, pg, zm, active_offset);
13958 uint64_t masked_src = ReadXRegister(instr->GetRd()) &
13959 GetUintMask(LaneSizeInBitsFromFormat(vform));
13960 WriteXRegister(instr->GetRd(), value.first ? value.second : masked_src);
13961 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013962}
13963
13964void Simulator::VisitSVEExtractElementToSIMDFPScalarRegister(
13965 const Instruction* instr) {
Martyn Capewellf804b602020-02-24 18:57:18 +000013966 VectorFormat vform = instr->GetSVEVectorFormat();
13967 SimVRegister& vdn = ReadVRegister(instr->GetRd());
13968 SimVRegister& zm = ReadVRegister(instr->GetRn());
13969 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13970
13971 int active_offset = -1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013972 switch (instr->Mask(SVEExtractElementToSIMDFPScalarRegisterMask)) {
13973 case LASTA_v_p_z:
Martyn Capewellf804b602020-02-24 18:57:18 +000013974 active_offset = 1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013975 break;
13976 case LASTB_v_p_z:
Martyn Capewellf804b602020-02-24 18:57:18 +000013977 active_offset = 0;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013978 break;
13979 default:
13980 VIXL_UNIMPLEMENTED();
13981 break;
13982 }
Martyn Capewellf804b602020-02-24 18:57:18 +000013983
13984 if (active_offset >= 0) {
13985 LogicVRegister dst(vdn);
13986 std::pair<bool, uint64_t> value = clast(vform, pg, zm, active_offset);
13987 dup_immediate(vform, vdn, 0);
13988 dst.SetUint(vform, 0, value.second);
13989 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013990}
13991
13992void Simulator::VisitSVEExtractElementToGeneralRegister(
13993 const Instruction* instr) {
Martyn Capewellf804b602020-02-24 18:57:18 +000013994 VectorFormat vform = instr->GetSVEVectorFormat();
13995 SimVRegister& zm = ReadVRegister(instr->GetRn());
13996 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
13997
13998 int active_offset = -1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010013999 switch (instr->Mask(SVEExtractElementToGeneralRegisterMask)) {
14000 case LASTA_r_p_z:
Martyn Capewellf804b602020-02-24 18:57:18 +000014001 active_offset = 1;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014002 break;
14003 case LASTB_r_p_z:
Martyn Capewellf804b602020-02-24 18:57:18 +000014004 active_offset = 0;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014005 break;
14006 default:
14007 VIXL_UNIMPLEMENTED();
14008 break;
14009 }
Martyn Capewellf804b602020-02-24 18:57:18 +000014010
14011 if (active_offset >= 0) {
14012 std::pair<bool, uint64_t> value = clast(vform, pg, zm, active_offset);
14013 WriteXRegister(instr->GetRd(), value.second);
14014 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014015}
14016
14017void Simulator::VisitSVECompressActiveElements(const Instruction* instr) {
Martyn Capewellf804b602020-02-24 18:57:18 +000014018 VectorFormat vform = instr->GetSVEVectorFormat();
14019 SimVRegister& zd = ReadVRegister(instr->GetRd());
14020 SimVRegister& zn = ReadVRegister(instr->GetRn());
14021 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
14022
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014023 switch (instr->Mask(SVECompressActiveElementsMask)) {
14024 case COMPACT_z_p_z:
Martyn Capewellf804b602020-02-24 18:57:18 +000014025 compact(vform, zd, pg, zn);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014026 break;
14027 default:
14028 VIXL_UNIMPLEMENTED();
14029 break;
14030 }
14031}
14032
14033void Simulator::VisitSVECopyGeneralRegisterToVector_Predicated(
14034 const Instruction* instr) {
14035 VectorFormat vform = instr->GetSVEVectorFormat();
14036 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
14037 SimVRegister z_result;
14038
14039 switch (instr->Mask(SVECopyGeneralRegisterToVector_PredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014040 case CPY_z_p_r:
Jacob Bramley0093bb92019-10-04 15:54:10 +010014041 dup_immediate(vform,
14042 z_result,
14043 ReadXRegister(instr->GetRn(), Reg31IsStackPointer));
14044 mov_merging(vform, ReadVRegister(instr->GetRd()), pg, z_result);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014045 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014046 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014047 VIXL_UNIMPLEMENTED();
14048 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014049 }
14050}
14051
14052void Simulator::VisitSVECopyIntImm_Predicated(const Instruction* instr) {
Jacob Bramley0f62eab2019-10-23 17:07:47 +010014053 VectorFormat vform = instr->GetSVEVectorFormat();
14054 SimPRegister& pg = ReadPRegister(instr->ExtractBits(19, 16));
14055 SimVRegister& zd = ReadVRegister(instr->GetRd());
14056
14057 SimVRegister result;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014058 switch (instr->Mask(SVECopyIntImm_PredicatedMask)) {
Jacob Bramley0f62eab2019-10-23 17:07:47 +010014059 case CPY_z_p_i: {
14060 // Use unsigned arithmetic to avoid undefined behaviour during the shift.
14061 uint64_t imm8 = instr->GetImmSVEIntWideSigned();
14062 dup_immediate(vform, result, imm8 << (instr->ExtractBit(13) * 8));
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014063 break;
Jacob Bramley0f62eab2019-10-23 17:07:47 +010014064 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014065 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014066 VIXL_UNIMPLEMENTED();
14067 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014068 }
Jacob Bramley0f62eab2019-10-23 17:07:47 +010014069
14070 if (instr->ExtractBit(14) != 0) {
14071 mov_merging(vform, zd, pg, result);
14072 } else {
14073 mov_zeroing(vform, zd, pg, result);
14074 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014075}
14076
14077void Simulator::VisitSVEReverseWithinElements(const Instruction* instr) {
Martyn Capewell77b6d982019-12-02 18:34:59 +000014078 SimVRegister& zd = ReadVRegister(instr->GetRd());
14079 SimVRegister& zn = ReadVRegister(instr->GetRn());
14080 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
14081 SimVRegister result;
14082
14083 // In NEON, the chunk size in which elements are REVersed is in the
14084 // instruction mnemonic, and the element size attached to the register.
14085 // SVE reverses the semantics; the mapping to logic functions below is to
14086 // account for this.
14087 VectorFormat chunk_form = instr->GetSVEVectorFormat();
14088 VectorFormat element_form = kFormatUndefined;
14089
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014090 switch (instr->Mask(SVEReverseWithinElementsMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014091 case RBIT_z_p_z:
Martyn Capewell77b6d982019-12-02 18:34:59 +000014092 rbit(chunk_form, result, zn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014093 break;
14094 case REVB_z_z:
Martyn Capewell77b6d982019-12-02 18:34:59 +000014095 VIXL_ASSERT((chunk_form == kFormatVnH) || (chunk_form == kFormatVnS) ||
14096 (chunk_form == kFormatVnD));
14097 element_form = kFormatVnB;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014098 break;
14099 case REVH_z_z:
Martyn Capewell77b6d982019-12-02 18:34:59 +000014100 VIXL_ASSERT((chunk_form == kFormatVnS) || (chunk_form == kFormatVnD));
14101 element_form = kFormatVnH;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014102 break;
14103 case REVW_z_z:
Martyn Capewell77b6d982019-12-02 18:34:59 +000014104 VIXL_ASSERT(chunk_form == kFormatVnD);
14105 element_form = kFormatVnS;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014106 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014107 default:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014108 VIXL_UNIMPLEMENTED();
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014109 break;
14110 }
Martyn Capewell77b6d982019-12-02 18:34:59 +000014111
14112 if (instr->Mask(SVEReverseWithinElementsMask) != RBIT_z_p_z) {
14113 VIXL_ASSERT(element_form != kFormatUndefined);
14114 switch (chunk_form) {
14115 case kFormatVnH:
14116 rev16(element_form, result, zn);
14117 break;
14118 case kFormatVnS:
14119 rev32(element_form, result, zn);
14120 break;
14121 case kFormatVnD:
14122 rev64(element_form, result, zn);
14123 break;
14124 default:
14125 VIXL_UNIMPLEMENTED();
14126 }
14127 }
14128
14129 mov_merging(chunk_form, zd, pg, result);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014130}
14131
Martyn Capewell1c7b9ae2020-11-03 14:40:16 +000014132void Simulator::VisitSVEVectorSplice(const Instruction* instr) {
Martyn Capewellf804b602020-02-24 18:57:18 +000014133 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewell1c7b9ae2020-11-03 14:40:16 +000014134 SimVRegister& zd = ReadVRegister(instr->GetRd());
14135 SimVRegister& zn = ReadVRegister(instr->GetRn());
14136 SimVRegister& zn2 = ReadVRegister((instr->GetRn() + 1) % kNumberOfZRegisters);
Martyn Capewellf804b602020-02-24 18:57:18 +000014137 SimPRegister& pg = ReadPRegister(instr->GetPgLow8());
14138
Martyn Capewell1c7b9ae2020-11-03 14:40:16 +000014139 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +010014140 case "splice_z_p_zz_des"_h:
Martyn Capewell1c7b9ae2020-11-03 14:40:16 +000014141 splice(vform, zd, pg, zd, zn);
14142 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010014143 case "splice_z_p_zz_con"_h:
Martyn Capewell1c7b9ae2020-11-03 14:40:16 +000014144 splice(vform, zd, pg, zn, zn2);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014145 break;
14146 default:
14147 VIXL_UNIMPLEMENTED();
14148 break;
14149 }
14150}
TatWai Chong4f28df72019-08-14 17:50:30 -070014151
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014152void Simulator::VisitSVEBroadcastGeneralRegister(const Instruction* instr) {
14153 SimVRegister& zd = ReadVRegister(instr->GetRd());
14154 switch (instr->Mask(SVEBroadcastGeneralRegisterMask)) {
14155 case DUP_z_r:
14156 dup_immediate(instr->GetSVEVectorFormat(),
14157 zd,
14158 ReadXRegister(instr->GetRn(), Reg31IsStackPointer));
14159 break;
14160 default:
14161 VIXL_UNIMPLEMENTED();
14162 break;
14163 }
14164}
14165
14166void Simulator::VisitSVEInsertSIMDFPScalarRegister(const Instruction* instr) {
14167 SimVRegister& zd = ReadVRegister(instr->GetRd());
14168 VectorFormat vform = instr->GetSVEVectorFormat();
14169 switch (instr->Mask(SVEInsertSIMDFPScalarRegisterMask)) {
14170 case INSR_z_v:
14171 insr(vform, zd, ReadDRegisterBits(instr->GetRn()));
14172 break;
14173 default:
14174 VIXL_UNIMPLEMENTED();
14175 break;
14176 }
14177}
14178
14179void Simulator::VisitSVEInsertGeneralRegister(const Instruction* instr) {
14180 SimVRegister& zd = ReadVRegister(instr->GetRd());
14181 VectorFormat vform = instr->GetSVEVectorFormat();
14182 switch (instr->Mask(SVEInsertGeneralRegisterMask)) {
14183 case INSR_z_r:
14184 insr(vform, zd, ReadXRegister(instr->GetRn()));
14185 break;
14186 default:
14187 VIXL_UNIMPLEMENTED();
14188 break;
14189 }
14190}
14191
14192void Simulator::VisitSVEBroadcastIndexElement(const Instruction* instr) {
14193 SimVRegister& zd = ReadVRegister(instr->GetRd());
14194 switch (instr->Mask(SVEBroadcastIndexElementMask)) {
TatWai Chong4f28df72019-08-14 17:50:30 -070014195 case DUP_z_zi: {
14196 std::pair<int, int> index_and_lane_size =
14197 instr->GetSVEPermuteIndexAndLaneSizeLog2();
14198 int index = index_and_lane_size.first;
14199 int lane_size_in_bytes_log_2 = index_and_lane_size.second;
14200 VectorFormat vform =
14201 SVEFormatFromLaneSizeInBytesLog2(lane_size_in_bytes_log_2);
14202 if ((index < 0) || (index >= LaneCountFromFormat(vform))) {
14203 // Out of bounds, set the destination register to zero.
14204 dup_immediate(kFormatVnD, zd, 0);
14205 } else {
14206 dup_element(vform, zd, ReadVRegister(instr->GetRn()), index);
14207 }
14208 return;
14209 }
TatWai Chong4f28df72019-08-14 17:50:30 -070014210 default:
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014211 VIXL_UNIMPLEMENTED();
TatWai Chong4f28df72019-08-14 17:50:30 -070014212 break;
14213 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014214}
TatWai Chong4f28df72019-08-14 17:50:30 -070014215
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014216void Simulator::VisitSVEReverseVectorElements(const Instruction* instr) {
14217 SimVRegister& zd = ReadVRegister(instr->GetRd());
TatWai Chong4f28df72019-08-14 17:50:30 -070014218 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014219 switch (instr->Mask(SVEReverseVectorElementsMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014220 case REV_z_z:
TatWai Chong4f28df72019-08-14 17:50:30 -070014221 rev(vform, zd, ReadVRegister(instr->GetRn()));
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014222 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014223 default:
14224 VIXL_UNIMPLEMENTED();
14225 break;
14226 }
14227}
14228
14229void Simulator::VisitSVEUnpackVectorElements(const Instruction* instr) {
14230 SimVRegister& zd = ReadVRegister(instr->GetRd());
14231 VectorFormat vform = instr->GetSVEVectorFormat();
14232 switch (instr->Mask(SVEUnpackVectorElementsMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014233 case SUNPKHI_z_z:
TatWai Chong4f28df72019-08-14 17:50:30 -070014234 unpk(vform, zd, ReadVRegister(instr->GetRn()), kHiHalf, kSignedExtend);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014235 break;
14236 case SUNPKLO_z_z:
TatWai Chong4f28df72019-08-14 17:50:30 -070014237 unpk(vform, zd, ReadVRegister(instr->GetRn()), kLoHalf, kSignedExtend);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014238 break;
14239 case UUNPKHI_z_z:
TatWai Chong4f28df72019-08-14 17:50:30 -070014240 unpk(vform, zd, ReadVRegister(instr->GetRn()), kHiHalf, kUnsignedExtend);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014241 break;
14242 case UUNPKLO_z_z:
TatWai Chong4f28df72019-08-14 17:50:30 -070014243 unpk(vform, zd, ReadVRegister(instr->GetRn()), kLoHalf, kUnsignedExtend);
14244 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014245 default:
14246 VIXL_UNIMPLEMENTED();
14247 break;
14248 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014249}
14250
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014251void Simulator::VisitSVETableLookup(const Instruction* instr) {
Martyn Capewell99c60492020-10-30 08:14:39 +000014252 VectorFormat vform = instr->GetSVEVectorFormat();
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014253 SimVRegister& zd = ReadVRegister(instr->GetRd());
Martyn Capewell99c60492020-10-30 08:14:39 +000014254 SimVRegister& zn = ReadVRegister(instr->GetRn());
14255 SimVRegister& zn2 = ReadVRegister((instr->GetRn() + 1) % kNumberOfZRegisters);
14256 SimVRegister& zm = ReadVRegister(instr->GetRm());
14257
14258 switch (form_hash_) {
Martyn Capewelld48909d2022-05-03 16:38:38 +010014259 case "tbl_z_zz_1"_h:
Martyn Capewell99c60492020-10-30 08:14:39 +000014260 tbl(vform, zd, zn, zm);
14261 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010014262 case "tbl_z_zz_2"_h:
Martyn Capewell99c60492020-10-30 08:14:39 +000014263 tbl(vform, zd, zn, zn2, zm);
14264 break;
Martyn Capewelld48909d2022-05-03 16:38:38 +010014265 case "tbx_z_zz"_h:
Martyn Capewell99c60492020-10-30 08:14:39 +000014266 tbx(vform, zd, zn, zm);
14267 break;
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014268 default:
Martyn Capewell99c60492020-10-30 08:14:39 +000014269 VIXL_UNIMPLEMENTED();
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014270 break;
14271 }
14272}
14273
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014274void Simulator::VisitSVEPredicateCount(const Instruction* instr) {
Jacob Bramleyd961a0c2019-07-17 10:53:45 +010014275 VectorFormat vform = instr->GetSVEVectorFormat();
14276 SimPRegister& pg = ReadPRegister(instr->ExtractBits(13, 10));
14277 SimPRegister& pn = ReadPRegister(instr->GetPn());
14278
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014279 switch (instr->Mask(SVEPredicateCountMask)) {
Jacob Bramleyd961a0c2019-07-17 10:53:45 +010014280 case CNTP_r_p_p: {
14281 WriteXRegister(instr->GetRd(), CountActiveAndTrueLanes(vform, pg, pn));
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014282 break;
Jacob Bramleyd961a0c2019-07-17 10:53:45 +010014283 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014284 default:
14285 VIXL_UNIMPLEMENTED();
14286 break;
14287 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014288}
14289
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014290void Simulator::VisitSVEPredicateLogical(const Instruction* instr) {
14291 Instr op = instr->Mask(SVEPredicateLogicalMask);
TatWai Chonga3e8b172019-11-22 21:48:56 -080014292 SimPRegister& pd = ReadPRegister(instr->GetPd());
14293 SimPRegister& pg = ReadPRegister(instr->ExtractBits(13, 10));
14294 SimPRegister& pn = ReadPRegister(instr->GetPn());
14295 SimPRegister& pm = ReadPRegister(instr->GetPm());
14296 SimPRegister result;
TatWai Chongf4fa8222019-06-17 12:08:14 -070014297 switch (op) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014298 case ANDS_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014299 case AND_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014300 case BICS_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014301 case BIC_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014302 case EORS_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014303 case EOR_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014304 case NANDS_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014305 case NAND_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014306 case NORS_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014307 case NOR_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014308 case ORNS_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014309 case ORN_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014310 case ORRS_p_p_pp_z:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014311 case ORR_p_p_pp_z:
TatWai Chongf4fa8222019-06-17 12:08:14 -070014312 SVEPredicateLogicalHelper(static_cast<SVEPredicateLogicalOp>(op),
TatWai Chonga3e8b172019-11-22 21:48:56 -080014313 result,
14314 pn,
14315 pm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014316 break;
TatWai Chonga3e8b172019-11-22 21:48:56 -080014317 case SEL_p_p_pp:
14318 sel(pd, pg, pn, pm);
14319 return;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014320 default:
14321 VIXL_UNIMPLEMENTED();
14322 break;
14323 }
TatWai Chonga3e8b172019-11-22 21:48:56 -080014324
14325 mov_zeroing(pd, pg, result);
14326 if (instr->Mask(SVEPredicateLogicalSetFlagsBit) != 0) {
14327 PredTest(kFormatVnB, pg, pd);
14328 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014329}
14330
Jacob Bramley0ce75842019-07-17 18:12:50 +010014331void Simulator::VisitSVEPredicateFirstActive(const Instruction* instr) {
Jacob Bramley0ce75842019-07-17 18:12:50 +010014332 LogicPRegister pg = ReadPRegister(instr->ExtractBits(8, 5));
14333 LogicPRegister pdn = ReadPRegister(instr->GetPd());
14334 switch (instr->Mask(SVEPredicateFirstActiveMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014335 case PFIRST_p_p_p:
Jacob Bramley0ce75842019-07-17 18:12:50 +010014336 pfirst(pdn, pg, pdn);
14337 // TODO: Is this broken when pg == pdn?
14338 PredTest(kFormatVnB, pg, pdn);
14339 break;
14340 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014341 VIXL_UNIMPLEMENTED();
14342 break;
Jacob Bramley0ce75842019-07-17 18:12:50 +010014343 }
14344}
14345
14346void Simulator::VisitSVEPredicateInitialize(const Instruction* instr) {
Jacob Bramley0ce75842019-07-17 18:12:50 +010014347 // This group only contains PTRUE{S}, and there are no unallocated encodings.
14348 VIXL_STATIC_ASSERT(
14349 SVEPredicateInitializeMask ==
14350 (SVEPredicateInitializeFMask | SVEPredicateInitializeSetFlagsBit));
14351 VIXL_ASSERT((instr->Mask(SVEPredicateInitializeMask) == PTRUE_p_s) ||
14352 (instr->Mask(SVEPredicateInitializeMask) == PTRUES_p_s));
14353
14354 LogicPRegister pdn = ReadPRegister(instr->GetPd());
14355 VectorFormat vform = instr->GetSVEVectorFormat();
14356
14357 ptrue(vform, pdn, instr->GetImmSVEPredicateConstraint());
14358 if (instr->ExtractBit(16)) PredTest(vform, pdn, pdn);
14359}
14360
14361void Simulator::VisitSVEPredicateNextActive(const Instruction* instr) {
Jacob Bramley0ce75842019-07-17 18:12:50 +010014362 // This group only contains PNEXT, and there are no unallocated encodings.
14363 VIXL_STATIC_ASSERT(SVEPredicateNextActiveFMask == SVEPredicateNextActiveMask);
14364 VIXL_ASSERT(instr->Mask(SVEPredicateNextActiveMask) == PNEXT_p_p_p);
14365
14366 LogicPRegister pg = ReadPRegister(instr->ExtractBits(8, 5));
14367 LogicPRegister pdn = ReadPRegister(instr->GetPd());
14368 VectorFormat vform = instr->GetSVEVectorFormat();
14369
14370 pnext(vform, pdn, pg, pdn);
14371 // TODO: Is this broken when pg == pdn?
14372 PredTest(vform, pg, pdn);
14373}
14374
14375void Simulator::VisitSVEPredicateReadFromFFR_Predicated(
14376 const Instruction* instr) {
TatWai Chonga3e8b172019-11-22 21:48:56 -080014377 LogicPRegister pd(ReadPRegister(instr->GetPd()));
14378 LogicPRegister pg(ReadPRegister(instr->GetPn()));
14379 FlagsUpdate flags = LeaveFlags;
Jacob Bramley0ce75842019-07-17 18:12:50 +010014380 switch (instr->Mask(SVEPredicateReadFromFFR_PredicatedMask)) {
14381 case RDFFR_p_p_f:
TatWai Chonga3e8b172019-11-22 21:48:56 -080014382 // Do nothing.
14383 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014384 case RDFFRS_p_p_f:
TatWai Chonga3e8b172019-11-22 21:48:56 -080014385 flags = SetFlags;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014386 break;
Jacob Bramley0ce75842019-07-17 18:12:50 +010014387 default:
14388 VIXL_UNIMPLEMENTED();
14389 break;
14390 }
TatWai Chonga3e8b172019-11-22 21:48:56 -080014391
14392 LogicPRegister ffr(ReadFFR());
14393 mov_zeroing(pd, pg, ffr);
14394
14395 if (flags == SetFlags) {
14396 PredTest(kFormatVnB, pg, pd);
14397 }
Jacob Bramley0ce75842019-07-17 18:12:50 +010014398}
14399
14400void Simulator::VisitSVEPredicateReadFromFFR_Unpredicated(
14401 const Instruction* instr) {
TatWai Chong4023d7a2019-11-18 14:16:28 -080014402 LogicPRegister pd(ReadPRegister(instr->GetPd()));
14403 LogicPRegister ffr(ReadFFR());
Jacob Bramley0ce75842019-07-17 18:12:50 +010014404 switch (instr->Mask(SVEPredicateReadFromFFR_UnpredicatedMask)) {
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014405 case RDFFR_p_f:
TatWai Chong4023d7a2019-11-18 14:16:28 -080014406 mov(pd, ffr);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014407 break;
Jacob Bramley0ce75842019-07-17 18:12:50 +010014408 default:
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014409 VIXL_UNIMPLEMENTED();
14410 break;
Jacob Bramley0ce75842019-07-17 18:12:50 +010014411 }
14412}
14413
14414void Simulator::VisitSVEPredicateTest(const Instruction* instr) {
Jacob Bramley0ce75842019-07-17 18:12:50 +010014415 switch (instr->Mask(SVEPredicateTestMask)) {
14416 case PTEST_p_p:
14417 PredTest(kFormatVnB,
14418 ReadPRegister(instr->ExtractBits(13, 10)),
14419 ReadPRegister(instr->GetPn()));
14420 break;
14421 default:
14422 VIXL_UNIMPLEMENTED();
14423 break;
14424 }
14425}
14426
14427void Simulator::VisitSVEPredicateZero(const Instruction* instr) {
Jacob Bramley0ce75842019-07-17 18:12:50 +010014428 switch (instr->Mask(SVEPredicateZeroMask)) {
14429 case PFALSE_p:
14430 pfalse(ReadPRegister(instr->GetPd()));
14431 break;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014432 default:
14433 VIXL_UNIMPLEMENTED();
14434 break;
14435 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014436}
14437
14438void Simulator::VisitSVEPropagateBreak(const Instruction* instr) {
TatWai Chong38303d92019-12-02 15:49:29 -080014439 SimPRegister& pd = ReadPRegister(instr->GetPd());
14440 SimPRegister& pg = ReadPRegister(instr->ExtractBits(13, 10));
14441 SimPRegister& pn = ReadPRegister(instr->GetPn());
14442 SimPRegister& pm = ReadPRegister(instr->GetPm());
14443
14444 bool set_flags = false;
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014445 switch (instr->Mask(SVEPropagateBreakMask)) {
14446 case BRKPAS_p_p_pp:
TatWai Chong38303d92019-12-02 15:49:29 -080014447 set_flags = true;
14448 VIXL_FALLTHROUGH();
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014449 case BRKPA_p_p_pp:
TatWai Chong38303d92019-12-02 15:49:29 -080014450 brkpa(pd, pg, pn, pm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014451 break;
14452 case BRKPBS_p_p_pp:
TatWai Chong38303d92019-12-02 15:49:29 -080014453 set_flags = true;
14454 VIXL_FALLTHROUGH();
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014455 case BRKPB_p_p_pp:
TatWai Chong38303d92019-12-02 15:49:29 -080014456 brkpb(pd, pg, pn, pm);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014457 break;
14458 default:
14459 VIXL_UNIMPLEMENTED();
14460 break;
14461 }
TatWai Chong38303d92019-12-02 15:49:29 -080014462
14463 if (set_flags) {
14464 PredTest(kFormatVnB, pg, pd);
14465 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014466}
14467
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014468void Simulator::VisitSVEStackFrameAdjustment(const Instruction* instr) {
14469 uint64_t length = 0;
14470 switch (instr->Mask(SVEStackFrameAdjustmentMask)) {
14471 case ADDPL_r_ri:
14472 length = GetPredicateLengthInBytes();
14473 break;
14474 case ADDVL_r_ri:
14475 length = GetVectorLengthInBytes();
14476 break;
14477 default:
14478 VIXL_UNIMPLEMENTED();
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014479 }
Jacob Bramley9e5da2a2019-08-06 18:52:07 +010014480 uint64_t base = ReadXRegister(instr->GetRm(), Reg31IsStackPointer);
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014481 WriteXRegister(instr->GetRd(),
14482 base + (length * instr->GetImmSVEVLScale()),
14483 LogRegWrites,
14484 Reg31IsStackPointer);
14485}
Jacob Bramley9e5da2a2019-08-06 18:52:07 +010014486
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014487void Simulator::VisitSVEStackFrameSize(const Instruction* instr) {
14488 int64_t scale = instr->GetImmSVEVLScale();
14489
14490 switch (instr->Mask(SVEStackFrameSizeMask)) {
14491 case RDVL_r_i:
14492 WriteXRegister(instr->GetRd(), GetVectorLengthInBytes() * scale);
14493 break;
14494 default:
14495 VIXL_UNIMPLEMENTED();
14496 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014497}
14498
14499void Simulator::VisitSVEVectorSelect(const Instruction* instr) {
TatWai Chong6205eb42019-09-24 10:07:20 +010014500 // The only instruction in this group is `sel`, and there are no unused
14501 // encodings.
14502 VIXL_ASSERT(instr->Mask(SVEVectorSelectMask) == SEL_z_p_zz);
14503
14504 VectorFormat vform = instr->GetSVEVectorFormat();
14505 SimVRegister& zd = ReadVRegister(instr->GetRd());
14506 SimPRegister& pg = ReadPRegister(instr->ExtractBits(13, 10));
14507 SimVRegister& zn = ReadVRegister(instr->GetRn());
14508 SimVRegister& zm = ReadVRegister(instr->GetRm());
14509
14510 sel(vform, zd, pg, zn, zm);
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014511}
14512
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014513void Simulator::VisitSVEFFRInitialise(const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014514 switch (instr->Mask(SVEFFRInitialiseMask)) {
TatWai Chong4023d7a2019-11-18 14:16:28 -080014515 case SETFFR_f: {
14516 LogicPRegister ffr(ReadFFR());
14517 ffr.SetAllBits();
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014518 break;
TatWai Chong4023d7a2019-11-18 14:16:28 -080014519 }
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014520 default:
14521 VIXL_UNIMPLEMENTED();
14522 break;
14523 }
14524}
14525
14526void Simulator::VisitSVEFFRWriteFromPredicate(const Instruction* instr) {
Martyn Capewelld255bdb2019-08-13 16:27:30 +010014527 switch (instr->Mask(SVEFFRWriteFromPredicateMask)) {
TatWai Chong4023d7a2019-11-18 14:16:28 -080014528 case WRFFR_f_p: {
14529 SimPRegister pn(ReadPRegister(instr->GetPn()));
14530 bool last_active = true;
14531 for (unsigned i = 0; i < pn.GetSizeInBits(); i++) {
14532 bool active = pn.GetBit(i);
14533 if (active && !last_active) {
14534 // `pn` is non-monotonic. This is UNPREDICTABLE.
14535 VIXL_ABORT();
14536 }
14537 last_active = active;
14538 }
14539 mov(ReadFFR(), pn);
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014540 break;
TatWai Chong4023d7a2019-11-18 14:16:28 -080014541 }
Martyn Capewelle91d1ec2019-01-31 14:33:35 +000014542 default:
14543 VIXL_UNIMPLEMENTED();
14544 break;
14545 }
Martyn Capewellb545d6c2018-11-08 18:14:23 +000014546}
Alexandre Ramesd3832962016-07-04 15:03:43 +010014547
TatWai Chong6205eb42019-09-24 10:07:20 +010014548void Simulator::VisitSVEContiguousLoad_ScalarPlusImm(const Instruction* instr) {
TatWai Chong6205eb42019-09-24 10:07:20 +010014549 bool is_signed;
14550 switch (instr->Mask(SVEContiguousLoad_ScalarPlusImmMask)) {
14551 case LD1B_z_p_bi_u8:
14552 case LD1B_z_p_bi_u16:
14553 case LD1B_z_p_bi_u32:
14554 case LD1B_z_p_bi_u64:
14555 case LD1H_z_p_bi_u16:
14556 case LD1H_z_p_bi_u32:
14557 case LD1H_z_p_bi_u64:
14558 case LD1W_z_p_bi_u32:
14559 case LD1W_z_p_bi_u64:
14560 case LD1D_z_p_bi_u64:
14561 is_signed = false;
14562 break;
14563 case LD1SB_z_p_bi_s16:
14564 case LD1SB_z_p_bi_s32:
14565 case LD1SB_z_p_bi_s64:
14566 case LD1SH_z_p_bi_s32:
14567 case LD1SH_z_p_bi_s64:
14568 case LD1SW_z_p_bi_s64:
14569 is_signed = true;
14570 break;
14571 default:
14572 // This encoding group is complete, so no other values should be possible.
14573 VIXL_UNREACHABLE();
14574 is_signed = false;
14575 break;
14576 }
14577
Jacob Bramley6ebbba62019-10-09 15:02:10 +010014578 int vl = GetVectorLengthInBytes();
TatWai Chong6205eb42019-09-24 10:07:20 +010014579 int msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(is_signed);
14580 int esize_in_bytes_log2 = instr->GetSVEEsizeFromDtype(is_signed);
Jacob Bramley6ebbba62019-10-09 15:02:10 +010014581 VIXL_ASSERT(esize_in_bytes_log2 >= msize_in_bytes_log2);
14582 int vl_divisor_log2 = esize_in_bytes_log2 - msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000014583 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Jacob Bramley6ebbba62019-10-09 15:02:10 +010014584 uint64_t offset =
14585 (instr->ExtractSignedBits(19, 16) * vl) / (1 << vl_divisor_log2);
TatWai Chong6205eb42019-09-24 10:07:20 +010014586 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(esize_in_bytes_log2);
Maid3f755c2022-11-18 10:49:35 +000014587 LogicSVEAddressVector addr(base + offset);
Jacob Bramleybc4a54f2019-11-04 16:44:01 +000014588 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
14589 SVEStructuredLoadHelper(vform,
TatWai Chong6205eb42019-09-24 10:07:20 +010014590 ReadPRegister(instr->GetPgLow8()),
14591 instr->GetRt(),
TatWai Chong6205eb42019-09-24 10:07:20 +010014592 addr,
14593 is_signed);
14594}
14595
14596void Simulator::VisitSVEContiguousLoad_ScalarPlusScalar(
14597 const Instruction* instr) {
14598 bool is_signed;
TatWai Chong6205eb42019-09-24 10:07:20 +010014599 switch (instr->Mask(SVEContiguousLoad_ScalarPlusScalarMask)) {
14600 case LD1B_z_p_br_u8:
14601 case LD1B_z_p_br_u16:
14602 case LD1B_z_p_br_u32:
14603 case LD1B_z_p_br_u64:
14604 case LD1H_z_p_br_u16:
14605 case LD1H_z_p_br_u32:
14606 case LD1H_z_p_br_u64:
14607 case LD1W_z_p_br_u32:
14608 case LD1W_z_p_br_u64:
14609 case LD1D_z_p_br_u64:
14610 is_signed = false;
14611 break;
14612 case LD1SB_z_p_br_s16:
14613 case LD1SB_z_p_br_s32:
14614 case LD1SB_z_p_br_s64:
14615 case LD1SH_z_p_br_s32:
14616 case LD1SH_z_p_br_s64:
14617 case LD1SW_z_p_br_s64:
14618 is_signed = true;
14619 break;
14620 default:
14621 // This encoding group is complete, so no other values should be possible.
14622 VIXL_UNREACHABLE();
14623 is_signed = false;
14624 break;
14625 }
14626
14627 int msize_in_bytes_log2 = instr->GetSVEMsizeFromDtype(is_signed);
14628 int esize_in_bytes_log2 = instr->GetSVEEsizeFromDtype(is_signed);
14629 VIXL_ASSERT(msize_in_bytes_log2 <= esize_in_bytes_log2);
14630 VectorFormat vform = SVEFormatFromLaneSizeInBytesLog2(esize_in_bytes_log2);
Maid3f755c2022-11-18 10:49:35 +000014631 uint64_t base = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
TatWai Chong6205eb42019-09-24 10:07:20 +010014632 uint64_t offset = ReadXRegister(instr->GetRm());
14633 offset <<= msize_in_bytes_log2;
Maid3f755c2022-11-18 10:49:35 +000014634 LogicSVEAddressVector addr(base + offset);
Jacob Bramleybc4a54f2019-11-04 16:44:01 +000014635 addr.SetMsizeInBytesLog2(msize_in_bytes_log2);
14636 SVEStructuredLoadHelper(vform,
TatWai Chong6205eb42019-09-24 10:07:20 +010014637 ReadPRegister(instr->GetPgLow8()),
14638 instr->GetRt(),
TatWai Chong6205eb42019-09-24 10:07:20 +010014639 addr,
14640 is_signed);
14641}
14642
Alexandre Ramesd3832962016-07-04 15:03:43 +010014643void Simulator::DoUnreachable(const Instruction* instr) {
14644 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
14645 (instr->GetImmException() == kUnreachableOpcode));
14646
14647 fprintf(stream_,
14648 "Hit UNREACHABLE marker at pc=%p.\n",
14649 reinterpret_cast<const void*>(instr));
14650 abort();
14651}
14652
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014653void Simulator::Simulate_XdSP_XnSP_Xm(const Instruction* instr) {
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014654 VIXL_ASSERT(form_hash_ == Hash("irg_64i_dp_2src"));
14655 uint64_t rn = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014656 uint64_t rm = ReadXRegister(instr->GetRm());
TatWai Chong6767df02022-03-25 11:33:54 -070014657 uint64_t tag = GenerateRandomTag(rm & 0xffff);
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014658 uint64_t new_val = GetAddressWithAllocationTag(rn, tag);
14659 WriteXRegister(instr->GetRd(), new_val, LogRegWrites, Reg31IsStackPointer);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014660}
14661
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014662void Simulator::SimulateMTEAddSubTag(const Instruction* instr) {
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014663 uint64_t rn = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014664 uint64_t rn_tag = GetAllocationTagFromAddress(rn);
14665 uint64_t tag_offset = instr->ExtractBits(13, 10);
14666 // TODO: implement GCR_EL1.Exclude to provide a tag exclusion list.
14667 uint64_t new_tag = ChooseNonExcludedTag(rn_tag, tag_offset);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014668
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014669 uint64_t offset = instr->ExtractBits(21, 16) * kMTETagGranuleInBytes;
14670 int carry = 0;
14671 if (form_hash_ == Hash("subg_64_addsub_immtags")) {
14672 offset = ~offset;
14673 carry = 1;
14674 } else {
14675 VIXL_ASSERT(form_hash_ == Hash("addg_64_addsub_immtags"));
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014676 }
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014677 uint64_t new_val =
14678 AddWithCarry(kXRegSize, /* set_flags = */ false, rn, offset, carry);
14679 new_val = GetAddressWithAllocationTag(new_val, new_tag);
14680 WriteXRegister(instr->GetRd(), new_val, LogRegWrites, Reg31IsStackPointer);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014681}
14682
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014683void Simulator::SimulateMTETagMaskInsert(const Instruction* instr) {
14684 VIXL_ASSERT(form_hash_ == Hash("gmi_64g_dp_2src"));
14685 uint64_t mask = ReadXRegister(instr->GetRm());
14686 uint64_t tag = GetAllocationTagFromAddress(
14687 ReadXRegister(instr->GetRn(), Reg31IsStackPointer));
TheLastRar49d6efa2024-10-15 16:37:27 +010014688 uint64_t mask_bit = uint64_t{1} << tag;
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014689 WriteXRegister(instr->GetRd(), mask | mask_bit);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014690}
14691
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014692void Simulator::SimulateMTESubPointer(const Instruction* instr) {
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014693 uint64_t rn = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014694 uint64_t rm = ReadXRegister(instr->GetRm(), Reg31IsStackPointer);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014695
Martyn Capewelle2e0b2d2022-01-27 11:09:18 +000014696 VIXL_ASSERT((form_hash_ == Hash("subps_64s_dp_2src")) ||
14697 (form_hash_ == Hash("subp_64s_dp_2src")));
14698 bool set_flags = (form_hash_ == Hash("subps_64s_dp_2src"));
14699
14700 rn = ExtractSignedBitfield64(55, 0, rn);
14701 rm = ExtractSignedBitfield64(55, 0, rm);
14702 uint64_t new_val = AddWithCarry(kXRegSize, set_flags, rn, ~rm, 1);
14703 WriteXRegister(instr->GetRd(), new_val);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014704}
14705
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014706void Simulator::SimulateMTEStoreTagPair(const Instruction* instr) {
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014707 uint64_t rn = ReadXRegister(instr->GetRn(), Reg31IsStackPointer);
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014708 uint64_t rt = ReadXRegister(instr->GetRt());
14709 uint64_t rt2 = ReadXRegister(instr->GetRt2());
14710 int offset = instr->GetImmLSPair() * static_cast<int>(kMTETagGranuleInBytes);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014711
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014712 AddrMode addr_mode = Offset;
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014713 switch (form_hash_) {
14714 case Hash("stgp_64_ldstpair_off"):
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014715 // Default is the offset mode.
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014716 break;
14717 case Hash("stgp_64_ldstpair_post"):
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014718 addr_mode = PostIndex;
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014719 break;
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014720 case Hash("stgp_64_ldstpair_pre"):
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014721 addr_mode = PreIndex;
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014722 break;
14723 default:
14724 VIXL_UNIMPLEMENTED();
14725 }
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014726
14727 uintptr_t address = AddressModeHelper(instr->GetRn(), offset, addr_mode);
14728 if (!IsAligned(address, kMTETagGranuleInBytes)) {
14729 VIXL_ALIGNMENT_EXCEPTION();
14730 }
14731
14732 int tag = GetAllocationTagFromAddress(rn);
14733 meta_data_.SetMTETag(address, tag);
14734
Chris Jones3134e252024-02-29 13:44:20 +000014735 if (!MemWrite<uint64_t>(address, rt)) return;
14736 if (!MemWrite<uint64_t>(address + kXRegSizeInBytes, rt2)) return;
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014737}
14738
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014739void Simulator::SimulateMTEStoreTag(const Instruction* instr) {
14740 uint64_t rt = ReadXRegister(instr->GetRt(), Reg31IsStackPointer);
14741 int offset = instr->GetImmLS() * static_cast<int>(kMTETagGranuleInBytes);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014742
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014743 AddrMode addr_mode = Offset;
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014744 switch (form_hash_) {
14745 case Hash("st2g_64soffset_ldsttags"):
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014746 case Hash("stg_64soffset_ldsttags"):
14747 case Hash("stz2g_64soffset_ldsttags"):
14748 case Hash("stzg_64soffset_ldsttags"):
14749 // Default is the offset mode.
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014750 break;
14751 case Hash("st2g_64spost_ldsttags"):
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014752 case Hash("stg_64spost_ldsttags"):
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014753 case Hash("stz2g_64spost_ldsttags"):
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014754 case Hash("stzg_64spost_ldsttags"):
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014755 addr_mode = PostIndex;
14756 break;
14757 case Hash("st2g_64spre_ldsttags"):
14758 case Hash("stg_64spre_ldsttags"):
14759 case Hash("stz2g_64spre_ldsttags"):
14760 case Hash("stzg_64spre_ldsttags"):
14761 addr_mode = PreIndex;
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014762 break;
14763 default:
14764 VIXL_UNIMPLEMENTED();
14765 }
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014766
14767 bool is_pair = false;
14768 switch (form_hash_) {
14769 case Hash("st2g_64soffset_ldsttags"):
14770 case Hash("st2g_64spost_ldsttags"):
14771 case Hash("st2g_64spre_ldsttags"):
14772 case Hash("stz2g_64soffset_ldsttags"):
14773 case Hash("stz2g_64spost_ldsttags"):
14774 case Hash("stz2g_64spre_ldsttags"):
14775 is_pair = true;
14776 break;
14777 default:
14778 break;
14779 }
14780
14781 bool is_zeroing = false;
14782 switch (form_hash_) {
14783 case Hash("stz2g_64soffset_ldsttags"):
14784 case Hash("stz2g_64spost_ldsttags"):
14785 case Hash("stz2g_64spre_ldsttags"):
14786 case Hash("stzg_64soffset_ldsttags"):
14787 case Hash("stzg_64spost_ldsttags"):
14788 case Hash("stzg_64spre_ldsttags"):
14789 is_zeroing = true;
14790 break;
14791 default:
14792 break;
14793 }
14794
14795 uintptr_t address = AddressModeHelper(instr->GetRn(), offset, addr_mode);
14796
14797 if (is_zeroing) {
TheLastRar49d6efa2024-10-15 16:37:27 +010014798 if (!IsAligned(address, kMTETagGranuleInBytes)) {
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014799 VIXL_ALIGNMENT_EXCEPTION();
14800 }
14801 VIXL_STATIC_ASSERT(kMTETagGranuleInBytes >= sizeof(uint64_t));
14802 VIXL_STATIC_ASSERT(kMTETagGranuleInBytes % sizeof(uint64_t) == 0);
14803
14804 size_t fill_size = kMTETagGranuleInBytes;
14805 if (is_pair) {
14806 fill_size += kMTETagGranuleInBytes;
14807 }
14808
14809 size_t fill_offset = 0;
14810 while (fill_offset < fill_size) {
Chris Jones3134e252024-02-29 13:44:20 +000014811 if (!MemWrite<uint64_t>(address + fill_offset, 0)) return;
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014812 fill_offset += sizeof(uint64_t);
14813 }
14814 }
14815
14816 int tag = GetAllocationTagFromAddress(rt);
14817 meta_data_.SetMTETag(address, tag, instr);
14818 if (is_pair) {
14819 meta_data_.SetMTETag(address + kMTETagGranuleInBytes, tag, instr);
14820 }
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014821}
14822
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014823void Simulator::SimulateMTELoadTag(const Instruction* instr) {
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014824 uint64_t rt = ReadXRegister(instr->GetRt());
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014825 int offset = instr->GetImmLS() * static_cast<int>(kMTETagGranuleInBytes);
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014826
14827 switch (form_hash_) {
14828 case Hash("ldg_64loffset_ldsttags"):
14829 break;
14830 default:
14831 VIXL_UNIMPLEMENTED();
14832 }
TatWai Chong2d2f24c2022-04-12 10:29:08 -070014833
14834 uintptr_t address = AddressModeHelper(instr->GetRn(), offset, Offset);
14835 address = AlignDown(address, kMTETagGranuleInBytes);
14836 uint64_t tag = meta_data_.GetMTETag(address, instr);
14837 WriteXRegister(instr->GetRt(), GetAddressWithAllocationTag(rt, tag));
Martyn Capewell2e4aff62022-01-20 13:59:43 +000014838}
Alexandre Ramesd3832962016-07-04 15:03:43 +010014839
Martyn Capewelld6acdad2022-05-12 15:35:15 +010014840void Simulator::SimulateCpyFP(const Instruction* instr) {
14841 MOPSPHelper<"cpy"_h>(instr);
14842 LogSystemRegister(NZCV);
14843}
14844
14845void Simulator::SimulateCpyP(const Instruction* instr) {
14846 MOPSPHelper<"cpy"_h>(instr);
14847
14848 int d = instr->GetRd();
14849 int n = instr->GetRn();
14850 int s = instr->GetRs();
14851
14852 // Determine copy direction. For cases in which direction is implementation
14853 // defined, use forward.
14854 bool is_backwards = false;
14855 uint64_t xs = ReadXRegister(s);
14856 uint64_t xd = ReadXRegister(d);
14857 uint64_t xn = ReadXRegister(n);
14858
14859 // Ignore the top byte of addresses for comparisons. We can use xn as is,
14860 // as it should have zero in bits 63:55.
14861 uint64_t xs_tbi = ExtractUnsignedBitfield64(55, 0, xs);
14862 uint64_t xd_tbi = ExtractUnsignedBitfield64(55, 0, xd);
14863 VIXL_ASSERT(ExtractUnsignedBitfield64(63, 55, xn) == 0);
14864 if ((xs_tbi < xd_tbi) && ((xs_tbi + xn) > xd_tbi)) {
14865 is_backwards = true;
14866 WriteXRegister(s, xs + xn);
14867 WriteXRegister(d, xd + xn);
14868 }
14869
14870 ReadNzcv().SetN(is_backwards ? 1 : 0);
14871 LogSystemRegister(NZCV);
14872}
14873
14874void Simulator::SimulateCpyM(const Instruction* instr) {
14875 VIXL_ASSERT(instr->IsConsistentMOPSTriplet<"cpy"_h>());
14876 VIXL_ASSERT(instr->IsMOPSMainOf(GetLastExecutedInstruction(), "cpy"_h));
14877
14878 int d = instr->GetRd();
14879 int n = instr->GetRn();
14880 int s = instr->GetRs();
14881
14882 uint64_t xd = ReadXRegister(d);
14883 uint64_t xn = ReadXRegister(n);
14884 uint64_t xs = ReadXRegister(s);
14885 bool is_backwards = ReadN();
14886
14887 int step = 1;
14888 if (is_backwards) {
14889 step = -1;
14890 xs--;
14891 xd--;
14892 }
14893
14894 while (xn--) {
Chris Jones30e7bbd2024-02-15 15:05:25 +000014895 VIXL_DEFINE_OR_RETURN(temp, MemRead<uint8_t>(xs));
Chris Jones3134e252024-02-29 13:44:20 +000014896 if (!MemWrite<uint8_t>(xd, temp)) return;
Martyn Capewelld6acdad2022-05-12 15:35:15 +010014897 LogMemTransfer(xd, xs, temp);
14898 xs += step;
14899 xd += step;
14900 }
14901
14902 if (is_backwards) {
14903 xs++;
14904 xd++;
14905 }
14906
14907 WriteXRegister(d, xd);
14908 WriteXRegister(n, 0);
14909 WriteXRegister(s, xs);
14910}
14911
14912void Simulator::SimulateCpyE(const Instruction* instr) {
14913 USE(instr);
14914 VIXL_ASSERT(instr->IsConsistentMOPSTriplet<"cpy"_h>());
14915 VIXL_ASSERT(instr->IsMOPSEpilogueOf(GetLastExecutedInstruction(), "cpy"_h));
14916 // This implementation does nothing in the epilogue; all copying is completed
14917 // in the "main" part.
14918}
14919
14920void Simulator::SimulateSetP(const Instruction* instr) {
14921 MOPSPHelper<"set"_h>(instr);
14922 LogSystemRegister(NZCV);
14923}
14924
14925void Simulator::SimulateSetM(const Instruction* instr) {
14926 VIXL_ASSERT(instr->IsConsistentMOPSTriplet<"set"_h>());
14927 VIXL_ASSERT(instr->IsMOPSMainOf(GetLastExecutedInstruction(), "set"_h));
14928
14929 uint64_t xd = ReadXRegister(instr->GetRd());
14930 uint64_t xn = ReadXRegister(instr->GetRn());
14931 uint64_t xs = ReadXRegister(instr->GetRs());
14932
14933 while (xn--) {
14934 LogWrite(instr->GetRs(), GetPrintRegPartial(kPrintRegLaneSizeB), xd);
TheLastRar49d6efa2024-10-15 16:37:27 +010014935 if (!MemWrite<uint8_t>(xd++, static_cast<uint8_t>(xs))) return;
Martyn Capewelld6acdad2022-05-12 15:35:15 +010014936 }
14937 WriteXRegister(instr->GetRd(), xd);
14938 WriteXRegister(instr->GetRn(), 0);
14939}
14940
14941void Simulator::SimulateSetE(const Instruction* instr) {
14942 USE(instr);
14943 VIXL_ASSERT(instr->IsConsistentMOPSTriplet<"set"_h>());
14944 VIXL_ASSERT(instr->IsMOPSEpilogueOf(GetLastExecutedInstruction(), "set"_h));
14945 // This implementation does nothing in the epilogue; all setting is completed
14946 // in the "main" part.
14947}
14948
14949void Simulator::SimulateSetGP(const Instruction* instr) {
14950 MOPSPHelper<"setg"_h>(instr);
14951
14952 uint64_t xd = ReadXRegister(instr->GetRd());
14953 uint64_t xn = ReadXRegister(instr->GetRn());
14954
14955 if ((xn > 0) && !IsAligned(xd, kMTETagGranuleInBytes)) {
14956 VIXL_ALIGNMENT_EXCEPTION();
14957 }
14958
14959 if (!IsAligned(xn, kMTETagGranuleInBytes)) {
14960 VIXL_ALIGNMENT_EXCEPTION();
14961 }
14962
14963 LogSystemRegister(NZCV);
14964}
14965
14966void Simulator::SimulateSetGM(const Instruction* instr) {
14967 uint64_t xd = ReadXRegister(instr->GetRd());
14968 uint64_t xn = ReadXRegister(instr->GetRn());
14969
14970 int tag = GetAllocationTagFromAddress(xd);
14971 while (xn) {
14972 meta_data_.SetMTETag(xd, tag);
14973 xd += 16;
14974 xn -= 16;
14975 }
14976 SimulateSetM(instr);
14977}
14978
Alexandre Ramesd3832962016-07-04 15:03:43 +010014979void Simulator::DoTrace(const Instruction* instr) {
14980 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
14981 (instr->GetImmException() == kTraceOpcode));
14982
14983 // Read the arguments encoded inline in the instruction stream.
14984 uint32_t parameters;
14985 uint32_t command;
14986
14987 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
14988 memcpy(&parameters, instr + kTraceParamsOffset, sizeof(parameters));
14989 memcpy(&command, instr + kTraceCommandOffset, sizeof(command));
14990
14991 switch (command) {
14992 case TRACE_ENABLE:
14993 SetTraceParameters(GetTraceParameters() | parameters);
14994 break;
14995 case TRACE_DISABLE:
14996 SetTraceParameters(GetTraceParameters() & ~parameters);
14997 break;
14998 default:
14999 VIXL_UNREACHABLE();
15000 }
15001
15002 WritePc(instr->GetInstructionAtOffset(kTraceLength));
15003}
15004
15005
15006void Simulator::DoLog(const Instruction* instr) {
15007 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
15008 (instr->GetImmException() == kLogOpcode));
15009
15010 // Read the arguments encoded inline in the instruction stream.
15011 uint32_t parameters;
15012
15013 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
15014 memcpy(&parameters, instr + kTraceParamsOffset, sizeof(parameters));
15015
15016 // We don't support a one-shot LOG_DISASM.
15017 VIXL_ASSERT((parameters & LOG_DISASM) == 0);
15018 // Print the requested information.
15019 if (parameters & LOG_SYSREGS) PrintSystemRegisters();
15020 if (parameters & LOG_REGS) PrintRegisters();
15021 if (parameters & LOG_VREGS) PrintVRegisters();
15022
15023 WritePc(instr->GetInstructionAtOffset(kLogLength));
15024}
15025
15026
15027void Simulator::DoPrintf(const Instruction* instr) {
15028 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
15029 (instr->GetImmException() == kPrintfOpcode));
15030
15031 // Read the arguments encoded inline in the instruction stream.
15032 uint32_t arg_count;
15033 uint32_t arg_pattern_list;
15034 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
15035 memcpy(&arg_count, instr + kPrintfArgCountOffset, sizeof(arg_count));
15036 memcpy(&arg_pattern_list,
15037 instr + kPrintfArgPatternListOffset,
15038 sizeof(arg_pattern_list));
15039
15040 VIXL_ASSERT(arg_count <= kPrintfMaxArgCount);
15041 VIXL_ASSERT((arg_pattern_list >> (kPrintfArgPatternBits * arg_count)) == 0);
15042
15043 // We need to call the host printf function with a set of arguments defined by
15044 // arg_pattern_list. Because we don't know the types and sizes of the
15045 // arguments, this is very difficult to do in a robust and portable way. To
15046 // work around the problem, we pick apart the format string, and print one
15047 // format placeholder at a time.
15048
15049 // Allocate space for the format string. We take a copy, so we can modify it.
15050 // Leave enough space for one extra character per expected argument (plus the
15051 // '\0' termination).
15052 const char* format_base = ReadRegister<const char*>(0);
15053 VIXL_ASSERT(format_base != NULL);
15054 size_t length = strlen(format_base) + 1;
15055 char* const format = new char[length + arg_count];
15056
15057 // A list of chunks, each with exactly one format placeholder.
15058 const char* chunks[kPrintfMaxArgCount];
15059
15060 // Copy the format string and search for format placeholders.
15061 uint32_t placeholder_count = 0;
15062 char* format_scratch = format;
15063 for (size_t i = 0; i < length; i++) {
15064 if (format_base[i] != '%') {
15065 *format_scratch++ = format_base[i];
15066 } else {
15067 if (format_base[i + 1] == '%') {
15068 // Ignore explicit "%%" sequences.
15069 *format_scratch++ = format_base[i];
15070 i++;
15071 // Chunks after the first are passed as format strings to printf, so we
15072 // need to escape '%' characters in those chunks.
15073 if (placeholder_count > 0) *format_scratch++ = format_base[i];
15074 } else {
15075 VIXL_CHECK(placeholder_count < arg_count);
15076 // Insert '\0' before placeholders, and store their locations.
15077 *format_scratch++ = '\0';
15078 chunks[placeholder_count++] = format_scratch;
15079 *format_scratch++ = format_base[i];
15080 }
15081 }
15082 }
15083 VIXL_CHECK(placeholder_count == arg_count);
15084
15085 // Finally, call printf with each chunk, passing the appropriate register
15086 // argument. Normally, printf returns the number of bytes transmitted, so we
15087 // can emulate a single printf call by adding the result from each chunk. If
15088 // any call returns a negative (error) value, though, just return that value.
15089
15090 printf("%s", clr_printf);
15091
15092 // Because '\0' is inserted before each placeholder, the first string in
15093 // 'format' contains no format placeholders and should be printed literally.
15094 int result = printf("%s", format);
15095 int pcs_r = 1; // Start at x1. x0 holds the format string.
15096 int pcs_f = 0; // Start at d0.
15097 if (result >= 0) {
15098 for (uint32_t i = 0; i < placeholder_count; i++) {
15099 int part_result = -1;
15100
15101 uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits);
15102 arg_pattern &= (1 << kPrintfArgPatternBits) - 1;
15103 switch (arg_pattern) {
15104 case kPrintfArgW:
15105 part_result = printf(chunks[i], ReadWRegister(pcs_r++));
15106 break;
15107 case kPrintfArgX:
15108 part_result = printf(chunks[i], ReadXRegister(pcs_r++));
15109 break;
15110 case kPrintfArgD:
15111 part_result = printf(chunks[i], ReadDRegister(pcs_f++));
15112 break;
15113 default:
15114 VIXL_UNREACHABLE();
15115 }
15116
15117 if (part_result < 0) {
15118 // Handle error values.
15119 result = part_result;
15120 break;
15121 }
15122
15123 result += part_result;
15124 }
15125 }
15126
15127 printf("%s", clr_normal);
15128
15129 // Printf returns its result in x0 (just like the C library's printf).
15130 WriteXRegister(0, result);
15131
15132 // The printf parameters are inlined in the code, so skip them.
15133 WritePc(instr->GetInstructionAtOffset(kPrintfLength));
15134
15135 // Set LR as if we'd just called a native printf function.
15136 WriteLr(ReadPc());
15137
15138 delete[] format;
15139}
15140
Alexandre Rames064e02d2016-07-12 11:53:13 +010015141
Alexandre Ramesca73ba02016-07-28 09:16:03 +010015142#ifdef VIXL_HAS_SIMULATED_RUNTIME_CALL_SUPPORT
Alexandre Rames064e02d2016-07-12 11:53:13 +010015143void Simulator::DoRuntimeCall(const Instruction* instr) {
Alexandre Rames0d2a3d52016-08-15 14:24:44 +010015144 VIXL_STATIC_ASSERT(kRuntimeCallAddressSize == sizeof(uintptr_t));
Alexandre Rames064e02d2016-07-12 11:53:13 +010015145 // The appropriate `Simulator::SimulateRuntimeCall()` wrapper and the function
15146 // to call are passed inlined in the assembly.
Chris Jones30e7bbd2024-02-15 15:05:25 +000015147 VIXL_DEFINE_OR_RETURN(call_wrapper_address,
15148 MemRead<uintptr_t>(instr + kRuntimeCallWrapperOffset));
15149 VIXL_DEFINE_OR_RETURN(function_address,
15150 MemRead<uintptr_t>(instr + kRuntimeCallFunctionOffset));
15151 VIXL_DEFINE_OR_RETURN(call_type,
15152 MemRead<uint32_t>(instr + kRuntimeCallTypeOffset));
Alexandre Rames064e02d2016-07-12 11:53:13 +010015153 auto runtime_call_wrapper =
Jacob Bramley482d4df2016-08-05 16:58:17 +010015154 reinterpret_cast<void (*)(Simulator*, uintptr_t)>(call_wrapper_address);
Alexandre Rames62799612017-02-05 20:22:52 -080015155
Chris Jones30e7bbd2024-02-15 15:05:25 +000015156 if (static_cast<RuntimeCallType>(call_type) == kCallRuntime) {
mmc28a3c407232024-06-19 15:03:55 +010015157 const Instruction* addr = instr->GetInstructionAtOffset(kRuntimeCallLength);
15158 WriteLr(addr);
15159 GCSPush(reinterpret_cast<uint64_t>(addr));
Alexandre Rames62799612017-02-05 20:22:52 -080015160 }
Alexandre Rames0d2a3d52016-08-15 14:24:44 +010015161 runtime_call_wrapper(this, function_address);
Alexandre Rames62799612017-02-05 20:22:52 -080015162 // Read the return address from `lr` and write it into `pc`.
mmc28a3c407232024-06-19 15:03:55 +010015163 uint64_t addr = ReadRegister<uint64_t>(kLinkRegCode);
15164 if (IsGCSCheckEnabled()) {
15165 uint64_t expected_lr = GCSPeek();
15166 char msg[128];
15167 if (expected_lr != 0) {
15168 if ((expected_lr & 0x3) != 0) {
15169 snprintf(msg,
15170 sizeof(msg),
TheLastRar49d6efa2024-10-15 16:37:27 +010015171 "GCS contains misaligned return address: 0x%016" PRIx64 "\n",
mmc28a3c407232024-06-19 15:03:55 +010015172 expected_lr);
15173 ReportGCSFailure(msg);
15174 } else if ((addr != 0) && (addr != expected_lr)) {
15175 snprintf(msg,
15176 sizeof(msg),
TheLastRar49d6efa2024-10-15 16:37:27 +010015177 "GCS mismatch: lr = 0x%016" PRIx64 ", gcs = 0x%016" PRIx64
15178 "\n",
mmc28a3c407232024-06-19 15:03:55 +010015179 addr,
15180 expected_lr);
15181 ReportGCSFailure(msg);
15182 }
15183 GCSPop();
15184 }
15185 }
15186 WritePc(reinterpret_cast<Instruction*>(addr));
Alexandre Rames064e02d2016-07-12 11:53:13 +010015187}
15188#else
15189void Simulator::DoRuntimeCall(const Instruction* instr) {
15190 USE(instr);
15191 VIXL_UNREACHABLE();
15192}
15193#endif
15194
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +010015195
15196void Simulator::DoConfigureCPUFeatures(const Instruction* instr) {
15197 VIXL_ASSERT(instr->Mask(ExceptionMask) == HLT);
15198
15199 typedef ConfigureCPUFeaturesElementType ElementType;
Jacob Bramleyfdf332a2018-09-17 11:17:54 +010015200 VIXL_ASSERT(CPUFeatures::kNumberOfFeatures <
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +010015201 std::numeric_limits<ElementType>::max());
15202
15203 // k{Set,Enable,Disable}CPUFeatures have the same parameter encoding.
15204
15205 size_t element_size = sizeof(ElementType);
15206 size_t offset = kConfigureCPUFeaturesListOffset;
15207
15208 // Read the kNone-terminated list of features.
15209 CPUFeatures parameters;
15210 while (true) {
Chris Jones30e7bbd2024-02-15 15:05:25 +000015211 VIXL_DEFINE_OR_RETURN(feature, MemRead<ElementType>(instr + offset));
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +010015212 offset += element_size;
Jacob Bramleyfdf332a2018-09-17 11:17:54 +010015213 if (feature == static_cast<ElementType>(CPUFeatures::kNone)) break;
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +010015214 parameters.Combine(static_cast<CPUFeatures::Feature>(feature));
15215 }
15216
15217 switch (instr->GetImmException()) {
15218 case kSetCPUFeaturesOpcode:
15219 SetCPUFeatures(parameters);
15220 break;
15221 case kEnableCPUFeaturesOpcode:
15222 GetCPUFeatures()->Combine(parameters);
15223 break;
15224 case kDisableCPUFeaturesOpcode:
15225 GetCPUFeatures()->Remove(parameters);
15226 break;
15227 default:
15228 VIXL_UNREACHABLE();
15229 break;
15230 }
15231
15232 WritePc(instr->GetInstructionAtOffset(AlignUp(offset, kInstructionSize)));
15233}
15234
15235
15236void Simulator::DoSaveCPUFeatures(const Instruction* instr) {
15237 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
15238 (instr->GetImmException() == kSaveCPUFeaturesOpcode));
15239 USE(instr);
15240
15241 saved_cpu_features_.push_back(*GetCPUFeatures());
15242}
15243
15244
15245void Simulator::DoRestoreCPUFeatures(const Instruction* instr) {
15246 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
15247 (instr->GetImmException() == kRestoreCPUFeaturesOpcode));
15248 USE(instr);
15249
15250 SetCPUFeatures(saved_cpu_features_.back());
15251 saved_cpu_features_.pop_back();
15252}
15253
TheLastRar49d6efa2024-10-15 16:37:27 +010015254#ifdef VIXL_HAS_SIMULATED_MMAP
TatWai Chong2d2f24c2022-04-12 10:29:08 -070015255void* Simulator::Mmap(
15256 void* address, size_t length, int prot, int flags, int fd, off_t offset) {
15257 // The underlying system `mmap` in the simulated environment doesn't recognize
15258 // PROT_BTI and PROT_MTE. Although the kernel probably just ignores the bits
15259 // it doesn't know, mask those protections out before calling is safer.
15260 int intenal_prot = prot;
15261 prot &= ~(PROT_BTI | PROT_MTE);
15262
15263 uint64_t address2 = reinterpret_cast<uint64_t>(
15264 mmap(address, length, prot, flags, fd, offset));
15265
15266 if (intenal_prot & PROT_MTE) {
15267 // The returning address of `mmap` isn't tagged.
15268 int tag = static_cast<int>(GenerateRandomTag());
15269 SetGranuleTag(address2, tag, length);
15270 address2 = GetAddressWithAllocationTag(address2, tag);
15271 }
15272
15273 return reinterpret_cast<void*>(address2);
15274}
15275
15276
15277int Simulator::Munmap(void* address, size_t length, int prot) {
15278 if (prot & PROT_MTE) {
15279 // Untag the address since `munmap` doesn't recognize the memory tagging
15280 // managed by the Simulator.
15281 address = AddressUntag(address);
15282 CleanGranuleTag(reinterpret_cast<char*>(address), length);
15283 }
15284
15285 return munmap(address, length);
15286}
TheLastRar49d6efa2024-10-15 16:37:27 +010015287#endif // VIXL_HAS_SIMULATED_MMAP
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +010015288
Alexandre Ramesd3832962016-07-04 15:03:43 +010015289} // namespace aarch64
15290} // namespace vixl
15291
Pierre Langlois1e85b7f2016-08-05 14:20:36 +010015292#endif // VIXL_INCLUDE_SIMULATOR_AARCH64